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