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