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