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