xref: /openbmc/libmctp/core.c (revision 5d3d4e6d)
1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2 
3 #include <assert.h>
4 #include <errno.h>
5 #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"
18 #include "libmctp-cmds.h"
19 #include "range.h"
20 
21 /* Internal data structures */
22 
23 enum mctp_bus_state {
24 	mctp_bus_state_constructed = 0,
25 	mctp_bus_state_tx_enabled,
26 	mctp_bus_state_tx_disabled,
27 };
28 
29 struct mctp_bus {
30 	mctp_eid_t eid;
31 	struct mctp_binding *binding;
32 	enum mctp_bus_state state;
33 
34 	struct mctp_pktbuf *tx_queue_head;
35 	struct mctp_pktbuf *tx_queue_tail;
36 
37 	/* todo: routing */
38 };
39 
40 struct mctp_msg_ctx {
41 	uint8_t		src;
42 	uint8_t		dest;
43 	uint8_t		tag;
44 	uint8_t		last_seq;
45 	void		*buf;
46 	size_t		buf_size;
47 	size_t		buf_alloc_size;
48 	size_t		fragment_size;
49 };
50 
51 struct mctp {
52 	int			n_busses;
53 	struct mctp_bus		*busses;
54 
55 	/* Message RX callback */
56 	mctp_rx_fn		message_rx;
57 	void			*message_rx_data;
58 
59 	/* Packet capture callback */
60 	mctp_capture_fn		capture;
61 	void			*capture_data;
62 
63 	/* Message reassembly.
64 	 * @todo: flexible context count
65 	 */
66 	struct mctp_msg_ctx	msg_ctxs[16];
67 
68 	enum {
69 		ROUTE_ENDPOINT,
70 		ROUTE_BRIDGE,
71 	}			route_policy;
72 	size_t max_message_size;
73 };
74 
75 #ifndef BUILD_ASSERT
76 #define BUILD_ASSERT(x) \
77 	do { (void)sizeof(char[0-(!(x))]); } while (0)
78 #endif
79 
80 #ifndef ARRAY_SIZE
81 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
82 #endif
83 
84 /* 64kb should be sufficient for a single message. Applications
85  * requiring higher sizes can override by setting max_message_size.*/
86 #ifndef MCTP_MAX_MESSAGE_SIZE
87 #define MCTP_MAX_MESSAGE_SIZE 65536
88 #endif
89 
90 static int mctp_message_tx_on_bus(struct mctp_bus *bus, mctp_eid_t src,
91 				  mctp_eid_t dest, void *msg, size_t msg_len);
92 
93 struct mctp_pktbuf *mctp_pktbuf_alloc(struct mctp_binding *binding, size_t len)
94 {
95 	struct mctp_pktbuf *buf;
96 	size_t size;
97 
98 	size = binding->pkt_size + binding->pkt_header + binding->pkt_trailer;
99 
100 	/* todo: pools */
101 	buf = __mctp_alloc(sizeof(*buf) + size);
102 
103 	buf->size = size;
104 	buf->start = binding->pkt_header;
105 	buf->end = buf->start + len;
106 	buf->mctp_hdr_off = buf->start;
107 	buf->next = NULL;
108 
109 	return buf;
110 }
111 
112 void mctp_pktbuf_free(struct mctp_pktbuf *pkt)
113 {
114 	__mctp_free(pkt);
115 }
116 
117 struct mctp_hdr *mctp_pktbuf_hdr(struct mctp_pktbuf *pkt)
118 {
119 	return (void *)pkt->data + pkt->mctp_hdr_off;
120 }
121 
122 void *mctp_pktbuf_data(struct mctp_pktbuf *pkt)
123 {
124 	return (void *)pkt->data + pkt->mctp_hdr_off + sizeof(struct mctp_hdr);
125 }
126 
127 size_t mctp_pktbuf_size(struct mctp_pktbuf *pkt)
128 {
129 	return pkt->end - pkt->start;
130 }
131 
132 void *mctp_pktbuf_alloc_start(struct mctp_pktbuf *pkt, size_t size)
133 {
134 	assert(size <= pkt->start);
135 	pkt->start -= size;
136 	return pkt->data + pkt->start;
137 }
138 
139 void *mctp_pktbuf_alloc_end(struct mctp_pktbuf *pkt, size_t size)
140 {
141 	void *buf;
142 
143 	assert(size <= (pkt->size - pkt->end));
144 	buf = pkt->data + pkt->end;
145 	pkt->end += size;
146 	return buf;
147 }
148 
149 int mctp_pktbuf_push(struct mctp_pktbuf *pkt, void *data, size_t len)
150 {
151 	void *p;
152 
153 	if (pkt->end + len > pkt->size)
154 		return -1;
155 
156 	p = pkt->data + pkt->end;
157 
158 	pkt->end += len;
159 	memcpy(p, data, len);
160 
161 	return 0;
162 }
163 
164 void *mctp_pktbuf_pop(struct mctp_pktbuf *pkt, size_t len)
165 {
166 	if (len > mctp_pktbuf_size(pkt))
167 		return NULL;
168 
169 	pkt->end -= len;
170 	return pkt->data + pkt->end;
171 }
172 
173 /* Message reassembly */
174 static struct mctp_msg_ctx *mctp_msg_ctx_lookup(struct mctp *mctp,
175 		uint8_t src, uint8_t dest, uint8_t tag)
176 {
177 	unsigned int i;
178 
179 	/* @todo: better lookup, if we add support for more outstanding
180 	 * message contexts */
181 	for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) {
182 		struct mctp_msg_ctx *ctx = &mctp->msg_ctxs[i];
183 		if (ctx->src == src && ctx->dest == dest && ctx->tag == tag)
184 			return ctx;
185 	}
186 
187 	return NULL;
188 }
189 
190 static struct mctp_msg_ctx *mctp_msg_ctx_create(struct mctp *mctp,
191 		uint8_t src, uint8_t dest, uint8_t tag)
192 {
193 	struct mctp_msg_ctx *ctx = NULL;
194 	unsigned int i;
195 
196 	for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) {
197 		struct mctp_msg_ctx *tmp = &mctp->msg_ctxs[i];
198 		if (!tmp->src) {
199 			ctx = tmp;
200 			break;
201 		}
202 	}
203 
204 	if (!ctx)
205 		return NULL;
206 
207 	ctx->src = src;
208 	ctx->dest = dest;
209 	ctx->tag = tag;
210 	ctx->buf_size = 0;
211 
212 	return ctx;
213 }
214 
215 static void mctp_msg_ctx_drop(struct mctp_msg_ctx *ctx)
216 {
217 	ctx->src = 0;
218 }
219 
220 static void mctp_msg_ctx_reset(struct mctp_msg_ctx *ctx)
221 {
222 	ctx->buf_size = 0;
223 	ctx->fragment_size = 0;
224 }
225 
226 static int mctp_msg_ctx_add_pkt(struct mctp_msg_ctx *ctx,
227 		struct mctp_pktbuf *pkt, size_t max_size)
228 {
229 	size_t len;
230 
231 	len = mctp_pktbuf_size(pkt) - sizeof(struct mctp_hdr);
232 
233 	if (len + ctx->buf_size < ctx->buf_size) {
234 		return -1;
235 	}
236 
237 	if (ctx->buf_size + len > ctx->buf_alloc_size) {
238 		size_t new_alloc_size;
239 		void *lbuf;
240 
241 		/* @todo: finer-grained allocation */
242 		if (!ctx->buf_alloc_size) {
243 			new_alloc_size = MAX(len, 4096UL);
244 		} else {
245 			new_alloc_size = MAX(ctx->buf_alloc_size * 2, len + ctx->buf_size);
246 		}
247 
248 		/* Don't allow heap to grow beyond a limit */
249 		if (new_alloc_size > max_size)
250 			return -1;
251 
252 
253 		lbuf = __mctp_realloc(ctx->buf, new_alloc_size);
254 		if (lbuf) {
255 			ctx->buf = lbuf;
256 			ctx->buf_alloc_size = new_alloc_size;
257 		} else {
258 			__mctp_free(ctx->buf);
259 			return -1;
260 		}
261 	}
262 
263 	memcpy(ctx->buf + ctx->buf_size, mctp_pktbuf_data(pkt), len);
264 	ctx->buf_size += len;
265 
266 	return 0;
267 }
268 
269 /* Core API functions */
270 struct mctp *mctp_init(void)
271 {
272 	struct mctp *mctp;
273 
274 	mctp = __mctp_alloc(sizeof(*mctp));
275 
276 	if(!mctp)
277 		return NULL;
278 
279 	memset(mctp, 0, sizeof(*mctp));
280 	mctp->max_message_size = MCTP_MAX_MESSAGE_SIZE;
281 
282 	return mctp;
283 }
284 
285 void mctp_set_max_message_size(struct mctp *mctp, size_t message_size)
286 {
287 	mctp->max_message_size = message_size;
288 }
289 
290 void mctp_set_capture_handler(struct mctp *mctp, mctp_capture_fn fn, void *user)
291 {
292 	mctp->capture = fn;
293 	mctp->capture_data = user;
294 }
295 
296 static void mctp_bus_destroy(struct mctp_bus *bus)
297 {
298 	while (bus->tx_queue_head) {
299 		struct mctp_pktbuf *curr = bus->tx_queue_head;
300 
301 		bus->tx_queue_head = curr->next;
302 		mctp_pktbuf_free(curr);
303 	}
304 }
305 
306 void mctp_destroy(struct mctp *mctp)
307 {
308 	size_t i;
309 
310 	/* Cleanup message assembly contexts */
311 	BUILD_ASSERT(ARRAY_SIZE(mctp->msg_ctxs) < SIZE_MAX);
312 	for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) {
313 		struct mctp_msg_ctx *tmp = &mctp->msg_ctxs[i];
314 		if (tmp->buf)
315 			__mctp_free(tmp->buf);
316 	}
317 
318 	while (mctp->n_busses--)
319 		mctp_bus_destroy(&mctp->busses[mctp->n_busses]);
320 
321 	__mctp_free(mctp->busses);
322 	__mctp_free(mctp);
323 }
324 
325 int mctp_set_rx_all(struct mctp *mctp, mctp_rx_fn fn, void *data)
326 {
327 	mctp->message_rx = fn;
328 	mctp->message_rx_data = data;
329 	return 0;
330 }
331 
332 static struct mctp_bus *find_bus_for_eid(struct mctp *mctp,
333 		mctp_eid_t dest __attribute__((unused)))
334 {
335 	/* for now, just use the first bus. For full routing support,
336 	 * we will need a table of neighbours */
337 	return &mctp->busses[0];
338 }
339 
340 int mctp_register_bus(struct mctp *mctp,
341 		struct mctp_binding *binding,
342 		mctp_eid_t eid)
343 {
344 	int rc = 0;
345 
346 	/* todo: multiple busses */
347 	assert(mctp->n_busses == 0);
348 	mctp->n_busses = 1;
349 
350 	mctp->busses = __mctp_alloc(sizeof(struct mctp_bus));
351 	if (!mctp->busses)
352 		return -ENOMEM;
353 
354 	memset(mctp->busses, 0, sizeof(struct mctp_bus));
355 	mctp->busses[0].binding = binding;
356 	mctp->busses[0].eid = eid;
357 	binding->bus = &mctp->busses[0];
358 	binding->mctp = mctp;
359 	mctp->route_policy = ROUTE_ENDPOINT;
360 
361 	if (binding->start) {
362 		rc = binding->start(binding);
363 		if (rc < 0) {
364 			mctp_prerr("Failed to start binding: %d", rc);
365 			binding->bus = NULL;
366 			__mctp_free(mctp->busses);
367 			mctp->busses = NULL;
368 			mctp->n_busses = 0;
369 		}
370 	}
371 
372 	return rc;
373 }
374 
375 int mctp_bridge_busses(struct mctp *mctp,
376 		struct mctp_binding *b1, struct mctp_binding *b2)
377 {
378 	int rc = 0;
379 
380 	assert(mctp->n_busses == 0);
381 	mctp->busses = __mctp_alloc(2 * sizeof(struct mctp_bus));
382 	if (!mctp->busses)
383 		return -ENOMEM;
384 	memset(mctp->busses, 0, 2 * sizeof(struct mctp_bus));
385 	mctp->n_busses = 2;
386 	mctp->busses[0].binding = b1;
387 	b1->bus = &mctp->busses[0];
388 	b1->mctp = mctp;
389 	mctp->busses[1].binding = b2;
390 	b2->bus = &mctp->busses[1];
391 	b2->mctp = mctp;
392 
393 	mctp->route_policy = ROUTE_BRIDGE;
394 
395 	if (b1->start) {
396 		rc = b1->start(b1);
397 		if (rc < 0) {
398 			mctp_prerr("Failed to start bridged bus %s: %d",
399 				   b1->name, rc);
400 			goto done;
401 		}
402 	}
403 
404 	if (b2->start) {
405 		rc = b2->start(b2);
406 		if (rc < 0) {
407 			mctp_prerr("Failed to start bridged bus %s: %d",
408 				   b2->name, rc);
409 			goto done;
410 		}
411 	}
412 
413 done:
414 	return rc;
415 }
416 
417 static inline bool mctp_ctrl_cmd_is_transport(struct mctp_ctrl_msg_hdr *hdr)
418 {
419 	return ((hdr->command_code >= MCTP_CTRL_CMD_FIRST_TRANSPORT) &&
420 		(hdr->command_code <= MCTP_CTRL_CMD_LAST_TRANSPORT));
421 }
422 
423 static bool mctp_ctrl_handle_msg(struct mctp_bus *bus, mctp_eid_t src,
424 				 void *buffer, size_t length)
425 {
426 	struct mctp_ctrl_msg_hdr *msg_hdr = buffer;
427 
428 	/*
429 	 * Control message is received. If a transport control message handler
430 	 * is provided, it will called. If there is no dedicated handler, this
431 	 * function returns false and data can be handled by the generic
432 	 * message handler. The transport control message handler will be
433 	 * provided with messages in the command range 0xF0 - 0xFF.
434 	 */
435 	if (mctp_ctrl_cmd_is_transport(msg_hdr)) {
436 		if (bus->binding->control_rx != NULL) {
437 			/* MCTP bus binding handler */
438 			bus->binding->control_rx(src,
439 						 bus->binding->control_rx_data,
440 						 buffer, length);
441 			return true;
442 		}
443 	}
444 
445 	/*
446 	 * Command was not handled, due to lack of specific callback.
447 	 * It will be passed to regular message_rx handler.
448 	 */
449 	return false;
450 }
451 
452 static inline bool mctp_rx_dest_is_local(struct mctp_bus *bus, mctp_eid_t dest)
453 {
454 	return dest == bus->eid || dest == MCTP_EID_NULL ||
455 	       dest == MCTP_EID_BROADCAST;
456 }
457 
458 static inline bool mctp_ctrl_cmd_is_request(struct mctp_ctrl_msg_hdr *hdr)
459 {
460 	return hdr->ic_msg_type == MCTP_CTRL_HDR_MSG_TYPE &&
461 	       hdr->rq_dgram_inst & MCTP_CTRL_HDR_FLAG_REQUEST;
462 }
463 
464 /*
465  * Receive the complete MCTP message and route it.
466  * Asserts:
467  *     'buf' is not NULL.
468  */
469 static void mctp_rx(struct mctp *mctp, struct mctp_bus *bus, mctp_eid_t src,
470 		    mctp_eid_t dest, void *buf, size_t len)
471 {
472 	assert(buf != NULL);
473 
474 	if (mctp->route_policy == ROUTE_ENDPOINT &&
475 	    mctp_rx_dest_is_local(bus, dest)) {
476 		/* Handle MCTP Control Messages: */
477 		if (len >= sizeof(struct mctp_ctrl_msg_hdr)) {
478 			struct mctp_ctrl_msg_hdr *msg_hdr = buf;
479 
480 			/*
481 			 * Identify if this is a control request message.
482 			 * See DSP0236 v1.3.0 sec. 11.5.
483 			 */
484 			if (mctp_ctrl_cmd_is_request(msg_hdr)) {
485 				bool handled;
486 				handled = mctp_ctrl_handle_msg(bus, src, buf,
487 							       len);
488 				if (handled)
489 					return;
490 			}
491 		}
492 		if (mctp->message_rx)
493 			mctp->message_rx(src, mctp->message_rx_data, buf, len);
494 	}
495 
496 	if (mctp->route_policy == ROUTE_BRIDGE) {
497 		int i;
498 
499 		for (i = 0; i < mctp->n_busses; i++) {
500 			struct mctp_bus *dest_bus = &mctp->busses[i];
501 			if (dest_bus == bus)
502 				continue;
503 
504 			mctp_message_tx_on_bus(dest_bus, src, dest, buf, len);
505 		}
506 
507 	}
508 }
509 
510 void mctp_bus_rx(struct mctp_binding *binding, struct mctp_pktbuf *pkt)
511 {
512 	struct mctp_bus *bus = binding->bus;
513 	struct mctp *mctp = binding->mctp;
514 	uint8_t flags, exp_seq, seq, tag;
515 	struct mctp_msg_ctx *ctx;
516 	struct mctp_hdr *hdr;
517 	size_t len;
518 	void *p;
519 	int rc;
520 
521 	assert(bus);
522 
523 	/* Drop packet if it was smaller than mctp hdr size */
524 	if (mctp_pktbuf_size(pkt) <= sizeof(struct mctp_hdr))
525 		goto out;
526 
527 	if (mctp->capture)
528 		mctp->capture(pkt, mctp->capture_data);
529 
530 	hdr = mctp_pktbuf_hdr(pkt);
531 
532 	/* small optimisation: don't bother reassembly if we're going to
533 	 * drop the packet in mctp_rx anyway */
534 	if (mctp->route_policy == ROUTE_ENDPOINT && hdr->dest != bus->eid)
535 		goto out;
536 
537 	flags = hdr->flags_seq_tag & (MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM);
538 	tag = (hdr->flags_seq_tag >> MCTP_HDR_TAG_SHIFT) & MCTP_HDR_TAG_MASK;
539 	seq = (hdr->flags_seq_tag >> MCTP_HDR_SEQ_SHIFT) & MCTP_HDR_SEQ_MASK;
540 
541 	switch (flags) {
542 	case MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM:
543 		/* single-packet message - send straight up to rx function,
544 		 * no need to create a message context */
545 		len = pkt->end - pkt->mctp_hdr_off - sizeof(struct mctp_hdr);
546 		p = pkt->data + pkt->mctp_hdr_off + sizeof(struct mctp_hdr);
547 		mctp_rx(mctp, bus, hdr->src, hdr->dest, p, len);
548 		break;
549 
550 	case MCTP_HDR_FLAG_SOM:
551 		/* start of a new message - start the new context for
552 		 * future message reception. If an existing context is
553 		 * already present, drop it. */
554 		ctx = mctp_msg_ctx_lookup(mctp, hdr->src, hdr->dest, tag);
555 		if (ctx) {
556 			mctp_msg_ctx_reset(ctx);
557 		} else {
558 			ctx = mctp_msg_ctx_create(mctp,
559 					hdr->src, hdr->dest, tag);
560 			/* If context creation fails due to exhaution of contexts we
561 			* can support, drop the packet */
562 			if (!ctx) {
563 				mctp_prdebug("Context buffers exhausted.");
564 				goto out;
565 			}
566 		}
567 
568 		/* Save the fragment size, subsequent middle fragments
569 		 * should of the same size */
570 		ctx->fragment_size = mctp_pktbuf_size(pkt);
571 
572 		rc = mctp_msg_ctx_add_pkt(ctx, pkt, mctp->max_message_size);
573 		if (rc) {
574 			mctp_msg_ctx_drop(ctx);
575 		} else {
576 			ctx->last_seq = seq;
577 		}
578 
579 		break;
580 
581 	case MCTP_HDR_FLAG_EOM:
582 		ctx = mctp_msg_ctx_lookup(mctp, hdr->src, hdr->dest, tag);
583 		if (!ctx)
584 			goto out;
585 
586 		exp_seq = (ctx->last_seq + 1) % 4;
587 
588 		if (exp_seq != seq) {
589 			mctp_prdebug(
590 				"Sequence number %d does not match expected %d",
591 				seq, exp_seq);
592 			mctp_msg_ctx_drop(ctx);
593 			goto out;
594 		}
595 
596 		len = mctp_pktbuf_size(pkt);
597 
598 		if (len > ctx->fragment_size) {
599 			mctp_prdebug("Unexpected fragment size. Expected" \
600 				" less than %zu, received = %zu",
601 				ctx->fragment_size, len);
602 			mctp_msg_ctx_drop(ctx);
603 			goto out;
604 		}
605 
606 		rc = mctp_msg_ctx_add_pkt(ctx, pkt, mctp->max_message_size);
607 		if (!rc)
608 			mctp_rx(mctp, bus, ctx->src, ctx->dest,
609 					ctx->buf, ctx->buf_size);
610 
611 		mctp_msg_ctx_drop(ctx);
612 		break;
613 
614 	case 0:
615 		/* Neither SOM nor EOM */
616 		ctx = mctp_msg_ctx_lookup(mctp, hdr->src,hdr->dest, tag);
617 		if (!ctx)
618 			goto out;
619 
620 		exp_seq = (ctx->last_seq + 1) % 4;
621 		if (exp_seq != seq) {
622 			mctp_prdebug(
623 				"Sequence number %d does not match expected %d",
624 				seq, exp_seq);
625 			mctp_msg_ctx_drop(ctx);
626 			goto out;
627 		}
628 
629 		len = mctp_pktbuf_size(pkt);
630 
631 		if (len != ctx->fragment_size) {
632 			mctp_prdebug("Unexpected fragment size. Expected = %zu " \
633 				"received = %zu", ctx->fragment_size, len);
634 			mctp_msg_ctx_drop(ctx);
635 			goto out;
636 		}
637 
638 		rc = mctp_msg_ctx_add_pkt(ctx, pkt, mctp->max_message_size);
639 		if (rc) {
640 			mctp_msg_ctx_drop(ctx);
641 			goto out;
642 		}
643 		ctx->last_seq = seq;
644 
645 		break;
646 	}
647 out:
648 	mctp_pktbuf_free(pkt);
649 }
650 
651 static int mctp_packet_tx(struct mctp_bus *bus,
652 		struct mctp_pktbuf *pkt)
653 {
654 	struct mctp *mctp = bus->binding->mctp;
655 
656 	if (bus->state != mctp_bus_state_tx_enabled)
657 		return -1;
658 
659 	if (mctp->capture)
660 		mctp->capture(pkt, mctp->capture_data);
661 
662 	return bus->binding->tx(bus->binding, pkt);
663 }
664 
665 static void mctp_send_tx_queue(struct mctp_bus *bus)
666 {
667 	struct mctp_pktbuf *pkt;
668 
669 	while ((pkt = bus->tx_queue_head)) {
670 		int rc;
671 
672 		rc = mctp_packet_tx(bus, pkt);
673 		if (rc)
674 			break;
675 
676 		bus->tx_queue_head = pkt->next;
677 		mctp_pktbuf_free(pkt);
678 	}
679 
680 	if (!bus->tx_queue_head)
681 		bus->tx_queue_tail = NULL;
682 
683 }
684 
685 void mctp_binding_set_tx_enabled(struct mctp_binding *binding, bool enable)
686 {
687 	struct mctp_bus *bus = binding->bus;
688 
689 	switch(bus->state) {
690 	case mctp_bus_state_constructed:
691 		if (!enable)
692 			return;
693 
694 		if (binding->pkt_size < MCTP_PACKET_SIZE(MCTP_BTU)) {
695 			mctp_prerr("Cannot start %s binding with invalid MTU: %zu",
696 				   binding->name,
697 				   MCTP_BODY_SIZE(binding->pkt_size));
698 			return;
699 		}
700 
701 		bus->state = mctp_bus_state_tx_enabled;
702 		mctp_prinfo("%s binding started", binding->name);
703 		return;
704 	case mctp_bus_state_tx_enabled:
705 		if (enable)
706 			return;
707 
708 		bus->state = mctp_bus_state_tx_disabled;
709 		mctp_prdebug("%s binding Tx disabled", binding->name);
710 		return;
711 	case mctp_bus_state_tx_disabled:
712 		if (!enable)
713 			return;
714 
715 		bus->state = mctp_bus_state_tx_enabled;
716 		mctp_prdebug("%s binding Tx enabled", binding->name);
717 		mctp_send_tx_queue(bus);
718 		return;
719 	}
720 }
721 
722 static int mctp_message_tx_on_bus(struct mctp_bus *bus, mctp_eid_t src,
723 				  mctp_eid_t dest, void *msg, size_t msg_len)
724 {
725 	size_t max_payload_len, payload_len, p;
726 	struct mctp_pktbuf *pkt;
727 	struct mctp_hdr *hdr;
728 	int i;
729 
730 	if (bus->state == mctp_bus_state_constructed)
731 		return -ENXIO;
732 
733 	max_payload_len = MCTP_BODY_SIZE(bus->binding->pkt_size);
734 
735 	{
736 		const bool valid_mtu = max_payload_len >= MCTP_BTU;
737 		assert(valid_mtu);
738 		if (!valid_mtu)
739 			return -EINVAL;
740 	}
741 
742 	mctp_prdebug("%s: Generating packets for transmission of %zu byte message from %hhu to %hhu",
743 		     __func__, msg_len, src, dest);
744 
745 	/* queue up packets, each of max MCTP_MTU size */
746 	for (p = 0, i = 0; p < msg_len; i++) {
747 		payload_len = msg_len - p;
748 		if (payload_len > max_payload_len)
749 			payload_len = max_payload_len;
750 
751 		pkt = mctp_pktbuf_alloc(bus->binding,
752 				payload_len + sizeof(*hdr));
753 		hdr = mctp_pktbuf_hdr(pkt);
754 
755 		/* todo: tags */
756 		hdr->ver = bus->binding->version & 0xf;
757 		hdr->dest = dest;
758 		hdr->src = src;
759 		hdr->flags_seq_tag = MCTP_HDR_FLAG_TO |
760 			(0 << MCTP_HDR_TAG_SHIFT);
761 
762 		if (i == 0)
763 			hdr->flags_seq_tag |= MCTP_HDR_FLAG_SOM;
764 		if (p + payload_len >= msg_len)
765 			hdr->flags_seq_tag |= MCTP_HDR_FLAG_EOM;
766 		hdr->flags_seq_tag |=
767 			(i & MCTP_HDR_SEQ_MASK) << MCTP_HDR_SEQ_SHIFT;
768 
769 		memcpy(mctp_pktbuf_data(pkt), msg + p, payload_len);
770 
771 		/* add to tx queue */
772 		if (bus->tx_queue_tail)
773 			bus->tx_queue_tail->next = pkt;
774 		else
775 			bus->tx_queue_head = pkt;
776 		bus->tx_queue_tail = pkt;
777 
778 		p += payload_len;
779 	}
780 
781 	mctp_prdebug("%s: Enqueued %d packets", __func__, i);
782 
783 	mctp_send_tx_queue(bus);
784 
785 	return 0;
786 }
787 
788 int mctp_message_tx(struct mctp *mctp, mctp_eid_t eid,
789 		void *msg, size_t msg_len)
790 {
791 	struct mctp_bus *bus;
792 
793 	bus = find_bus_for_eid(mctp, eid);
794 	return mctp_message_tx_on_bus(bus, bus->eid, eid, msg, msg_len);
795 }
796