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 }; 49 50 struct mctp { 51 int n_busses; 52 struct mctp_bus *busses; 53 54 /* Message RX callback */ 55 mctp_rx_fn message_rx; 56 void *message_rx_data; 57 58 /* Message reassembly. 59 * @todo: flexible context count 60 */ 61 struct mctp_msg_ctx msg_ctxs[16]; 62 63 enum { 64 ROUTE_ENDPOINT, 65 ROUTE_BRIDGE, 66 } route_policy; 67 size_t max_message_size; 68 }; 69 70 #ifndef BUILD_ASSERT 71 #define BUILD_ASSERT(x) \ 72 do { (void)sizeof(char[0-(!(x))]); } while (0) 73 #endif 74 75 #ifndef ARRAY_SIZE 76 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 77 #endif 78 79 /* 64kb should be sufficient for a single message. Applications 80 * requiring higher sizes can override by setting max_message_size.*/ 81 #ifndef MCTP_MAX_MESSAGE_SIZE 82 #define MCTP_MAX_MESSAGE_SIZE 65536 83 #endif 84 85 static int mctp_message_tx_on_bus(struct mctp_bus *bus, mctp_eid_t src, 86 mctp_eid_t dest, void *msg, size_t msg_len); 87 88 struct mctp_pktbuf *mctp_pktbuf_alloc(struct mctp_binding *binding, size_t len) 89 { 90 struct mctp_pktbuf *buf; 91 size_t size; 92 93 size = binding->pkt_size + binding->pkt_header + binding->pkt_trailer; 94 95 /* todo: pools */ 96 buf = __mctp_alloc(sizeof(*buf) + size); 97 98 buf->size = size; 99 buf->start = binding->pkt_header; 100 buf->end = buf->start + len; 101 buf->mctp_hdr_off = buf->start; 102 buf->next = NULL; 103 104 return buf; 105 } 106 107 void mctp_pktbuf_free(struct mctp_pktbuf *pkt) 108 { 109 __mctp_free(pkt); 110 } 111 112 struct mctp_hdr *mctp_pktbuf_hdr(struct mctp_pktbuf *pkt) 113 { 114 return (void *)pkt->data + pkt->mctp_hdr_off; 115 } 116 117 void *mctp_pktbuf_data(struct mctp_pktbuf *pkt) 118 { 119 return (void *)pkt->data + pkt->mctp_hdr_off + sizeof(struct mctp_hdr); 120 } 121 122 size_t mctp_pktbuf_size(struct mctp_pktbuf *pkt) 123 { 124 return pkt->end - pkt->start; 125 } 126 127 void *mctp_pktbuf_alloc_start(struct mctp_pktbuf *pkt, size_t size) 128 { 129 assert(size <= pkt->start); 130 pkt->start -= size; 131 return pkt->data + pkt->start; 132 } 133 134 void *mctp_pktbuf_alloc_end(struct mctp_pktbuf *pkt, size_t size) 135 { 136 void *buf; 137 138 assert(size <= (pkt->size - pkt->end)); 139 buf = pkt->data + pkt->end; 140 pkt->end += size; 141 return buf; 142 } 143 144 int mctp_pktbuf_push(struct mctp_pktbuf *pkt, void *data, size_t len) 145 { 146 void *p; 147 148 if (pkt->end + len > pkt->size) 149 return -1; 150 151 p = pkt->data + pkt->end; 152 153 pkt->end += len; 154 memcpy(p, data, len); 155 156 return 0; 157 } 158 159 void *mctp_pktbuf_pop(struct mctp_pktbuf *pkt, size_t len) 160 { 161 if (len > mctp_pktbuf_size(pkt)) 162 return NULL; 163 164 pkt->end -= len; 165 return pkt->data + pkt->end; 166 } 167 168 /* Message reassembly */ 169 static struct mctp_msg_ctx *mctp_msg_ctx_lookup(struct mctp *mctp, 170 uint8_t src, uint8_t dest, uint8_t tag) 171 { 172 unsigned int i; 173 174 /* @todo: better lookup, if we add support for more outstanding 175 * message contexts */ 176 for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) { 177 struct mctp_msg_ctx *ctx = &mctp->msg_ctxs[i]; 178 if (ctx->src == src && ctx->dest == dest && ctx->tag == tag) 179 return ctx; 180 } 181 182 return NULL; 183 } 184 185 static struct mctp_msg_ctx *mctp_msg_ctx_create(struct mctp *mctp, 186 uint8_t src, uint8_t dest, uint8_t tag) 187 { 188 struct mctp_msg_ctx *ctx = NULL; 189 unsigned int i; 190 191 for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) { 192 struct mctp_msg_ctx *tmp = &mctp->msg_ctxs[i]; 193 if (!tmp->src) { 194 ctx = tmp; 195 break; 196 } 197 } 198 199 if (!ctx) 200 return NULL; 201 202 ctx->src = src; 203 ctx->dest = dest; 204 ctx->tag = tag; 205 ctx->buf_size = 0; 206 207 return ctx; 208 } 209 210 static void mctp_msg_ctx_drop(struct mctp_msg_ctx *ctx) 211 { 212 ctx->src = 0; 213 } 214 215 static void mctp_msg_ctx_reset(struct mctp_msg_ctx *ctx) 216 { 217 ctx->buf_size = 0; 218 } 219 220 static int mctp_msg_ctx_add_pkt(struct mctp_msg_ctx *ctx, 221 struct mctp_pktbuf *pkt, size_t max_size) 222 { 223 size_t len; 224 225 len = mctp_pktbuf_size(pkt) - sizeof(struct mctp_hdr); 226 227 if (ctx->buf_size + len > ctx->buf_alloc_size) { 228 size_t new_alloc_size; 229 void *lbuf; 230 231 /* @todo: finer-grained allocation */ 232 if (!ctx->buf_alloc_size) { 233 new_alloc_size = MAX(len, 4096UL); 234 } else { 235 new_alloc_size = ctx->buf_alloc_size * 2; 236 } 237 238 /* Don't allow heap to grow beyond a limit */ 239 if (new_alloc_size > max_size) 240 return -1; 241 242 243 lbuf = __mctp_realloc(ctx->buf, new_alloc_size); 244 if (lbuf) { 245 ctx->buf = lbuf; 246 ctx->buf_alloc_size = new_alloc_size; 247 } else { 248 __mctp_free(ctx->buf); 249 return -1; 250 } 251 } 252 253 memcpy(ctx->buf + ctx->buf_size, mctp_pktbuf_data(pkt), len); 254 ctx->buf_size += len; 255 256 return 0; 257 } 258 259 /* Core API functions */ 260 struct mctp *mctp_init(void) 261 { 262 struct mctp *mctp; 263 264 mctp = __mctp_alloc(sizeof(*mctp)); 265 266 if(!mctp) 267 return NULL; 268 269 memset(mctp, 0, sizeof(*mctp)); 270 mctp->max_message_size = MCTP_MAX_MESSAGE_SIZE; 271 272 return mctp; 273 } 274 275 void mctp_set_max_message_size(struct mctp *mctp, size_t message_size) 276 { 277 mctp->max_message_size = message_size; 278 } 279 280 static void mctp_bus_destroy(struct mctp_bus *bus) 281 { 282 while (bus->tx_queue_head) { 283 struct mctp_pktbuf *curr = bus->tx_queue_head; 284 285 bus->tx_queue_head = curr->next; 286 mctp_pktbuf_free(curr); 287 } 288 } 289 290 void mctp_destroy(struct mctp *mctp) 291 { 292 size_t i; 293 294 /* Cleanup message assembly contexts */ 295 BUILD_ASSERT(ARRAY_SIZE(mctp->msg_ctxs) < SIZE_MAX); 296 for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) { 297 struct mctp_msg_ctx *tmp = &mctp->msg_ctxs[i]; 298 if (tmp->buf) 299 __mctp_free(tmp->buf); 300 } 301 302 while (mctp->n_busses--) 303 mctp_bus_destroy(&mctp->busses[mctp->n_busses]); 304 305 __mctp_free(mctp->busses); 306 __mctp_free(mctp); 307 } 308 309 int mctp_set_rx_all(struct mctp *mctp, mctp_rx_fn fn, void *data) 310 { 311 mctp->message_rx = fn; 312 mctp->message_rx_data = data; 313 return 0; 314 } 315 316 static struct mctp_bus *find_bus_for_eid(struct mctp *mctp, 317 mctp_eid_t dest __attribute__((unused))) 318 { 319 /* for now, just use the first bus. For full routing support, 320 * we will need a table of neighbours */ 321 return &mctp->busses[0]; 322 } 323 324 int mctp_register_bus(struct mctp *mctp, 325 struct mctp_binding *binding, 326 mctp_eid_t eid) 327 { 328 int rc = 0; 329 330 /* todo: multiple busses */ 331 assert(mctp->n_busses == 0); 332 mctp->n_busses = 1; 333 334 mctp->busses = __mctp_alloc(sizeof(struct mctp_bus)); 335 if (!mctp->busses) 336 return -ENOMEM; 337 338 memset(mctp->busses, 0, sizeof(struct mctp_bus)); 339 mctp->busses[0].binding = binding; 340 mctp->busses[0].eid = eid; 341 binding->bus = &mctp->busses[0]; 342 binding->mctp = mctp; 343 mctp->route_policy = ROUTE_ENDPOINT; 344 345 if (binding->start) { 346 rc = binding->start(binding); 347 if (rc < 0) { 348 mctp_prerr("Failed to start binding: %d", rc); 349 binding->bus = NULL; 350 __mctp_free(mctp->busses); 351 mctp->busses = NULL; 352 mctp->n_busses = 0; 353 } 354 } 355 356 return rc; 357 } 358 359 int mctp_bridge_busses(struct mctp *mctp, 360 struct mctp_binding *b1, struct mctp_binding *b2) 361 { 362 int rc = 0; 363 364 assert(mctp->n_busses == 0); 365 mctp->busses = __mctp_alloc(2 * sizeof(struct mctp_bus)); 366 if (!mctp->busses) 367 return -ENOMEM; 368 memset(mctp->busses, 0, 2 * sizeof(struct mctp_bus)); 369 mctp->n_busses = 2; 370 mctp->busses[0].binding = b1; 371 b1->bus = &mctp->busses[0]; 372 b1->mctp = mctp; 373 mctp->busses[1].binding = b2; 374 b2->bus = &mctp->busses[1]; 375 b2->mctp = mctp; 376 377 mctp->route_policy = ROUTE_BRIDGE; 378 379 if (b1->start) { 380 rc = b1->start(b1); 381 if (rc < 0) { 382 mctp_prerr("Failed to start bridged bus %s: %d", 383 b1->name, rc); 384 goto done; 385 } 386 } 387 388 if (b2->start) { 389 rc = b2->start(b2); 390 if (rc < 0) { 391 mctp_prerr("Failed to start bridged bus %s: %d", 392 b2->name, rc); 393 goto done; 394 } 395 } 396 397 done: 398 return rc; 399 } 400 401 static inline bool mctp_ctrl_cmd_is_transport(struct mctp_ctrl_msg_hdr *hdr) 402 { 403 return ((hdr->command_code >= MCTP_CTRL_CMD_FIRST_TRANSPORT) && 404 (hdr->command_code <= MCTP_CTRL_CMD_LAST_TRANSPORT)); 405 } 406 407 static bool mctp_ctrl_handle_msg(struct mctp_bus *bus, mctp_eid_t src, 408 void *buffer, 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, 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, void *buf, size_t len) 455 { 456 assert(buf != NULL); 457 458 if (mctp->route_policy == ROUTE_ENDPOINT && 459 mctp_rx_dest_is_local(bus, dest)) { 460 /* Handle MCTP Control Messages: */ 461 if (len >= sizeof(struct mctp_ctrl_msg_hdr)) { 462 struct mctp_ctrl_msg_hdr *msg_hdr = buf; 463 464 /* 465 * Identify if this is a control request message. 466 * See DSP0236 v1.3.0 sec. 11.5. 467 */ 468 if (mctp_ctrl_cmd_is_request(msg_hdr)) { 469 bool handled; 470 handled = mctp_ctrl_handle_msg(bus, src, buf, 471 len); 472 if (handled) 473 return; 474 } 475 } 476 if (mctp->message_rx) 477 mctp->message_rx(src, mctp->message_rx_data, buf, len); 478 } 479 480 if (mctp->route_policy == ROUTE_BRIDGE) { 481 int i; 482 483 for (i = 0; i < mctp->n_busses; i++) { 484 struct mctp_bus *dest_bus = &mctp->busses[i]; 485 if (dest_bus == bus) 486 continue; 487 488 mctp_message_tx_on_bus(dest_bus, src, dest, buf, len); 489 } 490 491 } 492 } 493 494 void mctp_bus_rx(struct mctp_binding *binding, struct mctp_pktbuf *pkt) 495 { 496 struct mctp_bus *bus = binding->bus; 497 struct mctp *mctp = binding->mctp; 498 uint8_t flags, exp_seq, seq, tag; 499 struct mctp_msg_ctx *ctx; 500 struct mctp_hdr *hdr; 501 size_t len; 502 void *p; 503 int rc; 504 505 assert(bus); 506 507 /* Drop packet if it was smaller than mctp hdr size */ 508 if (mctp_pktbuf_size(pkt) <= sizeof(struct mctp_hdr)) 509 goto out; 510 511 hdr = mctp_pktbuf_hdr(pkt); 512 513 /* small optimisation: don't bother reassembly if we're going to 514 * drop the packet in mctp_rx anyway */ 515 if (mctp->route_policy == ROUTE_ENDPOINT && hdr->dest != bus->eid) 516 goto out; 517 518 flags = hdr->flags_seq_tag & (MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM); 519 tag = (hdr->flags_seq_tag >> MCTP_HDR_TAG_SHIFT) & MCTP_HDR_TAG_MASK; 520 seq = (hdr->flags_seq_tag >> MCTP_HDR_SEQ_SHIFT) & MCTP_HDR_SEQ_MASK; 521 522 switch (flags) { 523 case MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM: 524 /* single-packet message - send straight up to rx function, 525 * no need to create a message context */ 526 len = pkt->end - pkt->mctp_hdr_off - sizeof(struct mctp_hdr); 527 p = pkt->data + pkt->mctp_hdr_off + sizeof(struct mctp_hdr); 528 mctp_rx(mctp, bus, hdr->src, hdr->dest, p, len); 529 break; 530 531 case MCTP_HDR_FLAG_SOM: 532 /* start of a new message - start the new context for 533 * future message reception. If an existing context is 534 * already present, drop it. */ 535 ctx = mctp_msg_ctx_lookup(mctp, hdr->src, hdr->dest, tag); 536 if (ctx) { 537 mctp_msg_ctx_reset(ctx); 538 } else { 539 ctx = mctp_msg_ctx_create(mctp, 540 hdr->src, hdr->dest, tag); 541 } 542 543 rc = mctp_msg_ctx_add_pkt(ctx, pkt, mctp->max_message_size); 544 if (rc) { 545 mctp_msg_ctx_drop(ctx); 546 } else { 547 ctx->last_seq = seq; 548 } 549 550 break; 551 552 case MCTP_HDR_FLAG_EOM: 553 ctx = mctp_msg_ctx_lookup(mctp, hdr->src, hdr->dest, tag); 554 if (!ctx) 555 goto out; 556 557 exp_seq = (ctx->last_seq + 1) % 4; 558 559 if (exp_seq != seq) { 560 mctp_prdebug( 561 "Sequence number %d does not match expected %d", 562 seq, exp_seq); 563 mctp_msg_ctx_drop(ctx); 564 goto out; 565 } 566 567 rc = mctp_msg_ctx_add_pkt(ctx, pkt, mctp->max_message_size); 568 if (!rc) 569 mctp_rx(mctp, bus, ctx->src, ctx->dest, 570 ctx->buf, ctx->buf_size); 571 572 mctp_msg_ctx_drop(ctx); 573 break; 574 575 case 0: 576 /* Neither SOM nor EOM */ 577 ctx = mctp_msg_ctx_lookup(mctp, hdr->src,hdr->dest, tag); 578 if (!ctx) 579 goto out; 580 581 exp_seq = (ctx->last_seq + 1) % 4; 582 if (exp_seq != seq) { 583 mctp_prdebug( 584 "Sequence number %d does not match expected %d", 585 seq, exp_seq); 586 mctp_msg_ctx_drop(ctx); 587 goto out; 588 } 589 590 rc = mctp_msg_ctx_add_pkt(ctx, pkt, mctp->max_message_size); 591 if (rc) { 592 mctp_msg_ctx_drop(ctx); 593 goto out; 594 } 595 ctx->last_seq = seq; 596 597 break; 598 } 599 out: 600 mctp_pktbuf_free(pkt); 601 } 602 603 static int mctp_packet_tx(struct mctp_bus *bus, 604 struct mctp_pktbuf *pkt) 605 { 606 if (bus->state != mctp_bus_state_tx_enabled) 607 return -1; 608 609 return bus->binding->tx(bus->binding, pkt); 610 } 611 612 static void mctp_send_tx_queue(struct mctp_bus *bus) 613 { 614 struct mctp_pktbuf *pkt; 615 616 while ((pkt = bus->tx_queue_head)) { 617 int rc; 618 619 rc = mctp_packet_tx(bus, pkt); 620 if (rc) 621 break; 622 623 bus->tx_queue_head = pkt->next; 624 mctp_pktbuf_free(pkt); 625 } 626 627 if (!bus->tx_queue_head) 628 bus->tx_queue_tail = NULL; 629 630 } 631 632 void mctp_binding_set_tx_enabled(struct mctp_binding *binding, bool enable) 633 { 634 struct mctp_bus *bus = binding->bus; 635 636 switch(bus->state) { 637 case mctp_bus_state_constructed: 638 if (!enable) 639 return; 640 641 if (binding->pkt_size < MCTP_PACKET_SIZE(MCTP_BTU)) { 642 mctp_prerr("Cannot start %s binding with invalid MTU: %zu", 643 binding->name, 644 MCTP_BODY_SIZE(binding->pkt_size)); 645 return; 646 } 647 648 bus->state = mctp_bus_state_tx_enabled; 649 mctp_prinfo("%s binding started", binding->name); 650 return; 651 case mctp_bus_state_tx_enabled: 652 if (enable) 653 return; 654 655 bus->state = mctp_bus_state_tx_disabled; 656 mctp_prdebug("%s binding Tx disabled", binding->name); 657 return; 658 case mctp_bus_state_tx_disabled: 659 if (!enable) 660 return; 661 662 bus->state = mctp_bus_state_tx_enabled; 663 mctp_prdebug("%s binding Tx enabled", binding->name); 664 mctp_send_tx_queue(bus); 665 return; 666 } 667 } 668 669 static int mctp_message_tx_on_bus(struct mctp_bus *bus, mctp_eid_t src, 670 mctp_eid_t dest, void *msg, size_t msg_len) 671 { 672 size_t max_payload_len, payload_len, p; 673 struct mctp_pktbuf *pkt; 674 struct mctp_hdr *hdr; 675 int i; 676 677 if (bus->state == mctp_bus_state_constructed) 678 return -ENXIO; 679 680 max_payload_len = MCTP_BODY_SIZE(bus->binding->pkt_size); 681 682 { 683 const bool valid_mtu = max_payload_len >= MCTP_BTU; 684 assert(valid_mtu); 685 if (!valid_mtu) 686 return -EINVAL; 687 } 688 689 mctp_prdebug("%s: Generating packets for transmission of %zu byte message from %hhu to %hhu", 690 __func__, msg_len, src, dest); 691 692 /* queue up packets, each of max MCTP_MTU size */ 693 for (p = 0, i = 0; p < msg_len; i++) { 694 payload_len = msg_len - p; 695 if (payload_len > max_payload_len) 696 payload_len = max_payload_len; 697 698 pkt = mctp_pktbuf_alloc(bus->binding, 699 payload_len + sizeof(*hdr)); 700 hdr = mctp_pktbuf_hdr(pkt); 701 702 /* todo: tags */ 703 hdr->ver = bus->binding->version & 0xf; 704 hdr->dest = dest; 705 hdr->src = src; 706 hdr->flags_seq_tag = MCTP_HDR_FLAG_TO | 707 (0 << MCTP_HDR_TAG_SHIFT); 708 709 if (i == 0) 710 hdr->flags_seq_tag |= MCTP_HDR_FLAG_SOM; 711 if (p + payload_len >= msg_len) 712 hdr->flags_seq_tag |= MCTP_HDR_FLAG_EOM; 713 hdr->flags_seq_tag |= 714 (i & MCTP_HDR_SEQ_MASK) << MCTP_HDR_SEQ_SHIFT; 715 716 memcpy(mctp_pktbuf_data(pkt), msg + p, payload_len); 717 718 /* add to tx queue */ 719 if (bus->tx_queue_tail) 720 bus->tx_queue_tail->next = pkt; 721 else 722 bus->tx_queue_head = pkt; 723 bus->tx_queue_tail = pkt; 724 725 p += payload_len; 726 } 727 728 mctp_prdebug("%s: Enqueued %d packets", __func__, i); 729 730 mctp_send_tx_queue(bus); 731 732 return 0; 733 } 734 735 int mctp_message_tx(struct mctp *mctp, mctp_eid_t eid, 736 void *msg, size_t msg_len) 737 { 738 struct mctp_bus *bus; 739 740 bus = find_bus_for_eid(mctp, eid); 741 return mctp_message_tx_on_bus(bus, bus->eid, eid, msg, msg_len); 742 } 743