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