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