13d36ee2eSJeremy Kerr /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
24cdc200fSJeremy Kerr
34cdc200fSJeremy Kerr #include <assert.h>
43e8a12a4SAndrew Jeffery #include <errno.h>
54cdc200fSJeremy Kerr #include <stdarg.h>
64cdc200fSJeremy Kerr #include <stddef.h>
74cdc200fSJeremy Kerr #include <stdint.h>
84cdc200fSJeremy Kerr #include <stdio.h>
94cdc200fSJeremy Kerr #include <stdlib.h>
104cdc200fSJeremy Kerr #include <string.h>
11*a3830d25SMatt Johnston #include <stdalign.h>
124cdc200fSJeremy Kerr
134cdc200fSJeremy Kerr #undef pr_fmt
144cdc200fSJeremy Kerr #define pr_fmt(fmt) "core: " fmt
154cdc200fSJeremy Kerr
164cdc200fSJeremy Kerr #include "libmctp.h"
174cdc200fSJeremy Kerr #include "libmctp-alloc.h"
184cdc200fSJeremy Kerr #include "libmctp-log.h"
19ba6727e6SWiktor Gołgowski #include "libmctp-cmds.h"
20c2b833e4SAndrew Jeffery #include "range.h"
214a09e1dcSMatt Johnston #include "compiler.h"
22f9b99f1fSMatt Johnston #include "core-internal.h"
234058b2cbSMatt Johnston #include "control.h"
244cdc200fSJeremy Kerr
2544e64dfaSMatt Johnston #if MCTP_DEFAULT_CLOCK_GETTIME
2644e64dfaSMatt Johnston #include <time.h>
2744e64dfaSMatt Johnston #endif
2844e64dfaSMatt Johnston
2924db71fbSJeremy Kerr #ifndef ARRAY_SIZE
3024db71fbSJeremy Kerr #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
3124db71fbSJeremy Kerr #endif
3224db71fbSJeremy Kerr
33b93b6112SAndrew Jeffery static int mctp_message_tx_on_bus(struct mctp_bus *bus, mctp_eid_t src,
34f39c3857SSumanth Bhat mctp_eid_t dest, bool tag_owner,
35f39c3857SSumanth Bhat uint8_t msg_tag, void *msg, size_t msg_len);
3661c95992SMatt Johnston static void mctp_dealloc_tag(struct mctp_bus *bus, mctp_eid_t local,
3761c95992SMatt Johnston mctp_eid_t remote, uint8_t tag);
381a4ec3cdSJeremy Kerr
mctp_pktbuf_alloc(struct mctp_binding * binding,size_t len)39df15f7e9SJeremy Kerr struct mctp_pktbuf *mctp_pktbuf_alloc(struct mctp_binding *binding, size_t len)
404cdc200fSJeremy Kerr {
414a09e1dcSMatt Johnston size_t size =
424a09e1dcSMatt Johnston binding->pkt_size + binding->pkt_header + binding->pkt_trailer;
43487b31e0SRashmica Gupta if (len > size) {
44487b31e0SRashmica Gupta return NULL;
45487b31e0SRashmica Gupta }
464cdc200fSJeremy Kerr
474a09e1dcSMatt Johnston void *storage = __mctp_alloc(size + sizeof(struct mctp_pktbuf));
484a09e1dcSMatt Johnston if (!storage) {
492608b294SPedro Martelletto return NULL;
504a09e1dcSMatt Johnston }
514a09e1dcSMatt Johnston struct mctp_pktbuf *pkt = mctp_pktbuf_init(binding, storage);
524a09e1dcSMatt Johnston pkt->alloc = true;
534a09e1dcSMatt Johnston pkt->end = pkt->start + len;
544a09e1dcSMatt Johnston return pkt;
554cdc200fSJeremy Kerr }
564cdc200fSJeremy Kerr
mctp_pktbuf_free(struct mctp_pktbuf * pkt)574cdc200fSJeremy Kerr void mctp_pktbuf_free(struct mctp_pktbuf *pkt)
584cdc200fSJeremy Kerr {
594a09e1dcSMatt Johnston if (pkt->alloc) {
604cdc200fSJeremy Kerr __mctp_free(pkt);
614a09e1dcSMatt Johnston } else {
624a09e1dcSMatt Johnston mctp_prdebug("pktbuf_free called for non-alloced");
634a09e1dcSMatt Johnston }
644a09e1dcSMatt Johnston }
654a09e1dcSMatt Johnston
mctp_pktbuf_init(struct mctp_binding * binding,void * storage)664a09e1dcSMatt Johnston struct mctp_pktbuf *mctp_pktbuf_init(struct mctp_binding *binding,
674a09e1dcSMatt Johnston void *storage)
684a09e1dcSMatt Johnston {
69*a3830d25SMatt Johnston assert((size_t)storage % alignof(struct mctp_pktbuf) == 0);
70*a3830d25SMatt Johnston
714a09e1dcSMatt Johnston size_t size =
724a09e1dcSMatt Johnston binding->pkt_size + binding->pkt_header + binding->pkt_trailer;
734a09e1dcSMatt Johnston struct mctp_pktbuf *buf = (struct mctp_pktbuf *)storage;
744a09e1dcSMatt Johnston buf->size = size;
754a09e1dcSMatt Johnston buf->start = binding->pkt_header;
764a09e1dcSMatt Johnston buf->end = buf->start;
774a09e1dcSMatt Johnston buf->mctp_hdr_off = buf->start;
784a09e1dcSMatt Johnston buf->alloc = false;
794a09e1dcSMatt Johnston
804a09e1dcSMatt Johnston return buf;
814cdc200fSJeremy Kerr }
824cdc200fSJeremy Kerr
mctp_pktbuf_hdr(struct mctp_pktbuf * pkt)834cdc200fSJeremy Kerr struct mctp_hdr *mctp_pktbuf_hdr(struct mctp_pktbuf *pkt)
844cdc200fSJeremy Kerr {
857aaccb51SMoritz Fischer return (struct mctp_hdr *)(pkt->data + pkt->mctp_hdr_off);
864cdc200fSJeremy Kerr }
874cdc200fSJeremy Kerr
mctp_pktbuf_data(struct mctp_pktbuf * pkt)884cdc200fSJeremy Kerr void *mctp_pktbuf_data(struct mctp_pktbuf *pkt)
894cdc200fSJeremy Kerr {
907aaccb51SMoritz Fischer return pkt->data + pkt->mctp_hdr_off + sizeof(struct mctp_hdr);
914cdc200fSJeremy Kerr }
924cdc200fSJeremy Kerr
mctp_pktbuf_size(const struct mctp_pktbuf * pkt)934a09e1dcSMatt Johnston size_t mctp_pktbuf_size(const struct mctp_pktbuf *pkt)
944cdc200fSJeremy Kerr {
954cdc200fSJeremy Kerr return pkt->end - pkt->start;
964cdc200fSJeremy Kerr }
974cdc200fSJeremy Kerr
mctp_pktbuf_alloc_start(struct mctp_pktbuf * pkt,size_t size)98df15f7e9SJeremy Kerr void *mctp_pktbuf_alloc_start(struct mctp_pktbuf *pkt, size_t size)
994cdc200fSJeremy Kerr {
1004cdc200fSJeremy Kerr assert(size <= pkt->start);
1014cdc200fSJeremy Kerr pkt->start -= size;
1024cdc200fSJeremy Kerr return pkt->data + pkt->start;
1034cdc200fSJeremy Kerr }
1044cdc200fSJeremy Kerr
mctp_pktbuf_alloc_end(struct mctp_pktbuf * pkt,size_t size)105df15f7e9SJeremy Kerr void *mctp_pktbuf_alloc_end(struct mctp_pktbuf *pkt, size_t size)
1064cdc200fSJeremy Kerr {
1074cdc200fSJeremy Kerr void *buf;
1084cdc200fSJeremy Kerr
1093ac70d62SAndrew Jeffery assert(size <= (pkt->size - pkt->end));
1104cdc200fSJeremy Kerr buf = pkt->data + pkt->end;
1114cdc200fSJeremy Kerr pkt->end += size;
1124cdc200fSJeremy Kerr return buf;
1134cdc200fSJeremy Kerr }
1144cdc200fSJeremy Kerr
mctp_pktbuf_push(struct mctp_pktbuf * pkt,const void * data,size_t len)115dfbf0fd0SMatt Johnston int mctp_pktbuf_push(struct mctp_pktbuf *pkt, const void *data, size_t len)
1164cdc200fSJeremy Kerr {
1174cdc200fSJeremy Kerr void *p;
1184cdc200fSJeremy Kerr
119df15f7e9SJeremy Kerr if (pkt->end + len > pkt->size)
1204cdc200fSJeremy Kerr return -1;
1214cdc200fSJeremy Kerr
1224cdc200fSJeremy Kerr p = pkt->data + pkt->end;
1234cdc200fSJeremy Kerr
1244cdc200fSJeremy Kerr pkt->end += len;
1254cdc200fSJeremy Kerr memcpy(p, data, len);
1264cdc200fSJeremy Kerr
1274cdc200fSJeremy Kerr return 0;
1284cdc200fSJeremy Kerr }
1294cdc200fSJeremy Kerr
mctp_pktbuf_pop(struct mctp_pktbuf * pkt,size_t len)130eba19a3bSAndrew Jeffery void *mctp_pktbuf_pop(struct mctp_pktbuf *pkt, size_t len)
131eba19a3bSAndrew Jeffery {
132eba19a3bSAndrew Jeffery if (len > mctp_pktbuf_size(pkt))
133eba19a3bSAndrew Jeffery return NULL;
134eba19a3bSAndrew Jeffery
135eba19a3bSAndrew Jeffery pkt->end -= len;
136eba19a3bSAndrew Jeffery return pkt->data + pkt->end;
137eba19a3bSAndrew Jeffery }
138eba19a3bSAndrew Jeffery
1394a09e1dcSMatt Johnston /* Allocate a duplicate of the message and copy it */
mctp_msg_dup(const void * msg,size_t msg_len,struct mctp * mctp)1404a09e1dcSMatt Johnston static void *mctp_msg_dup(const void *msg, size_t msg_len, struct mctp *mctp)
1414a09e1dcSMatt Johnston {
1424a09e1dcSMatt Johnston void *copy = __mctp_msg_alloc(msg_len, mctp);
1434a09e1dcSMatt Johnston if (!copy) {
1444a09e1dcSMatt Johnston mctp_prdebug("msg dup len %zu failed", msg_len);
1454a09e1dcSMatt Johnston return NULL;
1464a09e1dcSMatt Johnston }
1474a09e1dcSMatt Johnston
1484a09e1dcSMatt Johnston memcpy(copy, msg, msg_len);
1494a09e1dcSMatt Johnston return copy;
1504a09e1dcSMatt Johnston }
1514a09e1dcSMatt Johnston
15224db71fbSJeremy Kerr /* Message reassembly */
mctp_msg_ctx_lookup(struct mctp * mctp,uint8_t src,uint8_t dest,uint8_t tag)153a721c2d8SPatrick Williams static struct mctp_msg_ctx *mctp_msg_ctx_lookup(struct mctp *mctp, uint8_t src,
154a721c2d8SPatrick Williams uint8_t dest, uint8_t tag)
15524db71fbSJeremy Kerr {
15624db71fbSJeremy Kerr unsigned int i;
15724db71fbSJeremy Kerr
15824db71fbSJeremy Kerr /* @todo: better lookup, if we add support for more outstanding
15924db71fbSJeremy Kerr * message contexts */
16024db71fbSJeremy Kerr for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) {
16124db71fbSJeremy Kerr struct mctp_msg_ctx *ctx = &mctp->msg_ctxs[i];
1624a09e1dcSMatt Johnston if (ctx->buf && ctx->src == src && ctx->dest == dest &&
1634a09e1dcSMatt Johnston ctx->tag == tag)
16424db71fbSJeremy Kerr return ctx;
16524db71fbSJeremy Kerr }
16624db71fbSJeremy Kerr
16724db71fbSJeremy Kerr return NULL;
16824db71fbSJeremy Kerr }
16924db71fbSJeremy Kerr
mctp_msg_ctx_create(struct mctp * mctp,uint8_t src,uint8_t dest,uint8_t tag)170a721c2d8SPatrick Williams static struct mctp_msg_ctx *mctp_msg_ctx_create(struct mctp *mctp, uint8_t src,
171a721c2d8SPatrick Williams uint8_t dest, uint8_t tag)
17224db71fbSJeremy Kerr {
17311a234e1SJeremy Kerr struct mctp_msg_ctx *ctx = NULL;
17424db71fbSJeremy Kerr unsigned int i;
17524db71fbSJeremy Kerr
17624db71fbSJeremy Kerr for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) {
17724db71fbSJeremy Kerr struct mctp_msg_ctx *tmp = &mctp->msg_ctxs[i];
1784a09e1dcSMatt Johnston if (!tmp->buf) {
17924db71fbSJeremy Kerr ctx = tmp;
18024db71fbSJeremy Kerr break;
18124db71fbSJeremy Kerr }
18224db71fbSJeremy Kerr }
18324db71fbSJeremy Kerr
18424db71fbSJeremy Kerr if (!ctx)
18524db71fbSJeremy Kerr return NULL;
18624db71fbSJeremy Kerr
18724db71fbSJeremy Kerr ctx->src = src;
1881a4ec3cdSJeremy Kerr ctx->dest = dest;
18924db71fbSJeremy Kerr ctx->tag = tag;
1904a09e1dcSMatt Johnston
1919a3da81cSJeremy Kerr ctx->buf_size = 0;
1924a09e1dcSMatt Johnston ctx->buf_alloc_size = mctp->max_message_size;
1934a09e1dcSMatt Johnston ctx->buf = __mctp_msg_alloc(ctx->buf_alloc_size, mctp);
1944a09e1dcSMatt Johnston if (!ctx->buf) {
1954a09e1dcSMatt Johnston return NULL;
1964a09e1dcSMatt Johnston }
19724db71fbSJeremy Kerr
19824db71fbSJeremy Kerr return ctx;
19924db71fbSJeremy Kerr }
20024db71fbSJeremy Kerr
mctp_msg_ctx_drop(struct mctp_bus * bus,struct mctp_msg_ctx * ctx)2014a09e1dcSMatt Johnston static void mctp_msg_ctx_drop(struct mctp_bus *bus, struct mctp_msg_ctx *ctx)
20224db71fbSJeremy Kerr {
2034a09e1dcSMatt Johnston /* Free and mark as unused */
2044a09e1dcSMatt Johnston __mctp_msg_free(ctx->buf, bus->mctp);
2054a09e1dcSMatt Johnston ctx->buf = NULL;
20624db71fbSJeremy Kerr }
20724db71fbSJeremy Kerr
mctp_msg_ctx_reset(struct mctp_msg_ctx * ctx)20824db71fbSJeremy Kerr static void mctp_msg_ctx_reset(struct mctp_msg_ctx *ctx)
20924db71fbSJeremy Kerr {
21024db71fbSJeremy Kerr ctx->buf_size = 0;
21169f545f7SSumanth Bhat ctx->fragment_size = 0;
21224db71fbSJeremy Kerr }
21324db71fbSJeremy Kerr
mctp_msg_ctx_add_pkt(struct mctp_msg_ctx * ctx,struct mctp_pktbuf * pkt)21424db71fbSJeremy Kerr static int mctp_msg_ctx_add_pkt(struct mctp_msg_ctx *ctx,
2154a09e1dcSMatt Johnston struct mctp_pktbuf *pkt)
21624db71fbSJeremy Kerr {
21724db71fbSJeremy Kerr size_t len;
21824db71fbSJeremy Kerr
21924db71fbSJeremy Kerr len = mctp_pktbuf_size(pkt) - sizeof(struct mctp_hdr);
22024db71fbSJeremy Kerr
221bc79c24eSSumanth Bhat if (len + ctx->buf_size < ctx->buf_size) {
222bc79c24eSSumanth Bhat return -1;
223bc79c24eSSumanth Bhat }
224bc79c24eSSumanth Bhat
22524db71fbSJeremy Kerr if (ctx->buf_size + len > ctx->buf_alloc_size) {
2262c820c5aSSumanth Bhat return -1;
22724db71fbSJeremy Kerr }
22824db71fbSJeremy Kerr
2297aaccb51SMoritz Fischer memcpy((uint8_t *)ctx->buf + ctx->buf_size, mctp_pktbuf_data(pkt), len);
23024db71fbSJeremy Kerr ctx->buf_size += len;
23124db71fbSJeremy Kerr
23224db71fbSJeremy Kerr return 0;
23324db71fbSJeremy Kerr }
23424db71fbSJeremy Kerr
23524db71fbSJeremy Kerr /* Core API functions */
mctp_init(void)2364cdc200fSJeremy Kerr struct mctp *mctp_init(void)
2374cdc200fSJeremy Kerr {
2384cdc200fSJeremy Kerr struct mctp *mctp;
2394cdc200fSJeremy Kerr
2404cdc200fSJeremy Kerr mctp = __mctp_alloc(sizeof(*mctp));
24196d54492SSumanth Bhat
24296d54492SSumanth Bhat if (!mctp)
24396d54492SSumanth Bhat return NULL;
24496d54492SSumanth Bhat
245f9b99f1fSMatt Johnston mctp_setup(mctp, sizeof(*mctp));
246722d0db2SMatt Johnston return mctp;
247722d0db2SMatt Johnston }
248722d0db2SMatt Johnston
24944e64dfaSMatt Johnston #if MCTP_DEFAULT_CLOCK_GETTIME
mctp_default_now(void * ctx)25044e64dfaSMatt Johnston static uint64_t mctp_default_now(void *ctx __attribute__((unused)))
25144e64dfaSMatt Johnston {
25244e64dfaSMatt Johnston struct timespec tp;
25344e64dfaSMatt Johnston int rc = clock_gettime(CLOCK_MONOTONIC, &tp);
25444e64dfaSMatt Johnston if (rc) {
25544e64dfaSMatt Johnston /* Should not be possible */
25644e64dfaSMatt Johnston return 0;
25744e64dfaSMatt Johnston }
25844e64dfaSMatt Johnston return (uint64_t)tp.tv_sec * 1000 + tp.tv_nsec / 1000000;
25944e64dfaSMatt Johnston }
26044e64dfaSMatt Johnston #endif
26144e64dfaSMatt Johnston
mctp_setup(struct mctp * mctp,size_t struct_mctp_size)262f9b99f1fSMatt Johnston int mctp_setup(struct mctp *mctp, size_t struct_mctp_size)
263722d0db2SMatt Johnston {
264f9b99f1fSMatt Johnston if (struct_mctp_size < sizeof(struct mctp)) {
265f9b99f1fSMatt Johnston mctp_prdebug("Mismatching struct mctp");
266f9b99f1fSMatt Johnston return -EINVAL;
267f9b99f1fSMatt Johnston }
2684cdc200fSJeremy Kerr memset(mctp, 0, sizeof(*mctp));
2692c820c5aSSumanth Bhat mctp->max_message_size = MCTP_MAX_MESSAGE_SIZE;
27044e64dfaSMatt Johnston #if MCTP_DEFAULT_CLOCK_GETTIME
27144e64dfaSMatt Johnston mctp->platform_now = mctp_default_now;
27244e64dfaSMatt Johnston #endif
2734058b2cbSMatt Johnston #if MCTP_CONTROL_HANDLER
2744058b2cbSMatt Johnston mctp_control_add_type(mctp, MCTP_CTRL_HDR_MSG_TYPE);
2754058b2cbSMatt Johnston #endif
276f9b99f1fSMatt Johnston return 0;
2774cdc200fSJeremy Kerr }
2784cdc200fSJeremy Kerr
mctp_set_max_message_size(struct mctp * mctp,size_t message_size)2792c820c5aSSumanth Bhat void mctp_set_max_message_size(struct mctp *mctp, size_t message_size)
2802c820c5aSSumanth Bhat {
2812c820c5aSSumanth Bhat mctp->max_message_size = message_size;
2822c820c5aSSumanth Bhat }
2832c820c5aSSumanth Bhat
mctp_set_capture_handler(struct mctp * mctp,mctp_capture_fn fn,void * user)2845d3d4e6dSAndrew Jeffery void mctp_set_capture_handler(struct mctp *mctp, mctp_capture_fn fn, void *user)
2855d3d4e6dSAndrew Jeffery {
2865d3d4e6dSAndrew Jeffery mctp->capture = fn;
2875d3d4e6dSAndrew Jeffery mctp->capture_data = user;
2885d3d4e6dSAndrew Jeffery }
2895d3d4e6dSAndrew Jeffery
mctp_bus_destroy(struct mctp_bus * bus,struct mctp * mctp)2904a09e1dcSMatt Johnston static void mctp_bus_destroy(struct mctp_bus *bus, struct mctp *mctp)
2913ae89dceSAndrew Jeffery {
2924a09e1dcSMatt Johnston if (bus->tx_msg) {
2934a09e1dcSMatt Johnston __mctp_msg_free(bus->tx_msg, mctp);
2944a09e1dcSMatt Johnston bus->tx_msg = NULL;
2953ae89dceSAndrew Jeffery }
2963ae89dceSAndrew Jeffery }
2973ae89dceSAndrew Jeffery
mctp_cleanup(struct mctp * mctp)298722d0db2SMatt Johnston void mctp_cleanup(struct mctp *mctp)
299fa56ca5fSAndrew Jeffery {
300b93b6112SAndrew Jeffery size_t i;
301fa56ca5fSAndrew Jeffery
302fa56ca5fSAndrew Jeffery /* Cleanup message assembly contexts */
3033ef47785SMatt Johnston static_assert(ARRAY_SIZE(mctp->msg_ctxs) < SIZE_MAX, "size");
304fa56ca5fSAndrew Jeffery for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) {
305fa56ca5fSAndrew Jeffery struct mctp_msg_ctx *tmp = &mctp->msg_ctxs[i];
306fa56ca5fSAndrew Jeffery if (tmp->buf)
3074a09e1dcSMatt Johnston __mctp_msg_free(tmp->buf, mctp);
308fa56ca5fSAndrew Jeffery }
309fa56ca5fSAndrew Jeffery
3103ae89dceSAndrew Jeffery while (mctp->n_busses--)
3114a09e1dcSMatt Johnston mctp_bus_destroy(&mctp->busses[mctp->n_busses], mctp);
312722d0db2SMatt Johnston }
3133ae89dceSAndrew Jeffery
mctp_destroy(struct mctp * mctp)314722d0db2SMatt Johnston void mctp_destroy(struct mctp *mctp)
315722d0db2SMatt Johnston {
316722d0db2SMatt Johnston mctp_cleanup(mctp);
317fa56ca5fSAndrew Jeffery __mctp_free(mctp);
318fa56ca5fSAndrew Jeffery }
319fa56ca5fSAndrew Jeffery
mctp_set_rx_all(struct mctp * mctp,mctp_rx_fn fn,void * data)3204cdc200fSJeremy Kerr int mctp_set_rx_all(struct mctp *mctp, mctp_rx_fn fn, void *data)
3214cdc200fSJeremy Kerr {
3224cdc200fSJeremy Kerr mctp->message_rx = fn;
3234cdc200fSJeremy Kerr mctp->message_rx_data = data;
3244cdc200fSJeremy Kerr return 0;
3254cdc200fSJeremy Kerr }
3264cdc200fSJeremy Kerr
find_bus_for_eid(struct mctp * mctp,mctp_eid_t dest)327a721c2d8SPatrick Williams static struct mctp_bus *find_bus_for_eid(struct mctp *mctp, mctp_eid_t dest
328a721c2d8SPatrick Williams __attribute__((unused)))
3294cdc200fSJeremy Kerr {
330663ec39eSBrad Bishop if (mctp->n_busses == 0)
331663ec39eSBrad Bishop return NULL;
332663ec39eSBrad Bishop
3331a4ec3cdSJeremy Kerr /* for now, just use the first bus. For full routing support,
3341a4ec3cdSJeremy Kerr * we will need a table of neighbours */
3354cdc200fSJeremy Kerr return &mctp->busses[0];
3364cdc200fSJeremy Kerr }
3374cdc200fSJeremy Kerr
mctp_register_bus(struct mctp * mctp,struct mctp_binding * binding,mctp_eid_t eid)338a721c2d8SPatrick Williams int mctp_register_bus(struct mctp *mctp, struct mctp_binding *binding,
3394cdc200fSJeremy Kerr mctp_eid_t eid)
3404cdc200fSJeremy Kerr {
3413e8a12a4SAndrew Jeffery int rc = 0;
3423e8a12a4SAndrew Jeffery
3437520cec0SJeremy Kerr /* todo: multiple busses */
344722d0db2SMatt Johnston static_assert(MCTP_MAX_BUSSES >= 1, "need a bus");
3451a4ec3cdSJeremy Kerr assert(mctp->n_busses == 0);
3461a4ec3cdSJeremy Kerr mctp->n_busses = 1;
3473e8a12a4SAndrew Jeffery
3484a09e1dcSMatt Johnston assert(binding->tx_storage);
3494a09e1dcSMatt Johnston
35062d7236fSJames Feist memset(mctp->busses, 0, sizeof(struct mctp_bus));
3514a09e1dcSMatt Johnston mctp->busses[0].mctp = mctp;
3524cdc200fSJeremy Kerr mctp->busses[0].binding = binding;
3534cdc200fSJeremy Kerr mctp->busses[0].eid = eid;
3547520cec0SJeremy Kerr binding->bus = &mctp->busses[0];
3550a00dca2SJeremy Kerr binding->mctp = mctp;
3561a4ec3cdSJeremy Kerr mctp->route_policy = ROUTE_ENDPOINT;
3573b36d17cSJeremy Kerr
3583e8a12a4SAndrew Jeffery if (binding->start) {
3593e8a12a4SAndrew Jeffery rc = binding->start(binding);
3603e8a12a4SAndrew Jeffery if (rc < 0) {
3613e8a12a4SAndrew Jeffery mctp_prerr("Failed to start binding: %d", rc);
36219275230SAndrew Jeffery binding->bus = NULL;
3632304c833SAndrew Jeffery mctp->n_busses = 0;
3643e8a12a4SAndrew Jeffery }
3653e8a12a4SAndrew Jeffery }
3663b36d17cSJeremy Kerr
3673e8a12a4SAndrew Jeffery return rc;
3684cdc200fSJeremy Kerr }
3694cdc200fSJeremy Kerr
mctp_bus_set_eid(struct mctp_binding * binding,mctp_eid_t eid)3704058b2cbSMatt Johnston int mctp_bus_set_eid(struct mctp_binding *binding, mctp_eid_t eid)
3714058b2cbSMatt Johnston {
3724058b2cbSMatt Johnston if (eid < 8 || eid == 0xff) {
3734058b2cbSMatt Johnston return -EINVAL;
3744058b2cbSMatt Johnston }
3754058b2cbSMatt Johnston
3764058b2cbSMatt Johnston binding->bus->eid = eid;
3774058b2cbSMatt Johnston return 0;
3784058b2cbSMatt Johnston }
3794058b2cbSMatt Johnston
mctp_unregister_bus(struct mctp * mctp,struct mctp_binding * binding)3802094c3c0SAndrew Jeffery void mctp_unregister_bus(struct mctp *mctp, struct mctp_binding *binding)
3812094c3c0SAndrew Jeffery {
3822094c3c0SAndrew Jeffery /*
3832094c3c0SAndrew Jeffery * We only support one bus right now; once the call completes we will
3842094c3c0SAndrew Jeffery * have no more busses
3852094c3c0SAndrew Jeffery */
3862094c3c0SAndrew Jeffery mctp->n_busses = 0;
3872094c3c0SAndrew Jeffery binding->mctp = NULL;
3882094c3c0SAndrew Jeffery binding->bus = NULL;
3892094c3c0SAndrew Jeffery }
3902094c3c0SAndrew Jeffery
mctp_bridge_busses(struct mctp * mctp,struct mctp_binding * b1,struct mctp_binding * b2)391a721c2d8SPatrick Williams int mctp_bridge_busses(struct mctp *mctp, struct mctp_binding *b1,
392a721c2d8SPatrick Williams struct mctp_binding *b2)
3931a4ec3cdSJeremy Kerr {
39419275230SAndrew Jeffery int rc = 0;
39519275230SAndrew Jeffery
3964a09e1dcSMatt Johnston assert(b1->tx_storage);
3974a09e1dcSMatt Johnston assert(b2->tx_storage);
3984a09e1dcSMatt Johnston
3991a4ec3cdSJeremy Kerr assert(mctp->n_busses == 0);
400722d0db2SMatt Johnston assert(MCTP_MAX_BUSSES >= 2);
40162d7236fSJames Feist memset(mctp->busses, 0, 2 * sizeof(struct mctp_bus));
4021a4ec3cdSJeremy Kerr mctp->n_busses = 2;
4031a4ec3cdSJeremy Kerr mctp->busses[0].binding = b1;
4041a4ec3cdSJeremy Kerr b1->bus = &mctp->busses[0];
4051a4ec3cdSJeremy Kerr b1->mctp = mctp;
4061a4ec3cdSJeremy Kerr mctp->busses[1].binding = b2;
4071a4ec3cdSJeremy Kerr b2->bus = &mctp->busses[1];
4081a4ec3cdSJeremy Kerr b2->mctp = mctp;
4091a4ec3cdSJeremy Kerr
4101a4ec3cdSJeremy Kerr mctp->route_policy = ROUTE_BRIDGE;
4113b36d17cSJeremy Kerr
41219275230SAndrew Jeffery if (b1->start) {
41319275230SAndrew Jeffery rc = b1->start(b1);
41419275230SAndrew Jeffery if (rc < 0) {
41519275230SAndrew Jeffery mctp_prerr("Failed to start bridged bus %s: %d",
41619275230SAndrew Jeffery b1->name, rc);
41719275230SAndrew Jeffery goto done;
41819275230SAndrew Jeffery }
41919275230SAndrew Jeffery }
4203b36d17cSJeremy Kerr
42119275230SAndrew Jeffery if (b2->start) {
42219275230SAndrew Jeffery rc = b2->start(b2);
42319275230SAndrew Jeffery if (rc < 0) {
42419275230SAndrew Jeffery mctp_prerr("Failed to start bridged bus %s: %d",
42519275230SAndrew Jeffery b2->name, rc);
42619275230SAndrew Jeffery goto done;
42719275230SAndrew Jeffery }
42819275230SAndrew Jeffery }
4293b36d17cSJeremy Kerr
43019275230SAndrew Jeffery done:
43119275230SAndrew Jeffery return rc;
4321a4ec3cdSJeremy Kerr }
4331a4ec3cdSJeremy Kerr
mctp_ctrl_cmd_is_transport(struct mctp_ctrl_msg_hdr * hdr)434ba6727e6SWiktor Gołgowski static inline bool mctp_ctrl_cmd_is_transport(struct mctp_ctrl_msg_hdr *hdr)
4351a4ec3cdSJeremy Kerr {
4363ef47785SMatt Johnston #pragma GCC diagnostic push
4373ef47785SMatt Johnston #pragma GCC diagnostic ignored "-Wtype-limits"
438ba6727e6SWiktor Gołgowski return ((hdr->command_code >= MCTP_CTRL_CMD_FIRST_TRANSPORT) &&
439ba6727e6SWiktor Gołgowski (hdr->command_code <= MCTP_CTRL_CMD_LAST_TRANSPORT));
4403ef47785SMatt Johnston #pragma GCC diagnostic pop
441ba6727e6SWiktor Gołgowski }
442ba6727e6SWiktor Gołgowski
mctp_ctrl_handle_msg(struct mctp_bus * bus,mctp_eid_t src,uint8_t msg_tag,bool tag_owner,void * buffer,size_t length)443b93b6112SAndrew Jeffery static bool mctp_ctrl_handle_msg(struct mctp_bus *bus, mctp_eid_t src,
444f39c3857SSumanth Bhat uint8_t msg_tag, bool tag_owner, void *buffer,
445f39c3857SSumanth Bhat size_t length)
446ba6727e6SWiktor Gołgowski {
447ba6727e6SWiktor Gołgowski struct mctp_ctrl_msg_hdr *msg_hdr = buffer;
448ba6727e6SWiktor Gołgowski
449ba6727e6SWiktor Gołgowski /*
450ba6727e6SWiktor Gołgowski * Control message is received. If a transport control message handler
451ba6727e6SWiktor Gołgowski * is provided, it will called. If there is no dedicated handler, this
452ba6727e6SWiktor Gołgowski * function returns false and data can be handled by the generic
453ba6727e6SWiktor Gołgowski * message handler. The transport control message handler will be
454ba6727e6SWiktor Gołgowski * provided with messages in the command range 0xF0 - 0xFF.
455ba6727e6SWiktor Gołgowski */
456ba6727e6SWiktor Gołgowski if (mctp_ctrl_cmd_is_transport(msg_hdr)) {
457ba6727e6SWiktor Gołgowski if (bus->binding->control_rx != NULL) {
458ba6727e6SWiktor Gołgowski /* MCTP bus binding handler */
459f39c3857SSumanth Bhat bus->binding->control_rx(src, msg_tag, tag_owner,
460ba6727e6SWiktor Gołgowski bus->binding->control_rx_data,
461ba6727e6SWiktor Gołgowski buffer, length);
462ba6727e6SWiktor Gołgowski return true;
463ba6727e6SWiktor Gołgowski }
4644058b2cbSMatt Johnston } else {
4654058b2cbSMatt Johnston #if MCTP_CONTROL_HANDLER
4664058b2cbSMatt Johnston /* libmctp will handle control requests */
4674058b2cbSMatt Johnston return mctp_control_handler(bus, src, tag_owner, msg_tag,
4684058b2cbSMatt Johnston buffer, length);
4694058b2cbSMatt Johnston #endif
470ba6727e6SWiktor Gołgowski }
471ba6727e6SWiktor Gołgowski
472ba6727e6SWiktor Gołgowski /*
473ba6727e6SWiktor Gołgowski * Command was not handled, due to lack of specific callback.
474ba6727e6SWiktor Gołgowski * It will be passed to regular message_rx handler.
475ba6727e6SWiktor Gołgowski */
476ba6727e6SWiktor Gołgowski return false;
477ba6727e6SWiktor Gołgowski }
478ba6727e6SWiktor Gołgowski
mctp_rx_dest_is_local(struct mctp_bus * bus,mctp_eid_t dest)479ba6727e6SWiktor Gołgowski static inline bool mctp_rx_dest_is_local(struct mctp_bus *bus, mctp_eid_t dest)
480ba6727e6SWiktor Gołgowski {
481ba6727e6SWiktor Gołgowski return dest == bus->eid || dest == MCTP_EID_NULL ||
482ba6727e6SWiktor Gołgowski dest == MCTP_EID_BROADCAST;
483ba6727e6SWiktor Gołgowski }
484ba6727e6SWiktor Gołgowski
mctp_ctrl_cmd_is_request(struct mctp_ctrl_msg_hdr * hdr)485ba6727e6SWiktor Gołgowski static inline bool mctp_ctrl_cmd_is_request(struct mctp_ctrl_msg_hdr *hdr)
486ba6727e6SWiktor Gołgowski {
487ba6727e6SWiktor Gołgowski return hdr->ic_msg_type == MCTP_CTRL_HDR_MSG_TYPE &&
488ba6727e6SWiktor Gołgowski hdr->rq_dgram_inst & MCTP_CTRL_HDR_FLAG_REQUEST;
489ba6727e6SWiktor Gołgowski }
490ba6727e6SWiktor Gołgowski
491ba6727e6SWiktor Gołgowski /*
492ba6727e6SWiktor Gołgowski * Receive the complete MCTP message and route it.
493ba6727e6SWiktor Gołgowski * Asserts:
494ba6727e6SWiktor Gołgowski * 'buf' is not NULL.
495ba6727e6SWiktor Gołgowski */
mctp_rx(struct mctp * mctp,struct mctp_bus * bus,mctp_eid_t src,mctp_eid_t dest,bool tag_owner,uint8_t msg_tag,void * buf,size_t len)496ba6727e6SWiktor Gołgowski static void mctp_rx(struct mctp *mctp, struct mctp_bus *bus, mctp_eid_t src,
497f39c3857SSumanth Bhat mctp_eid_t dest, bool tag_owner, uint8_t msg_tag, void *buf,
498f39c3857SSumanth Bhat size_t len)
499ba6727e6SWiktor Gołgowski {
500ba6727e6SWiktor Gołgowski assert(buf != NULL);
501ba6727e6SWiktor Gołgowski
5021a4ec3cdSJeremy Kerr if (mctp->route_policy == ROUTE_ENDPOINT &&
503ba6727e6SWiktor Gołgowski mctp_rx_dest_is_local(bus, dest)) {
50461c95992SMatt Johnston /* Note responses to allocated tags */
50561c95992SMatt Johnston if (!tag_owner) {
50661c95992SMatt Johnston mctp_dealloc_tag(bus, dest, src, msg_tag);
50761c95992SMatt Johnston }
50861c95992SMatt Johnston
509ba6727e6SWiktor Gołgowski /* Handle MCTP Control Messages: */
510ba6727e6SWiktor Gołgowski if (len >= sizeof(struct mctp_ctrl_msg_hdr)) {
511ba6727e6SWiktor Gołgowski struct mctp_ctrl_msg_hdr *msg_hdr = buf;
512ba6727e6SWiktor Gołgowski
513ba6727e6SWiktor Gołgowski /*
514ba6727e6SWiktor Gołgowski * Identify if this is a control request message.
515ba6727e6SWiktor Gołgowski * See DSP0236 v1.3.0 sec. 11.5.
516ba6727e6SWiktor Gołgowski */
517ba6727e6SWiktor Gołgowski if (mctp_ctrl_cmd_is_request(msg_hdr)) {
518ba6727e6SWiktor Gołgowski bool handled;
519f39c3857SSumanth Bhat handled = mctp_ctrl_handle_msg(
520f39c3857SSumanth Bhat bus, src, msg_tag, tag_owner, buf, len);
521ba6727e6SWiktor Gołgowski if (handled)
522ba6727e6SWiktor Gołgowski return;
523ba6727e6SWiktor Gołgowski }
524ba6727e6SWiktor Gołgowski }
525f39c3857SSumanth Bhat
526ba6727e6SWiktor Gołgowski if (mctp->message_rx)
527f39c3857SSumanth Bhat mctp->message_rx(src, tag_owner, msg_tag,
528f39c3857SSumanth Bhat mctp->message_rx_data, buf, len);
529ba6727e6SWiktor Gołgowski }
5301a4ec3cdSJeremy Kerr
5311a4ec3cdSJeremy Kerr if (mctp->route_policy == ROUTE_BRIDGE) {
5321a4ec3cdSJeremy Kerr int i;
5331a4ec3cdSJeremy Kerr
5341a4ec3cdSJeremy Kerr for (i = 0; i < mctp->n_busses; i++) {
5351a4ec3cdSJeremy Kerr struct mctp_bus *dest_bus = &mctp->busses[i];
5361a4ec3cdSJeremy Kerr if (dest_bus == bus)
5371a4ec3cdSJeremy Kerr continue;
5381a4ec3cdSJeremy Kerr
5394a09e1dcSMatt Johnston void *copy = mctp_msg_dup(buf, len, mctp);
5404a09e1dcSMatt Johnston if (!copy) {
5414a09e1dcSMatt Johnston return;
5424a09e1dcSMatt Johnston }
5434a09e1dcSMatt Johnston
544f39c3857SSumanth Bhat mctp_message_tx_on_bus(dest_bus, src, dest, tag_owner,
5454a09e1dcSMatt Johnston msg_tag, copy, len);
5461a4ec3cdSJeremy Kerr }
5471a4ec3cdSJeremy Kerr }
5481a4ec3cdSJeremy Kerr }
5491a4ec3cdSJeremy Kerr
mctp_bus_rx(struct mctp_binding * binding,struct mctp_pktbuf * pkt)5500a00dca2SJeremy Kerr void mctp_bus_rx(struct mctp_binding *binding, struct mctp_pktbuf *pkt)
5514cdc200fSJeremy Kerr {
5527520cec0SJeremy Kerr struct mctp_bus *bus = binding->bus;
5530a00dca2SJeremy Kerr struct mctp *mctp = binding->mctp;
554c2def9f3SEd Tanous uint8_t flags, exp_seq, seq, tag;
55524db71fbSJeremy Kerr struct mctp_msg_ctx *ctx;
55624db71fbSJeremy Kerr struct mctp_hdr *hdr;
557f39c3857SSumanth Bhat bool tag_owner;
5584cdc200fSJeremy Kerr size_t len;
5594cdc200fSJeremy Kerr void *p;
56024db71fbSJeremy Kerr int rc;
5614cdc200fSJeremy Kerr
5627520cec0SJeremy Kerr assert(bus);
5637520cec0SJeremy Kerr
564d97869deSSumanth Bhat /* Drop packet if it was smaller than mctp hdr size */
56586e9a97aSMatt Johnston if (mctp_pktbuf_size(pkt) < sizeof(struct mctp_hdr))
566d97869deSSumanth Bhat goto out;
567d97869deSSumanth Bhat
5685d3d4e6dSAndrew Jeffery if (mctp->capture)
569f2988977SRashmica Gupta mctp->capture(pkt, MCTP_MESSAGE_CAPTURE_INCOMING,
570f2988977SRashmica Gupta mctp->capture_data);
5715d3d4e6dSAndrew Jeffery
57224db71fbSJeremy Kerr hdr = mctp_pktbuf_hdr(pkt);
57324db71fbSJeremy Kerr
57418b9a37bSMatt Johnston if (hdr->src == MCTP_EID_BROADCAST) {
57518b9a37bSMatt Johnston /* drop packets with broadcast EID src */
57618b9a37bSMatt Johnston goto out;
57718b9a37bSMatt Johnston }
57818b9a37bSMatt Johnston
5791a4ec3cdSJeremy Kerr /* small optimisation: don't bother reassembly if we're going to
5801a4ec3cdSJeremy Kerr * drop the packet in mctp_rx anyway */
581133df7abSJohn Chung if (mctp->route_policy == ROUTE_ENDPOINT &&
582133df7abSJohn Chung !mctp_rx_dest_is_local(bus, hdr->dest))
583c1693af4SJeremy Kerr goto out;
58424db71fbSJeremy Kerr
58524db71fbSJeremy Kerr flags = hdr->flags_seq_tag & (MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM);
58624db71fbSJeremy Kerr tag = (hdr->flags_seq_tag >> MCTP_HDR_TAG_SHIFT) & MCTP_HDR_TAG_MASK;
58724db71fbSJeremy Kerr seq = (hdr->flags_seq_tag >> MCTP_HDR_SEQ_SHIFT) & MCTP_HDR_SEQ_MASK;
5887f7fdc1dSAndrew Jeffery tag_owner = (hdr->flags_seq_tag >> MCTP_HDR_TO_SHIFT) &
5897f7fdc1dSAndrew Jeffery MCTP_HDR_TO_MASK;
59024db71fbSJeremy Kerr
59124db71fbSJeremy Kerr switch (flags) {
59224db71fbSJeremy Kerr case MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM:
59324db71fbSJeremy Kerr /* single-packet message - send straight up to rx function,
59424db71fbSJeremy Kerr * no need to create a message context */
5954cdc200fSJeremy Kerr len = pkt->end - pkt->mctp_hdr_off - sizeof(struct mctp_hdr);
5964a09e1dcSMatt Johnston p = mctp_msg_dup(pkt->data + pkt->mctp_hdr_off +
5974a09e1dcSMatt Johnston sizeof(struct mctp_hdr),
5984a09e1dcSMatt Johnston len, mctp);
5994a09e1dcSMatt Johnston if (p) {
6004a09e1dcSMatt Johnston mctp_rx(mctp, bus, hdr->src, hdr->dest, tag_owner, tag,
6014a09e1dcSMatt Johnston p, len);
6024a09e1dcSMatt Johnston __mctp_msg_free(p, mctp);
6034a09e1dcSMatt Johnston }
60424db71fbSJeremy Kerr break;
60524db71fbSJeremy Kerr
60624db71fbSJeremy Kerr case MCTP_HDR_FLAG_SOM:
60724db71fbSJeremy Kerr /* start of a new message - start the new context for
60824db71fbSJeremy Kerr * future message reception. If an existing context is
60924db71fbSJeremy Kerr * already present, drop it. */
6101a4ec3cdSJeremy Kerr ctx = mctp_msg_ctx_lookup(mctp, hdr->src, hdr->dest, tag);
61124db71fbSJeremy Kerr if (ctx) {
61224db71fbSJeremy Kerr mctp_msg_ctx_reset(ctx);
61324db71fbSJeremy Kerr } else {
614a721c2d8SPatrick Williams ctx = mctp_msg_ctx_create(mctp, hdr->src, hdr->dest,
615a721c2d8SPatrick Williams tag);
61634d4c96fSSumanth Bhat /* If context creation fails due to exhaution of contexts we
61734d4c96fSSumanth Bhat * can support, drop the packet */
61834d4c96fSSumanth Bhat if (!ctx) {
61934d4c96fSSumanth Bhat mctp_prdebug("Context buffers exhausted.");
62034d4c96fSSumanth Bhat goto out;
62134d4c96fSSumanth Bhat }
62224db71fbSJeremy Kerr }
62324db71fbSJeremy Kerr
62469f545f7SSumanth Bhat /* Save the fragment size, subsequent middle fragments
62569f545f7SSumanth Bhat * should of the same size */
62669f545f7SSumanth Bhat ctx->fragment_size = mctp_pktbuf_size(pkt);
62769f545f7SSumanth Bhat
6284a09e1dcSMatt Johnston rc = mctp_msg_ctx_add_pkt(ctx, pkt);
62924db71fbSJeremy Kerr if (rc) {
6304a09e1dcSMatt Johnston mctp_msg_ctx_drop(bus, ctx);
63124db71fbSJeremy Kerr } else {
63224db71fbSJeremy Kerr ctx->last_seq = seq;
63324db71fbSJeremy Kerr }
63424db71fbSJeremy Kerr
63524db71fbSJeremy Kerr break;
63624db71fbSJeremy Kerr
63724db71fbSJeremy Kerr case MCTP_HDR_FLAG_EOM:
6381a4ec3cdSJeremy Kerr ctx = mctp_msg_ctx_lookup(mctp, hdr->src, hdr->dest, tag);
63924db71fbSJeremy Kerr if (!ctx)
640c1693af4SJeremy Kerr goto out;
64124db71fbSJeremy Kerr
642c2def9f3SEd Tanous exp_seq = (ctx->last_seq + 1) % 4;
643c2def9f3SEd Tanous
644c2def9f3SEd Tanous if (exp_seq != seq) {
645c2def9f3SEd Tanous mctp_prdebug(
646c2def9f3SEd Tanous "Sequence number %d does not match expected %d",
647c2def9f3SEd Tanous seq, exp_seq);
6484a09e1dcSMatt Johnston mctp_msg_ctx_drop(bus, ctx);
649c1693af4SJeremy Kerr goto out;
65024db71fbSJeremy Kerr }
65124db71fbSJeremy Kerr
65269f545f7SSumanth Bhat len = mctp_pktbuf_size(pkt);
65369f545f7SSumanth Bhat
65469f545f7SSumanth Bhat if (len > ctx->fragment_size) {
655a721c2d8SPatrick Williams mctp_prdebug("Unexpected fragment size. Expected"
65669f545f7SSumanth Bhat " less than %zu, received = %zu",
65769f545f7SSumanth Bhat ctx->fragment_size, len);
6584a09e1dcSMatt Johnston mctp_msg_ctx_drop(bus, ctx);
65969f545f7SSumanth Bhat goto out;
66069f545f7SSumanth Bhat }
66169f545f7SSumanth Bhat
6624a09e1dcSMatt Johnston rc = mctp_msg_ctx_add_pkt(ctx, pkt);
6631a4ec3cdSJeremy Kerr if (!rc)
664f39c3857SSumanth Bhat mctp_rx(mctp, bus, ctx->src, ctx->dest, tag_owner, tag,
66524db71fbSJeremy Kerr ctx->buf, ctx->buf_size);
66624db71fbSJeremy Kerr
6674a09e1dcSMatt Johnston mctp_msg_ctx_drop(bus, ctx);
66824db71fbSJeremy Kerr break;
669c2def9f3SEd Tanous
670c2def9f3SEd Tanous case 0:
671c2def9f3SEd Tanous /* Neither SOM nor EOM */
6721a4ec3cdSJeremy Kerr ctx = mctp_msg_ctx_lookup(mctp, hdr->src, hdr->dest, tag);
673c2def9f3SEd Tanous if (!ctx)
674c1693af4SJeremy Kerr goto out;
675c2def9f3SEd Tanous
676c2def9f3SEd Tanous exp_seq = (ctx->last_seq + 1) % 4;
677c2def9f3SEd Tanous if (exp_seq != seq) {
678c2def9f3SEd Tanous mctp_prdebug(
679c2def9f3SEd Tanous "Sequence number %d does not match expected %d",
680c2def9f3SEd Tanous seq, exp_seq);
6814a09e1dcSMatt Johnston mctp_msg_ctx_drop(bus, ctx);
682c1693af4SJeremy Kerr goto out;
683c2def9f3SEd Tanous }
684c2def9f3SEd Tanous
68569f545f7SSumanth Bhat len = mctp_pktbuf_size(pkt);
68669f545f7SSumanth Bhat
68769f545f7SSumanth Bhat if (len != ctx->fragment_size) {
688a721c2d8SPatrick Williams mctp_prdebug("Unexpected fragment size. Expected = %zu "
689a721c2d8SPatrick Williams "received = %zu",
690a721c2d8SPatrick Williams ctx->fragment_size, len);
6914a09e1dcSMatt Johnston mctp_msg_ctx_drop(bus, ctx);
69269f545f7SSumanth Bhat goto out;
69369f545f7SSumanth Bhat }
69469f545f7SSumanth Bhat
6954a09e1dcSMatt Johnston rc = mctp_msg_ctx_add_pkt(ctx, pkt);
696c2def9f3SEd Tanous if (rc) {
6974a09e1dcSMatt Johnston mctp_msg_ctx_drop(bus, ctx);
698c1693af4SJeremy Kerr goto out;
699c2def9f3SEd Tanous }
700c2def9f3SEd Tanous ctx->last_seq = seq;
701c2def9f3SEd Tanous
702c2def9f3SEd Tanous break;
70324db71fbSJeremy Kerr }
704c1693af4SJeremy Kerr out:
7054a09e1dcSMatt Johnston return;
7064cdc200fSJeremy Kerr }
7074cdc200fSJeremy Kerr
mctp_packet_tx(struct mctp_bus * bus,struct mctp_pktbuf * pkt)708a721c2d8SPatrick Williams static int mctp_packet_tx(struct mctp_bus *bus, struct mctp_pktbuf *pkt)
7094cdc200fSJeremy Kerr {
7105d3d4e6dSAndrew Jeffery struct mctp *mctp = bus->binding->mctp;
7115d3d4e6dSAndrew Jeffery
7124a09e1dcSMatt Johnston if (bus->state != mctp_bus_state_tx_enabled) {
7134a09e1dcSMatt Johnston mctp_prdebug("tx with bus disabled");
7141cd31184SJeremy Kerr return -1;
7154a09e1dcSMatt Johnston }
7161cd31184SJeremy Kerr
7175d3d4e6dSAndrew Jeffery if (mctp->capture)
718f2988977SRashmica Gupta mctp->capture(pkt, MCTP_MESSAGE_CAPTURE_OUTGOING,
719f2988977SRashmica Gupta mctp->capture_data);
7205d3d4e6dSAndrew Jeffery
7214cdc200fSJeremy Kerr return bus->binding->tx(bus->binding, pkt);
7224cdc200fSJeremy Kerr }
7234cdc200fSJeremy Kerr
7244a09e1dcSMatt Johnston /* Returns a pointer to the binding's tx_storage */
mctp_next_tx_pkt(struct mctp_bus * bus)7254a09e1dcSMatt Johnston static struct mctp_pktbuf *mctp_next_tx_pkt(struct mctp_bus *bus)
7264a09e1dcSMatt Johnston {
7274a09e1dcSMatt Johnston if (!bus->tx_msg) {
7284a09e1dcSMatt Johnston return NULL;
7294a09e1dcSMatt Johnston }
7304a09e1dcSMatt Johnston
7314a09e1dcSMatt Johnston size_t p = bus->tx_msgpos;
7324a09e1dcSMatt Johnston size_t msg_len = bus->tx_msglen;
7334a09e1dcSMatt Johnston size_t payload_len = msg_len - p;
7344a09e1dcSMatt Johnston size_t max_payload_len = MCTP_BODY_SIZE(bus->binding->pkt_size);
7354a09e1dcSMatt Johnston if (payload_len > max_payload_len)
7364a09e1dcSMatt Johnston payload_len = max_payload_len;
7374a09e1dcSMatt Johnston
7384a09e1dcSMatt Johnston struct mctp_pktbuf *pkt =
7394a09e1dcSMatt Johnston mctp_pktbuf_init(bus->binding, bus->binding->tx_storage);
7404a09e1dcSMatt Johnston struct mctp_hdr *hdr = mctp_pktbuf_hdr(pkt);
7414a09e1dcSMatt Johnston
7424a09e1dcSMatt Johnston hdr->ver = bus->binding->version & 0xf;
7434a09e1dcSMatt Johnston hdr->dest = bus->tx_dest;
7444a09e1dcSMatt Johnston hdr->src = bus->tx_src;
7454a09e1dcSMatt Johnston hdr->flags_seq_tag = (bus->tx_to << MCTP_HDR_TO_SHIFT) |
7464a09e1dcSMatt Johnston (bus->tx_tag << MCTP_HDR_TAG_SHIFT);
7474a09e1dcSMatt Johnston
7484a09e1dcSMatt Johnston if (p == 0)
7494a09e1dcSMatt Johnston hdr->flags_seq_tag |= MCTP_HDR_FLAG_SOM;
7504a09e1dcSMatt Johnston if (p + payload_len >= msg_len)
7514a09e1dcSMatt Johnston hdr->flags_seq_tag |= MCTP_HDR_FLAG_EOM;
7524a09e1dcSMatt Johnston hdr->flags_seq_tag |= bus->tx_seq << MCTP_HDR_SEQ_SHIFT;
7534a09e1dcSMatt Johnston
7544a09e1dcSMatt Johnston memcpy(mctp_pktbuf_data(pkt), (uint8_t *)bus->tx_msg + p, payload_len);
7554a09e1dcSMatt Johnston pkt->end = pkt->start + sizeof(*hdr) + payload_len;
7564a09e1dcSMatt Johnston bus->tx_pktlen = payload_len;
7574a09e1dcSMatt Johnston
7584a09e1dcSMatt Johnston mctp_prdebug(
7594a09e1dcSMatt Johnston "tx dst %d tag %d payload len %zu seq %d. msg pos %zu len %zu",
7604a09e1dcSMatt Johnston hdr->dest, bus->tx_tag, payload_len, bus->tx_seq, p, msg_len);
7614a09e1dcSMatt Johnston
7624a09e1dcSMatt Johnston return pkt;
7634a09e1dcSMatt Johnston }
7644a09e1dcSMatt Johnston
7654a09e1dcSMatt Johnston /* Called when a packet has successfully been sent */
mctp_tx_complete(struct mctp_bus * bus)7664a09e1dcSMatt Johnston static void mctp_tx_complete(struct mctp_bus *bus)
7674a09e1dcSMatt Johnston {
7684a09e1dcSMatt Johnston if (!bus->tx_msg) {
7694a09e1dcSMatt Johnston mctp_prdebug("tx complete no message");
7704a09e1dcSMatt Johnston return;
7714a09e1dcSMatt Johnston }
7724a09e1dcSMatt Johnston
7734a09e1dcSMatt Johnston bus->tx_seq = (bus->tx_seq + 1) & MCTP_HDR_SEQ_MASK;
7744a09e1dcSMatt Johnston bus->tx_msgpos += bus->tx_pktlen;
7754a09e1dcSMatt Johnston
7764a09e1dcSMatt Johnston if (bus->tx_msgpos >= bus->tx_msglen) {
7774a09e1dcSMatt Johnston __mctp_msg_free(bus->tx_msg, bus->binding->mctp);
7784a09e1dcSMatt Johnston bus->tx_msg = NULL;
7794a09e1dcSMatt Johnston }
7804a09e1dcSMatt Johnston }
7814a09e1dcSMatt Johnston
mctp_send_tx_queue(struct mctp_bus * bus)782cc2458d9SJeremy Kerr static void mctp_send_tx_queue(struct mctp_bus *bus)
7831cd31184SJeremy Kerr {
7841cd31184SJeremy Kerr struct mctp_pktbuf *pkt;
7851cd31184SJeremy Kerr
7864a09e1dcSMatt Johnston while (bus->tx_msg && bus->state == mctp_bus_state_tx_enabled) {
7871cd31184SJeremy Kerr int rc;
7881cd31184SJeremy Kerr
7894a09e1dcSMatt Johnston pkt = mctp_next_tx_pkt(bus);
7904a09e1dcSMatt Johnston
7911cd31184SJeremy Kerr rc = mctp_packet_tx(bus, pkt);
7920721f585SAndrew Jeffery switch (rc) {
7934a09e1dcSMatt Johnston /* If transmission succeded */
7940721f585SAndrew Jeffery case 0:
7950721f585SAndrew Jeffery /* Drop the packet */
7964a09e1dcSMatt Johnston mctp_tx_complete(bus);
7970721f585SAndrew Jeffery break;
7980721f585SAndrew Jeffery
7994a09e1dcSMatt Johnston /* If the binding was busy */
8000721f585SAndrew Jeffery case -EBUSY:
8014a09e1dcSMatt Johnston /* Keep the packet for next try */
8024a09e1dcSMatt Johnston mctp_prdebug("tx EBUSY");
8034a09e1dcSMatt Johnston return;
8044a09e1dcSMatt Johnston
8050721f585SAndrew Jeffery /* Some other unknown error occurred */
8060721f585SAndrew Jeffery default:
8074a09e1dcSMatt Johnston /* Drop the packet */
8084a09e1dcSMatt Johnston mctp_prdebug("tx drop %d", rc);
8094a09e1dcSMatt Johnston mctp_tx_complete(bus);
8104a09e1dcSMatt Johnston return;
8110721f585SAndrew Jeffery };
8121cd31184SJeremy Kerr }
8131cd31184SJeremy Kerr }
8141cd31184SJeremy Kerr
mctp_binding_set_tx_enabled(struct mctp_binding * binding,bool enable)8151cd31184SJeremy Kerr void mctp_binding_set_tx_enabled(struct mctp_binding *binding, bool enable)
8161cd31184SJeremy Kerr {
8171cd31184SJeremy Kerr struct mctp_bus *bus = binding->bus;
818c61501ccSAndrew Jeffery
819c61501ccSAndrew Jeffery switch (bus->state) {
820c61501ccSAndrew Jeffery case mctp_bus_state_constructed:
821c61501ccSAndrew Jeffery if (!enable)
822c61501ccSAndrew Jeffery return;
823c61501ccSAndrew Jeffery
8241fa707e2SAndrew Jeffery if (binding->pkt_size < MCTP_PACKET_SIZE(MCTP_BTU)) {
825a721c2d8SPatrick Williams mctp_prerr(
826a721c2d8SPatrick Williams "Cannot start %s binding with invalid MTU: %zu",
8271fa707e2SAndrew Jeffery binding->name,
8281fa707e2SAndrew Jeffery MCTP_BODY_SIZE(binding->pkt_size));
8291fa707e2SAndrew Jeffery return;
8301fa707e2SAndrew Jeffery }
8311fa707e2SAndrew Jeffery
832c61501ccSAndrew Jeffery bus->state = mctp_bus_state_tx_enabled;
833c61501ccSAndrew Jeffery mctp_prinfo("%s binding started", binding->name);
834c61501ccSAndrew Jeffery return;
835c61501ccSAndrew Jeffery case mctp_bus_state_tx_enabled:
8361cd31184SJeremy Kerr if (enable)
837c61501ccSAndrew Jeffery return;
838c61501ccSAndrew Jeffery
839c61501ccSAndrew Jeffery bus->state = mctp_bus_state_tx_disabled;
840c61501ccSAndrew Jeffery mctp_prdebug("%s binding Tx disabled", binding->name);
841c61501ccSAndrew Jeffery return;
842c61501ccSAndrew Jeffery case mctp_bus_state_tx_disabled:
843c61501ccSAndrew Jeffery if (!enable)
844c61501ccSAndrew Jeffery return;
845c61501ccSAndrew Jeffery
846c61501ccSAndrew Jeffery bus->state = mctp_bus_state_tx_enabled;
847c61501ccSAndrew Jeffery mctp_prdebug("%s binding Tx enabled", binding->name);
848cc2458d9SJeremy Kerr mctp_send_tx_queue(bus);
849c61501ccSAndrew Jeffery return;
850c61501ccSAndrew Jeffery }
8511cd31184SJeremy Kerr }
8521cd31184SJeremy Kerr
mctp_message_tx_on_bus(struct mctp_bus * bus,mctp_eid_t src,mctp_eid_t dest,bool tag_owner,uint8_t msg_tag,void * msg,size_t msg_len)853b93b6112SAndrew Jeffery static int mctp_message_tx_on_bus(struct mctp_bus *bus, mctp_eid_t src,
854f39c3857SSumanth Bhat mctp_eid_t dest, bool tag_owner,
855f39c3857SSumanth Bhat uint8_t msg_tag, void *msg, size_t msg_len)
8564cdc200fSJeremy Kerr {
8574a09e1dcSMatt Johnston size_t max_payload_len;
8584a09e1dcSMatt Johnston int rc;
8594cdc200fSJeremy Kerr
8604a09e1dcSMatt Johnston if (bus->state == mctp_bus_state_constructed) {
8614a09e1dcSMatt Johnston rc = -ENXIO;
8624a09e1dcSMatt Johnston goto err;
8634a09e1dcSMatt Johnston }
864c61501ccSAndrew Jeffery
8654a09e1dcSMatt Johnston if ((msg_tag & MCTP_HDR_TAG_MASK) != msg_tag) {
8664a09e1dcSMatt Johnston rc = -EINVAL;
8674a09e1dcSMatt Johnston goto err;
8684a09e1dcSMatt Johnston }
869f39c3857SSumanth Bhat
8701fa707e2SAndrew Jeffery max_payload_len = MCTP_BODY_SIZE(bus->binding->pkt_size);
8711fa707e2SAndrew Jeffery
8721fa707e2SAndrew Jeffery {
8731fa707e2SAndrew Jeffery const bool valid_mtu = max_payload_len >= MCTP_BTU;
8741fa707e2SAndrew Jeffery assert(valid_mtu);
8754a09e1dcSMatt Johnston if (!valid_mtu) {
8764a09e1dcSMatt Johnston rc = -EINVAL;
8774a09e1dcSMatt Johnston goto err;
8784a09e1dcSMatt Johnston }
8791fa707e2SAndrew Jeffery }
8804cdc200fSJeremy Kerr
881a721c2d8SPatrick Williams mctp_prdebug(
882a721c2d8SPatrick Williams "%s: Generating packets for transmission of %zu byte message from %hhu to %hhu",
883298865fcSAndrew Jeffery __func__, msg_len, src, dest);
884298865fcSAndrew Jeffery
8854a09e1dcSMatt Johnston if (bus->tx_msg) {
8864a09e1dcSMatt Johnston mctp_prdebug("Bus busy");
8874a09e1dcSMatt Johnston rc = -EBUSY;
8884a09e1dcSMatt Johnston goto err;
88924db71fbSJeremy Kerr }
89024db71fbSJeremy Kerr
8914a09e1dcSMatt Johnston /* Take the message to send */
8924a09e1dcSMatt Johnston bus->tx_msg = msg;
8934a09e1dcSMatt Johnston bus->tx_msglen = msg_len;
8944a09e1dcSMatt Johnston bus->tx_msgpos = 0;
8954a09e1dcSMatt Johnston /* bus->tx_seq is allowed to continue from previous message */
8964a09e1dcSMatt Johnston bus->tx_src = src;
8974a09e1dcSMatt Johnston bus->tx_dest = dest;
8984a09e1dcSMatt Johnston bus->tx_to = tag_owner;
8994a09e1dcSMatt Johnston bus->tx_tag = msg_tag;
900298865fcSAndrew Jeffery
901cc2458d9SJeremy Kerr mctp_send_tx_queue(bus);
90224db71fbSJeremy Kerr return 0;
9034a09e1dcSMatt Johnston
9044a09e1dcSMatt Johnston err:
9054a09e1dcSMatt Johnston __mctp_msg_free(msg, bus->binding->mctp);
9064a09e1dcSMatt Johnston return rc;
9074cdc200fSJeremy Kerr }
9081a4ec3cdSJeremy Kerr
mctp_message_tx_alloced(struct mctp * mctp,mctp_eid_t eid,bool tag_owner,uint8_t msg_tag,void * msg,size_t msg_len)9094a09e1dcSMatt Johnston int mctp_message_tx_alloced(struct mctp *mctp, mctp_eid_t eid, bool tag_owner,
910f39c3857SSumanth Bhat uint8_t msg_tag, void *msg, size_t msg_len)
9111a4ec3cdSJeremy Kerr {
9121a4ec3cdSJeremy Kerr struct mctp_bus *bus;
9131a4ec3cdSJeremy Kerr
914f39c3857SSumanth Bhat /* TODO: Protect against same tag being used across
915f39c3857SSumanth Bhat * different callers */
916f39c3857SSumanth Bhat if ((msg_tag & MCTP_HDR_TAG_MASK) != msg_tag) {
917f39c3857SSumanth Bhat mctp_prerr("Incorrect message tag %u passed.", msg_tag);
9184a09e1dcSMatt Johnston __mctp_msg_free(msg, mctp);
919f39c3857SSumanth Bhat return -EINVAL;
920f39c3857SSumanth Bhat }
921f39c3857SSumanth Bhat
9221a4ec3cdSJeremy Kerr bus = find_bus_for_eid(mctp, eid);
9234a09e1dcSMatt Johnston if (!bus) {
9244a09e1dcSMatt Johnston __mctp_msg_free(msg, mctp);
925663ec39eSBrad Bishop return 0;
9264a09e1dcSMatt Johnston }
927663ec39eSBrad Bishop
928f39c3857SSumanth Bhat return mctp_message_tx_on_bus(bus, bus->eid, eid, tag_owner, msg_tag,
929f39c3857SSumanth Bhat msg, msg_len);
9301a4ec3cdSJeremy Kerr }
9314a09e1dcSMatt Johnston
mctp_message_tx(struct mctp * mctp,mctp_eid_t eid,bool tag_owner,uint8_t msg_tag,const void * msg,size_t msg_len)9324a09e1dcSMatt Johnston int mctp_message_tx(struct mctp *mctp, mctp_eid_t eid, bool tag_owner,
9334a09e1dcSMatt Johnston uint8_t msg_tag, const void *msg, size_t msg_len)
9344a09e1dcSMatt Johnston {
9354a09e1dcSMatt Johnston void *copy = mctp_msg_dup(msg, msg_len, mctp);
9364a09e1dcSMatt Johnston if (!copy) {
9374a09e1dcSMatt Johnston return -ENOMEM;
9384a09e1dcSMatt Johnston }
9394a09e1dcSMatt Johnston
9404a09e1dcSMatt Johnston return mctp_message_tx_alloced(mctp, eid, tag_owner, msg_tag, copy,
9414a09e1dcSMatt Johnston msg_len);
9424a09e1dcSMatt Johnston }
9434a09e1dcSMatt Johnston
mctp_set_now_op(struct mctp * mctp,uint64_t (* now)(void *),void * ctx)94444e64dfaSMatt Johnston void mctp_set_now_op(struct mctp *mctp, uint64_t (*now)(void *), void *ctx)
94544e64dfaSMatt Johnston {
94644e64dfaSMatt Johnston assert(now);
94744e64dfaSMatt Johnston mctp->platform_now = now;
94844e64dfaSMatt Johnston mctp->platform_now_ctx = ctx;
94944e64dfaSMatt Johnston }
95044e64dfaSMatt Johnston
mctp_now(struct mctp * mctp)95144e64dfaSMatt Johnston uint64_t mctp_now(struct mctp *mctp)
95244e64dfaSMatt Johnston {
95344e64dfaSMatt Johnston assert(mctp->platform_now);
95444e64dfaSMatt Johnston return mctp->platform_now(mctp->platform_now_ctx);
95544e64dfaSMatt Johnston }
95644e64dfaSMatt Johnston
mctp_dealloc_tag(struct mctp_bus * bus,mctp_eid_t local,mctp_eid_t remote,uint8_t tag)95761c95992SMatt Johnston static void mctp_dealloc_tag(struct mctp_bus *bus, mctp_eid_t local,
95861c95992SMatt Johnston mctp_eid_t remote, uint8_t tag)
95961c95992SMatt Johnston {
96061c95992SMatt Johnston struct mctp *mctp = bus->binding->mctp;
96144e64dfaSMatt Johnston if (local == 0) {
96261c95992SMatt Johnston return;
96361c95992SMatt Johnston }
96461c95992SMatt Johnston
96561c95992SMatt Johnston for (size_t i = 0; i < ARRAY_SIZE(mctp->req_tags); i++) {
96661c95992SMatt Johnston struct mctp_req_tag *r = &mctp->req_tags[i];
96761c95992SMatt Johnston if (r->local == local && r->remote == remote && r->tag == tag) {
96861c95992SMatt Johnston r->local = 0;
96961c95992SMatt Johnston r->remote = 0;
97061c95992SMatt Johnston r->tag = 0;
97144e64dfaSMatt Johnston r->expiry = 0;
97261c95992SMatt Johnston return;
97361c95992SMatt Johnston }
97461c95992SMatt Johnston }
97561c95992SMatt Johnston }
97661c95992SMatt Johnston
mctp_alloc_tag(struct mctp * mctp,mctp_eid_t local,mctp_eid_t remote,uint8_t * ret_tag)97761c95992SMatt Johnston static int mctp_alloc_tag(struct mctp *mctp, mctp_eid_t local,
97861c95992SMatt Johnston mctp_eid_t remote, uint8_t *ret_tag)
97961c95992SMatt Johnston {
98061c95992SMatt Johnston assert(local != 0);
98144e64dfaSMatt Johnston uint64_t now = mctp_now(mctp);
98261c95992SMatt Johnston
98361c95992SMatt Johnston uint8_t used = 0;
98461c95992SMatt Johnston struct mctp_req_tag *spare = NULL;
98561c95992SMatt Johnston /* Find which tags and slots are used/spare */
98661c95992SMatt Johnston for (size_t i = 0; i < ARRAY_SIZE(mctp->req_tags); i++) {
98761c95992SMatt Johnston struct mctp_req_tag *r = &mctp->req_tags[i];
98844e64dfaSMatt Johnston if (r->local == 0 || r->expiry < now) {
98961c95992SMatt Johnston spare = r;
99061c95992SMatt Johnston } else {
99161c95992SMatt Johnston if (r->local == local && r->remote == remote) {
99261c95992SMatt Johnston used |= 1 << r->tag;
99361c95992SMatt Johnston }
99461c95992SMatt Johnston }
99561c95992SMatt Johnston }
99661c95992SMatt Johnston
99761c95992SMatt Johnston if (spare == NULL) {
99861c95992SMatt Johnston // All req_tag slots are in-use
99961c95992SMatt Johnston return -EBUSY;
100061c95992SMatt Johnston }
100161c95992SMatt Johnston
100261c95992SMatt Johnston for (uint8_t t = 0; t < 8; t++) {
100361c95992SMatt Johnston uint8_t tag = (t + mctp->tag_round_robin) % 8;
100461c95992SMatt Johnston if ((used & 1 << tag) == 0) {
100561c95992SMatt Johnston spare->local = local;
100661c95992SMatt Johnston spare->remote = remote;
100761c95992SMatt Johnston spare->tag = tag;
100844e64dfaSMatt Johnston spare->expiry = now + MCTP_TAG_TIMEOUT;
100961c95992SMatt Johnston *ret_tag = tag;
101061c95992SMatt Johnston mctp->tag_round_robin = (tag + 1) % 8;
101161c95992SMatt Johnston return 0;
101261c95992SMatt Johnston }
101361c95992SMatt Johnston }
101461c95992SMatt Johnston
101561c95992SMatt Johnston // All 8 tags are used for this src/dest pair
101661c95992SMatt Johnston return -EBUSY;
101761c95992SMatt Johnston }
101861c95992SMatt Johnston
mctp_message_tx_request(struct mctp * mctp,mctp_eid_t eid,void * msg,size_t msg_len,uint8_t * ret_alloc_msg_tag)101961c95992SMatt Johnston int mctp_message_tx_request(struct mctp *mctp, mctp_eid_t eid, void *msg,
102061c95992SMatt Johnston size_t msg_len, uint8_t *ret_alloc_msg_tag)
102161c95992SMatt Johnston {
102261c95992SMatt Johnston int rc;
102361c95992SMatt Johnston struct mctp_bus *bus;
102461c95992SMatt Johnston
102561c95992SMatt Johnston bus = find_bus_for_eid(mctp, eid);
102661c95992SMatt Johnston if (!bus) {
102761c95992SMatt Johnston __mctp_msg_free(msg, mctp);
102861c95992SMatt Johnston return 0;
102961c95992SMatt Johnston }
103061c95992SMatt Johnston
103161c95992SMatt Johnston uint8_t alloc_tag;
103261c95992SMatt Johnston rc = mctp_alloc_tag(mctp, bus->eid, eid, &alloc_tag);
103361c95992SMatt Johnston if (rc) {
103461c95992SMatt Johnston mctp_prdebug("Failed allocating tag");
103561c95992SMatt Johnston __mctp_msg_free(msg, mctp);
103661c95992SMatt Johnston return rc;
103761c95992SMatt Johnston }
103861c95992SMatt Johnston
103961c95992SMatt Johnston if (ret_alloc_msg_tag) {
104061c95992SMatt Johnston *ret_alloc_msg_tag = alloc_tag;
104161c95992SMatt Johnston }
104261c95992SMatt Johnston
104361c95992SMatt Johnston return mctp_message_tx_alloced(mctp, eid, true, alloc_tag, msg,
104461c95992SMatt Johnston msg_len);
104561c95992SMatt Johnston }
104661c95992SMatt Johnston
mctp_is_tx_ready(struct mctp * mctp,mctp_eid_t eid)10474a09e1dcSMatt Johnston bool mctp_is_tx_ready(struct mctp *mctp, mctp_eid_t eid)
10484a09e1dcSMatt Johnston {
10494a09e1dcSMatt Johnston struct mctp_bus *bus;
10504a09e1dcSMatt Johnston
10514a09e1dcSMatt Johnston bus = find_bus_for_eid(mctp, eid);
10524a09e1dcSMatt Johnston if (!bus) {
10534a09e1dcSMatt Johnston return true;
10544a09e1dcSMatt Johnston }
10554a09e1dcSMatt Johnston return bus->tx_msg == NULL;
10564a09e1dcSMatt Johnston }
10574a09e1dcSMatt Johnston
mctp_get_alloc_ctx(struct mctp * mctp)10584a09e1dcSMatt Johnston void *mctp_get_alloc_ctx(struct mctp *mctp)
10594a09e1dcSMatt Johnston {
10604a09e1dcSMatt Johnston return mctp->alloc_ctx;
10614a09e1dcSMatt Johnston }
10624a09e1dcSMatt Johnston
mctp_set_alloc_ctx(struct mctp * mctp,void * ctx)10634a09e1dcSMatt Johnston void mctp_set_alloc_ctx(struct mctp *mctp, void *ctx)
10644a09e1dcSMatt Johnston {
10654a09e1dcSMatt Johnston mctp->alloc_ctx = ctx;
10664a09e1dcSMatt Johnston }
1067