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 #include "compiler.h" 21 #include "core-internal.h" 22 23 #ifndef ARRAY_SIZE 24 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 25 #endif 26 27 static int mctp_message_tx_on_bus(struct mctp_bus *bus, mctp_eid_t src, 28 mctp_eid_t dest, bool tag_owner, 29 uint8_t msg_tag, void *msg, size_t msg_len); 30 static void mctp_dealloc_tag(struct mctp_bus *bus, mctp_eid_t local, 31 mctp_eid_t remote, uint8_t tag); 32 33 struct mctp_pktbuf *mctp_pktbuf_alloc(struct mctp_binding *binding, size_t len) 34 { 35 size_t size = 36 binding->pkt_size + binding->pkt_header + binding->pkt_trailer; 37 if (len > size) { 38 return NULL; 39 } 40 41 void *storage = __mctp_alloc(size + sizeof(struct mctp_pktbuf)); 42 if (!storage) { 43 return NULL; 44 } 45 struct mctp_pktbuf *pkt = mctp_pktbuf_init(binding, storage); 46 pkt->alloc = true; 47 pkt->end = pkt->start + len; 48 return pkt; 49 } 50 51 void mctp_pktbuf_free(struct mctp_pktbuf *pkt) 52 { 53 if (pkt->alloc) { 54 __mctp_free(pkt); 55 } else { 56 mctp_prdebug("pktbuf_free called for non-alloced"); 57 } 58 } 59 60 struct mctp_pktbuf *mctp_pktbuf_init(struct mctp_binding *binding, 61 void *storage) 62 { 63 size_t size = 64 binding->pkt_size + binding->pkt_header + binding->pkt_trailer; 65 struct mctp_pktbuf *buf = (struct mctp_pktbuf *)storage; 66 buf->size = size; 67 buf->start = binding->pkt_header; 68 buf->end = buf->start; 69 buf->mctp_hdr_off = buf->start; 70 buf->alloc = false; 71 72 return buf; 73 } 74 75 struct mctp_hdr *mctp_pktbuf_hdr(struct mctp_pktbuf *pkt) 76 { 77 return (struct mctp_hdr *)(pkt->data + pkt->mctp_hdr_off); 78 } 79 80 void *mctp_pktbuf_data(struct mctp_pktbuf *pkt) 81 { 82 return pkt->data + pkt->mctp_hdr_off + sizeof(struct mctp_hdr); 83 } 84 85 size_t mctp_pktbuf_size(const struct mctp_pktbuf *pkt) 86 { 87 return pkt->end - pkt->start; 88 } 89 90 void *mctp_pktbuf_alloc_start(struct mctp_pktbuf *pkt, size_t size) 91 { 92 assert(size <= pkt->start); 93 pkt->start -= size; 94 return pkt->data + pkt->start; 95 } 96 97 void *mctp_pktbuf_alloc_end(struct mctp_pktbuf *pkt, size_t size) 98 { 99 void *buf; 100 101 assert(size <= (pkt->size - pkt->end)); 102 buf = pkt->data + pkt->end; 103 pkt->end += size; 104 return buf; 105 } 106 107 int mctp_pktbuf_push(struct mctp_pktbuf *pkt, const void *data, size_t len) 108 { 109 void *p; 110 111 if (pkt->end + len > pkt->size) 112 return -1; 113 114 p = pkt->data + pkt->end; 115 116 pkt->end += len; 117 memcpy(p, data, len); 118 119 return 0; 120 } 121 122 void *mctp_pktbuf_pop(struct mctp_pktbuf *pkt, size_t len) 123 { 124 if (len > mctp_pktbuf_size(pkt)) 125 return NULL; 126 127 pkt->end -= len; 128 return pkt->data + pkt->end; 129 } 130 131 /* Allocate a duplicate of the message and copy it */ 132 static void *mctp_msg_dup(const void *msg, size_t msg_len, struct mctp *mctp) 133 { 134 void *copy = __mctp_msg_alloc(msg_len, mctp); 135 if (!copy) { 136 mctp_prdebug("msg dup len %zu failed", msg_len); 137 return NULL; 138 } 139 140 memcpy(copy, msg, msg_len); 141 return copy; 142 } 143 144 /* Message reassembly */ 145 static struct mctp_msg_ctx *mctp_msg_ctx_lookup(struct mctp *mctp, uint8_t src, 146 uint8_t dest, uint8_t tag) 147 { 148 unsigned int i; 149 150 /* @todo: better lookup, if we add support for more outstanding 151 * message contexts */ 152 for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) { 153 struct mctp_msg_ctx *ctx = &mctp->msg_ctxs[i]; 154 if (ctx->buf && ctx->src == src && ctx->dest == dest && 155 ctx->tag == tag) 156 return ctx; 157 } 158 159 return NULL; 160 } 161 162 static struct mctp_msg_ctx *mctp_msg_ctx_create(struct mctp *mctp, uint8_t src, 163 uint8_t dest, uint8_t tag) 164 { 165 struct mctp_msg_ctx *ctx = NULL; 166 unsigned int i; 167 168 for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) { 169 struct mctp_msg_ctx *tmp = &mctp->msg_ctxs[i]; 170 if (!tmp->buf) { 171 ctx = tmp; 172 break; 173 } 174 } 175 176 if (!ctx) 177 return NULL; 178 179 ctx->src = src; 180 ctx->dest = dest; 181 ctx->tag = tag; 182 183 ctx->buf_size = 0; 184 ctx->buf_alloc_size = mctp->max_message_size; 185 ctx->buf = __mctp_msg_alloc(ctx->buf_alloc_size, mctp); 186 if (!ctx->buf) { 187 return NULL; 188 } 189 190 return ctx; 191 } 192 193 static void mctp_msg_ctx_drop(struct mctp_bus *bus, struct mctp_msg_ctx *ctx) 194 { 195 /* Free and mark as unused */ 196 __mctp_msg_free(ctx->buf, bus->mctp); 197 ctx->buf = NULL; 198 } 199 200 static void mctp_msg_ctx_reset(struct mctp_msg_ctx *ctx) 201 { 202 ctx->buf_size = 0; 203 ctx->fragment_size = 0; 204 } 205 206 static int mctp_msg_ctx_add_pkt(struct mctp_msg_ctx *ctx, 207 struct mctp_pktbuf *pkt) 208 { 209 size_t len; 210 211 len = mctp_pktbuf_size(pkt) - sizeof(struct mctp_hdr); 212 213 if (len + ctx->buf_size < ctx->buf_size) { 214 return -1; 215 } 216 217 if (ctx->buf_size + len > ctx->buf_alloc_size) { 218 return -1; 219 } 220 221 memcpy((uint8_t *)ctx->buf + ctx->buf_size, mctp_pktbuf_data(pkt), len); 222 ctx->buf_size += len; 223 224 return 0; 225 } 226 227 /* Core API functions */ 228 struct mctp *mctp_init(void) 229 { 230 struct mctp *mctp; 231 232 mctp = __mctp_alloc(sizeof(*mctp)); 233 234 if (!mctp) 235 return NULL; 236 237 mctp_setup(mctp, sizeof(*mctp)); 238 return mctp; 239 } 240 241 int mctp_setup(struct mctp *mctp, size_t struct_mctp_size) 242 { 243 if (struct_mctp_size < sizeof(struct mctp)) { 244 mctp_prdebug("Mismatching struct mctp"); 245 return -EINVAL; 246 } 247 memset(mctp, 0, sizeof(*mctp)); 248 mctp->max_message_size = MCTP_MAX_MESSAGE_SIZE; 249 return 0; 250 } 251 252 void mctp_set_max_message_size(struct mctp *mctp, size_t message_size) 253 { 254 mctp->max_message_size = message_size; 255 } 256 257 void mctp_set_capture_handler(struct mctp *mctp, mctp_capture_fn fn, void *user) 258 { 259 mctp->capture = fn; 260 mctp->capture_data = user; 261 } 262 263 static void mctp_bus_destroy(struct mctp_bus *bus, struct mctp *mctp) 264 { 265 if (bus->tx_msg) { 266 __mctp_msg_free(bus->tx_msg, mctp); 267 bus->tx_msg = NULL; 268 } 269 } 270 271 void mctp_cleanup(struct mctp *mctp) 272 { 273 size_t i; 274 275 /* Cleanup message assembly contexts */ 276 static_assert(ARRAY_SIZE(mctp->msg_ctxs) < SIZE_MAX, "size"); 277 for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) { 278 struct mctp_msg_ctx *tmp = &mctp->msg_ctxs[i]; 279 if (tmp->buf) 280 __mctp_msg_free(tmp->buf, mctp); 281 } 282 283 while (mctp->n_busses--) 284 mctp_bus_destroy(&mctp->busses[mctp->n_busses], mctp); 285 } 286 287 void mctp_destroy(struct mctp *mctp) 288 { 289 mctp_cleanup(mctp); 290 __mctp_free(mctp); 291 } 292 293 int mctp_set_rx_all(struct mctp *mctp, mctp_rx_fn fn, void *data) 294 { 295 mctp->message_rx = fn; 296 mctp->message_rx_data = data; 297 return 0; 298 } 299 300 static struct mctp_bus *find_bus_for_eid(struct mctp *mctp, mctp_eid_t dest 301 __attribute__((unused))) 302 { 303 if (mctp->n_busses == 0) 304 return NULL; 305 306 /* for now, just use the first bus. For full routing support, 307 * we will need a table of neighbours */ 308 return &mctp->busses[0]; 309 } 310 311 int mctp_register_bus(struct mctp *mctp, struct mctp_binding *binding, 312 mctp_eid_t eid) 313 { 314 int rc = 0; 315 316 /* todo: multiple busses */ 317 static_assert(MCTP_MAX_BUSSES >= 1, "need a bus"); 318 assert(mctp->n_busses == 0); 319 mctp->n_busses = 1; 320 321 assert(binding->tx_storage); 322 323 memset(mctp->busses, 0, sizeof(struct mctp_bus)); 324 mctp->busses[0].mctp = mctp; 325 mctp->busses[0].binding = binding; 326 mctp->busses[0].eid = eid; 327 binding->bus = &mctp->busses[0]; 328 binding->mctp = mctp; 329 mctp->route_policy = ROUTE_ENDPOINT; 330 331 if (binding->start) { 332 rc = binding->start(binding); 333 if (rc < 0) { 334 mctp_prerr("Failed to start binding: %d", rc); 335 binding->bus = NULL; 336 mctp->n_busses = 0; 337 } 338 } 339 340 return rc; 341 } 342 343 void mctp_unregister_bus(struct mctp *mctp, struct mctp_binding *binding) 344 { 345 /* 346 * We only support one bus right now; once the call completes we will 347 * have no more busses 348 */ 349 mctp->n_busses = 0; 350 binding->mctp = NULL; 351 binding->bus = NULL; 352 } 353 354 int mctp_bridge_busses(struct mctp *mctp, struct mctp_binding *b1, 355 struct mctp_binding *b2) 356 { 357 int rc = 0; 358 359 assert(b1->tx_storage); 360 assert(b2->tx_storage); 361 362 assert(mctp->n_busses == 0); 363 assert(MCTP_MAX_BUSSES >= 2); 364 memset(mctp->busses, 0, 2 * sizeof(struct mctp_bus)); 365 mctp->n_busses = 2; 366 mctp->busses[0].binding = b1; 367 b1->bus = &mctp->busses[0]; 368 b1->mctp = mctp; 369 mctp->busses[1].binding = b2; 370 b2->bus = &mctp->busses[1]; 371 b2->mctp = mctp; 372 373 mctp->route_policy = ROUTE_BRIDGE; 374 375 if (b1->start) { 376 rc = b1->start(b1); 377 if (rc < 0) { 378 mctp_prerr("Failed to start bridged bus %s: %d", 379 b1->name, rc); 380 goto done; 381 } 382 } 383 384 if (b2->start) { 385 rc = b2->start(b2); 386 if (rc < 0) { 387 mctp_prerr("Failed to start bridged bus %s: %d", 388 b2->name, rc); 389 goto done; 390 } 391 } 392 393 done: 394 return rc; 395 } 396 397 static inline bool mctp_ctrl_cmd_is_transport(struct mctp_ctrl_msg_hdr *hdr) 398 { 399 #pragma GCC diagnostic push 400 #pragma GCC diagnostic ignored "-Wtype-limits" 401 return ((hdr->command_code >= MCTP_CTRL_CMD_FIRST_TRANSPORT) && 402 (hdr->command_code <= MCTP_CTRL_CMD_LAST_TRANSPORT)); 403 #pragma GCC diagnostic pop 404 } 405 406 static bool mctp_ctrl_handle_msg(struct mctp_bus *bus, mctp_eid_t src, 407 uint8_t msg_tag, bool tag_owner, void *buffer, 408 size_t length) 409 { 410 struct mctp_ctrl_msg_hdr *msg_hdr = buffer; 411 412 /* 413 * Control message is received. If a transport control message handler 414 * is provided, it will called. If there is no dedicated handler, this 415 * function returns false and data can be handled by the generic 416 * message handler. The transport control message handler will be 417 * provided with messages in the command range 0xF0 - 0xFF. 418 */ 419 if (mctp_ctrl_cmd_is_transport(msg_hdr)) { 420 if (bus->binding->control_rx != NULL) { 421 /* MCTP bus binding handler */ 422 bus->binding->control_rx(src, msg_tag, tag_owner, 423 bus->binding->control_rx_data, 424 buffer, length); 425 return true; 426 } 427 } 428 429 /* 430 * Command was not handled, due to lack of specific callback. 431 * It will be passed to regular message_rx handler. 432 */ 433 return false; 434 } 435 436 static inline bool mctp_rx_dest_is_local(struct mctp_bus *bus, mctp_eid_t dest) 437 { 438 return dest == bus->eid || dest == MCTP_EID_NULL || 439 dest == MCTP_EID_BROADCAST; 440 } 441 442 static inline bool mctp_ctrl_cmd_is_request(struct mctp_ctrl_msg_hdr *hdr) 443 { 444 return hdr->ic_msg_type == MCTP_CTRL_HDR_MSG_TYPE && 445 hdr->rq_dgram_inst & MCTP_CTRL_HDR_FLAG_REQUEST; 446 } 447 448 /* 449 * Receive the complete MCTP message and route it. 450 * Asserts: 451 * 'buf' is not NULL. 452 */ 453 static void mctp_rx(struct mctp *mctp, struct mctp_bus *bus, mctp_eid_t src, 454 mctp_eid_t dest, bool tag_owner, uint8_t msg_tag, void *buf, 455 size_t len) 456 { 457 assert(buf != NULL); 458 459 if (mctp->route_policy == ROUTE_ENDPOINT && 460 mctp_rx_dest_is_local(bus, dest)) { 461 /* Note responses to allocated tags */ 462 if (!tag_owner) { 463 mctp_dealloc_tag(bus, dest, src, msg_tag); 464 } 465 466 /* Handle MCTP Control Messages: */ 467 if (len >= sizeof(struct mctp_ctrl_msg_hdr)) { 468 struct mctp_ctrl_msg_hdr *msg_hdr = buf; 469 470 /* 471 * Identify if this is a control request message. 472 * See DSP0236 v1.3.0 sec. 11.5. 473 */ 474 if (mctp_ctrl_cmd_is_request(msg_hdr)) { 475 bool handled; 476 handled = mctp_ctrl_handle_msg( 477 bus, src, msg_tag, tag_owner, buf, len); 478 if (handled) 479 return; 480 } 481 } 482 483 if (mctp->message_rx) 484 mctp->message_rx(src, tag_owner, msg_tag, 485 mctp->message_rx_data, buf, len); 486 } 487 488 if (mctp->route_policy == ROUTE_BRIDGE) { 489 int i; 490 491 for (i = 0; i < mctp->n_busses; i++) { 492 struct mctp_bus *dest_bus = &mctp->busses[i]; 493 if (dest_bus == bus) 494 continue; 495 496 void *copy = mctp_msg_dup(buf, len, mctp); 497 if (!copy) { 498 return; 499 } 500 501 mctp_message_tx_on_bus(dest_bus, src, dest, tag_owner, 502 msg_tag, copy, len); 503 } 504 } 505 } 506 507 void mctp_bus_rx(struct mctp_binding *binding, struct mctp_pktbuf *pkt) 508 { 509 struct mctp_bus *bus = binding->bus; 510 struct mctp *mctp = binding->mctp; 511 uint8_t flags, exp_seq, seq, tag; 512 struct mctp_msg_ctx *ctx; 513 struct mctp_hdr *hdr; 514 bool tag_owner; 515 size_t len; 516 void *p; 517 int rc; 518 519 assert(bus); 520 521 /* Drop packet if it was smaller than mctp hdr size */ 522 if (mctp_pktbuf_size(pkt) < sizeof(struct mctp_hdr)) 523 goto out; 524 525 if (mctp->capture) 526 mctp->capture(pkt, MCTP_MESSAGE_CAPTURE_INCOMING, 527 mctp->capture_data); 528 529 hdr = mctp_pktbuf_hdr(pkt); 530 531 /* small optimisation: don't bother reassembly if we're going to 532 * drop the packet in mctp_rx anyway */ 533 if (mctp->route_policy == ROUTE_ENDPOINT && 534 !mctp_rx_dest_is_local(bus, hdr->dest)) 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 tag_owner = (hdr->flags_seq_tag >> MCTP_HDR_TO_SHIFT) & 541 MCTP_HDR_TO_MASK; 542 543 switch (flags) { 544 case MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM: 545 /* single-packet message - send straight up to rx function, 546 * no need to create a message context */ 547 len = pkt->end - pkt->mctp_hdr_off - sizeof(struct mctp_hdr); 548 p = mctp_msg_dup(pkt->data + pkt->mctp_hdr_off + 549 sizeof(struct mctp_hdr), 550 len, mctp); 551 if (p) { 552 mctp_rx(mctp, bus, hdr->src, hdr->dest, tag_owner, tag, 553 p, len); 554 __mctp_msg_free(p, mctp); 555 } 556 break; 557 558 case MCTP_HDR_FLAG_SOM: 559 /* start of a new message - start the new context for 560 * future message reception. If an existing context is 561 * already present, drop it. */ 562 ctx = mctp_msg_ctx_lookup(mctp, hdr->src, hdr->dest, tag); 563 if (ctx) { 564 mctp_msg_ctx_reset(ctx); 565 } else { 566 ctx = mctp_msg_ctx_create(mctp, hdr->src, hdr->dest, 567 tag); 568 /* If context creation fails due to exhaution of contexts we 569 * can support, drop the packet */ 570 if (!ctx) { 571 mctp_prdebug("Context buffers exhausted."); 572 goto out; 573 } 574 } 575 576 /* Save the fragment size, subsequent middle fragments 577 * should of the same size */ 578 ctx->fragment_size = mctp_pktbuf_size(pkt); 579 580 rc = mctp_msg_ctx_add_pkt(ctx, pkt); 581 if (rc) { 582 mctp_msg_ctx_drop(bus, ctx); 583 } else { 584 ctx->last_seq = seq; 585 } 586 587 break; 588 589 case MCTP_HDR_FLAG_EOM: 590 ctx = mctp_msg_ctx_lookup(mctp, hdr->src, hdr->dest, tag); 591 if (!ctx) 592 goto out; 593 594 exp_seq = (ctx->last_seq + 1) % 4; 595 596 if (exp_seq != seq) { 597 mctp_prdebug( 598 "Sequence number %d does not match expected %d", 599 seq, exp_seq); 600 mctp_msg_ctx_drop(bus, ctx); 601 goto out; 602 } 603 604 len = mctp_pktbuf_size(pkt); 605 606 if (len > ctx->fragment_size) { 607 mctp_prdebug("Unexpected fragment size. Expected" 608 " less than %zu, received = %zu", 609 ctx->fragment_size, len); 610 mctp_msg_ctx_drop(bus, ctx); 611 goto out; 612 } 613 614 rc = mctp_msg_ctx_add_pkt(ctx, pkt); 615 if (!rc) 616 mctp_rx(mctp, bus, ctx->src, ctx->dest, tag_owner, tag, 617 ctx->buf, ctx->buf_size); 618 619 mctp_msg_ctx_drop(bus, ctx); 620 break; 621 622 case 0: 623 /* Neither SOM nor EOM */ 624 ctx = mctp_msg_ctx_lookup(mctp, hdr->src, hdr->dest, tag); 625 if (!ctx) 626 goto out; 627 628 exp_seq = (ctx->last_seq + 1) % 4; 629 if (exp_seq != seq) { 630 mctp_prdebug( 631 "Sequence number %d does not match expected %d", 632 seq, exp_seq); 633 mctp_msg_ctx_drop(bus, ctx); 634 goto out; 635 } 636 637 len = mctp_pktbuf_size(pkt); 638 639 if (len != ctx->fragment_size) { 640 mctp_prdebug("Unexpected fragment size. Expected = %zu " 641 "received = %zu", 642 ctx->fragment_size, len); 643 mctp_msg_ctx_drop(bus, ctx); 644 goto out; 645 } 646 647 rc = mctp_msg_ctx_add_pkt(ctx, pkt); 648 if (rc) { 649 mctp_msg_ctx_drop(bus, ctx); 650 goto out; 651 } 652 ctx->last_seq = seq; 653 654 break; 655 } 656 out: 657 return; 658 } 659 660 static int mctp_packet_tx(struct mctp_bus *bus, struct mctp_pktbuf *pkt) 661 { 662 struct mctp *mctp = bus->binding->mctp; 663 664 if (bus->state != mctp_bus_state_tx_enabled) { 665 mctp_prdebug("tx with bus disabled"); 666 return -1; 667 } 668 669 if (mctp->capture) 670 mctp->capture(pkt, MCTP_MESSAGE_CAPTURE_OUTGOING, 671 mctp->capture_data); 672 673 return bus->binding->tx(bus->binding, pkt); 674 } 675 676 /* Returns a pointer to the binding's tx_storage */ 677 static struct mctp_pktbuf *mctp_next_tx_pkt(struct mctp_bus *bus) 678 { 679 if (!bus->tx_msg) { 680 return NULL; 681 } 682 683 size_t p = bus->tx_msgpos; 684 size_t msg_len = bus->tx_msglen; 685 size_t payload_len = msg_len - p; 686 size_t max_payload_len = MCTP_BODY_SIZE(bus->binding->pkt_size); 687 if (payload_len > max_payload_len) 688 payload_len = max_payload_len; 689 690 struct mctp_pktbuf *pkt = 691 mctp_pktbuf_init(bus->binding, bus->binding->tx_storage); 692 struct mctp_hdr *hdr = mctp_pktbuf_hdr(pkt); 693 694 hdr->ver = bus->binding->version & 0xf; 695 hdr->dest = bus->tx_dest; 696 hdr->src = bus->tx_src; 697 hdr->flags_seq_tag = (bus->tx_to << MCTP_HDR_TO_SHIFT) | 698 (bus->tx_tag << MCTP_HDR_TAG_SHIFT); 699 700 if (p == 0) 701 hdr->flags_seq_tag |= MCTP_HDR_FLAG_SOM; 702 if (p + payload_len >= msg_len) 703 hdr->flags_seq_tag |= MCTP_HDR_FLAG_EOM; 704 hdr->flags_seq_tag |= bus->tx_seq << MCTP_HDR_SEQ_SHIFT; 705 706 memcpy(mctp_pktbuf_data(pkt), (uint8_t *)bus->tx_msg + p, payload_len); 707 pkt->end = pkt->start + sizeof(*hdr) + payload_len; 708 bus->tx_pktlen = payload_len; 709 710 mctp_prdebug( 711 "tx dst %d tag %d payload len %zu seq %d. msg pos %zu len %zu", 712 hdr->dest, bus->tx_tag, payload_len, bus->tx_seq, p, msg_len); 713 714 return pkt; 715 } 716 717 /* Called when a packet has successfully been sent */ 718 static void mctp_tx_complete(struct mctp_bus *bus) 719 { 720 if (!bus->tx_msg) { 721 mctp_prdebug("tx complete no message"); 722 return; 723 } 724 725 bus->tx_seq = (bus->tx_seq + 1) & MCTP_HDR_SEQ_MASK; 726 bus->tx_msgpos += bus->tx_pktlen; 727 728 if (bus->tx_msgpos >= bus->tx_msglen) { 729 __mctp_msg_free(bus->tx_msg, bus->binding->mctp); 730 bus->tx_msg = NULL; 731 } 732 } 733 734 static void mctp_send_tx_queue(struct mctp_bus *bus) 735 { 736 struct mctp_pktbuf *pkt; 737 738 while (bus->tx_msg && bus->state == mctp_bus_state_tx_enabled) { 739 int rc; 740 741 pkt = mctp_next_tx_pkt(bus); 742 743 rc = mctp_packet_tx(bus, pkt); 744 switch (rc) { 745 /* If transmission succeded */ 746 case 0: 747 /* Drop the packet */ 748 mctp_tx_complete(bus); 749 break; 750 751 /* If the binding was busy */ 752 case -EBUSY: 753 /* Keep the packet for next try */ 754 mctp_prdebug("tx EBUSY"); 755 return; 756 757 /* Some other unknown error occurred */ 758 default: 759 /* Drop the packet */ 760 mctp_prdebug("tx drop %d", rc); 761 mctp_tx_complete(bus); 762 return; 763 }; 764 } 765 } 766 767 void mctp_binding_set_tx_enabled(struct mctp_binding *binding, bool enable) 768 { 769 struct mctp_bus *bus = binding->bus; 770 771 switch (bus->state) { 772 case mctp_bus_state_constructed: 773 if (!enable) 774 return; 775 776 if (binding->pkt_size < MCTP_PACKET_SIZE(MCTP_BTU)) { 777 mctp_prerr( 778 "Cannot start %s binding with invalid MTU: %zu", 779 binding->name, 780 MCTP_BODY_SIZE(binding->pkt_size)); 781 return; 782 } 783 784 bus->state = mctp_bus_state_tx_enabled; 785 mctp_prinfo("%s binding started", binding->name); 786 return; 787 case mctp_bus_state_tx_enabled: 788 if (enable) 789 return; 790 791 bus->state = mctp_bus_state_tx_disabled; 792 mctp_prdebug("%s binding Tx disabled", binding->name); 793 return; 794 case mctp_bus_state_tx_disabled: 795 if (!enable) 796 return; 797 798 bus->state = mctp_bus_state_tx_enabled; 799 mctp_prdebug("%s binding Tx enabled", binding->name); 800 mctp_send_tx_queue(bus); 801 return; 802 } 803 } 804 805 static int mctp_message_tx_on_bus(struct mctp_bus *bus, mctp_eid_t src, 806 mctp_eid_t dest, bool tag_owner, 807 uint8_t msg_tag, void *msg, size_t msg_len) 808 { 809 size_t max_payload_len; 810 int rc; 811 812 if (bus->state == mctp_bus_state_constructed) { 813 rc = -ENXIO; 814 goto err; 815 } 816 817 if ((msg_tag & MCTP_HDR_TAG_MASK) != msg_tag) { 818 rc = -EINVAL; 819 goto err; 820 } 821 822 max_payload_len = MCTP_BODY_SIZE(bus->binding->pkt_size); 823 824 { 825 const bool valid_mtu = max_payload_len >= MCTP_BTU; 826 assert(valid_mtu); 827 if (!valid_mtu) { 828 rc = -EINVAL; 829 goto err; 830 } 831 } 832 833 mctp_prdebug( 834 "%s: Generating packets for transmission of %zu byte message from %hhu to %hhu", 835 __func__, msg_len, src, dest); 836 837 if (bus->tx_msg) { 838 mctp_prdebug("Bus busy"); 839 rc = -EBUSY; 840 goto err; 841 } 842 843 /* Take the message to send */ 844 bus->tx_msg = msg; 845 bus->tx_msglen = msg_len; 846 bus->tx_msgpos = 0; 847 /* bus->tx_seq is allowed to continue from previous message */ 848 bus->tx_src = src; 849 bus->tx_dest = dest; 850 bus->tx_to = tag_owner; 851 bus->tx_tag = msg_tag; 852 853 mctp_send_tx_queue(bus); 854 return 0; 855 856 err: 857 __mctp_msg_free(msg, bus->binding->mctp); 858 return rc; 859 } 860 861 int mctp_message_tx_alloced(struct mctp *mctp, mctp_eid_t eid, bool tag_owner, 862 uint8_t msg_tag, void *msg, size_t msg_len) 863 { 864 struct mctp_bus *bus; 865 866 /* TODO: Protect against same tag being used across 867 * different callers */ 868 if ((msg_tag & MCTP_HDR_TAG_MASK) != msg_tag) { 869 mctp_prerr("Incorrect message tag %u passed.", msg_tag); 870 __mctp_msg_free(msg, mctp); 871 return -EINVAL; 872 } 873 874 bus = find_bus_for_eid(mctp, eid); 875 if (!bus) { 876 __mctp_msg_free(msg, mctp); 877 return 0; 878 } 879 880 return mctp_message_tx_on_bus(bus, bus->eid, eid, tag_owner, msg_tag, 881 msg, msg_len); 882 } 883 884 int mctp_message_tx(struct mctp *mctp, mctp_eid_t eid, bool tag_owner, 885 uint8_t msg_tag, const void *msg, size_t msg_len) 886 { 887 void *copy = mctp_msg_dup(msg, msg_len, mctp); 888 if (!copy) { 889 return -ENOMEM; 890 } 891 892 return mctp_message_tx_alloced(mctp, eid, tag_owner, msg_tag, copy, 893 msg_len); 894 } 895 896 static void mctp_dealloc_tag(struct mctp_bus *bus, mctp_eid_t local, 897 mctp_eid_t remote, uint8_t tag) 898 { 899 struct mctp *mctp = bus->binding->mctp; 900 if (local == 0 || remote == 0) { 901 return; 902 } 903 904 for (size_t i = 0; i < ARRAY_SIZE(mctp->req_tags); i++) { 905 struct mctp_req_tag *r = &mctp->req_tags[i]; 906 if (r->local == local && r->remote == remote && r->tag == tag) { 907 r->local = 0; 908 r->remote = 0; 909 r->tag = 0; 910 return; 911 } 912 } 913 } 914 915 static int mctp_alloc_tag(struct mctp *mctp, mctp_eid_t local, 916 mctp_eid_t remote, uint8_t *ret_tag) 917 { 918 assert(local != 0); 919 assert(remote != 0); 920 921 uint8_t used = 0; 922 struct mctp_req_tag *spare = NULL; 923 /* Find which tags and slots are used/spare */ 924 for (size_t i = 0; i < ARRAY_SIZE(mctp->req_tags); i++) { 925 struct mctp_req_tag *r = &mctp->req_tags[i]; 926 if (r->local == 0) { 927 spare = r; 928 } else { 929 // TODO: check timeouts 930 if (r->local == local && r->remote == remote) { 931 used |= 1 << r->tag; 932 } 933 } 934 } 935 936 if (spare == NULL) { 937 // All req_tag slots are in-use 938 return -EBUSY; 939 } 940 941 for (uint8_t t = 0; t < 8; t++) { 942 uint8_t tag = (t + mctp->tag_round_robin) % 8; 943 if ((used & 1 << tag) == 0) { 944 spare->local = local; 945 spare->remote = remote; 946 spare->tag = tag; 947 *ret_tag = tag; 948 mctp->tag_round_robin = (tag + 1) % 8; 949 return 0; 950 } 951 } 952 953 // All 8 tags are used for this src/dest pair 954 return -EBUSY; 955 } 956 957 int mctp_message_tx_request(struct mctp *mctp, mctp_eid_t eid, void *msg, 958 size_t msg_len, uint8_t *ret_alloc_msg_tag) 959 { 960 int rc; 961 struct mctp_bus *bus; 962 963 bus = find_bus_for_eid(mctp, eid); 964 if (!bus) { 965 __mctp_msg_free(msg, mctp); 966 return 0; 967 } 968 969 uint8_t alloc_tag; 970 rc = mctp_alloc_tag(mctp, bus->eid, eid, &alloc_tag); 971 if (rc) { 972 mctp_prdebug("Failed allocating tag"); 973 __mctp_msg_free(msg, mctp); 974 return rc; 975 } 976 977 if (ret_alloc_msg_tag) { 978 *ret_alloc_msg_tag = alloc_tag; 979 } 980 981 return mctp_message_tx_alloced(mctp, eid, true, alloc_tag, msg, 982 msg_len); 983 } 984 985 bool mctp_is_tx_ready(struct mctp *mctp, mctp_eid_t eid) 986 { 987 struct mctp_bus *bus; 988 989 bus = find_bus_for_eid(mctp, eid); 990 if (!bus) { 991 return true; 992 } 993 return bus->tx_msg == NULL; 994 } 995 996 void *mctp_get_alloc_ctx(struct mctp *mctp) 997 { 998 return mctp->alloc_ctx; 999 } 1000 1001 void mctp_set_alloc_ctx(struct mctp *mctp, void *ctx) 1002 { 1003 mctp->alloc_ctx = ctx; 1004 } 1005