1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 3 #define _GNU_SOURCE 4 5 #ifdef HAVE_CONFIG_H 6 #include "config.h" 7 #endif 8 9 #define SD_LISTEN_FDS_START 3 10 11 #include "compiler.h" 12 #include "libmctp.h" 13 #include "libmctp-serial.h" 14 #include "libmctp-astlpc.h" 15 #include "utils/mctp-capture.h" 16 17 #include <assert.h> 18 #include <err.h> 19 #include <errno.h> 20 #include <getopt.h> 21 #include <limits.h> 22 #include <poll.h> 23 #include <signal.h> 24 #include <stdbool.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <unistd.h> 29 30 #include <sys/signalfd.h> 31 #include <sys/socket.h> 32 #include <sys/un.h> 33 34 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 35 36 #if HAVE_SYSTEMD_SD_DAEMON_H 37 #include <systemd/sd-daemon.h> 38 #else 39 static inline int sd_listen_fds(int i __unused) 40 { 41 return -1; 42 } 43 #endif 44 45 static const mctp_eid_t local_eid_default = 8; 46 static char sockname[] = "\0mctp-mux"; 47 48 struct binding { 49 const char *name; 50 int (*init)(struct mctp *mctp, struct binding *binding, mctp_eid_t eid, 51 int n_params, char *const *params); 52 void (*destroy)(struct mctp *mctp, struct binding *binding); 53 int (*init_pollfd)(struct binding *binding, struct pollfd *pollfd); 54 int (*process)(struct binding *binding); 55 void *data; 56 }; 57 58 struct client { 59 bool active; 60 int sock; 61 uint8_t type; 62 }; 63 64 struct ctx { 65 struct mctp *mctp; 66 struct binding *binding; 67 bool verbose; 68 int local_eid; 69 uint8_t *buf; 70 size_t buf_size; 71 72 int sock; 73 struct pollfd *pollfds; 74 75 struct client *clients; 76 int n_clients; 77 78 struct { 79 struct capture binding; 80 struct capture socket; 81 } pcap; 82 }; 83 84 static void tx_message(struct ctx *ctx, mctp_eid_t eid, void *msg, size_t len) 85 { 86 int rc; 87 88 rc = mctp_message_tx(ctx->mctp, eid, MCTP_MESSAGE_TO_SRC, 0, msg, len); 89 if (rc) 90 warnx("Failed to send message: %d", rc); 91 } 92 93 static void client_remove_inactive(struct ctx *ctx) 94 { 95 int i; 96 97 for (i = 0; i < ctx->n_clients; i++) { 98 struct client *client = &ctx->clients[i]; 99 if (client->active) 100 continue; 101 close(client->sock); 102 103 ctx->n_clients--; 104 memmove(&ctx->clients[i], &ctx->clients[i + 1], 105 (ctx->n_clients - i) * sizeof(*ctx->clients)); 106 ctx->clients = realloc(ctx->clients, 107 ctx->n_clients * sizeof(*ctx->clients)); 108 } 109 } 110 111 static void rx_message(uint8_t eid, bool tag_owner __unused, 112 uint8_t msg_tag __unused, void *data, void *msg, 113 size_t len) 114 { 115 struct ctx *ctx = data; 116 struct iovec iov[2]; 117 struct msghdr msghdr; 118 bool removed; 119 uint8_t type; 120 int i, rc; 121 122 if (len < 2) 123 return; 124 125 type = *(uint8_t *)msg; 126 127 if (ctx->verbose) 128 fprintf(stderr, "MCTP message received: len %zd, type %d\n", 129 len, type); 130 131 memset(&msghdr, 0, sizeof(msghdr)); 132 msghdr.msg_iov = iov; 133 msghdr.msg_iovlen = 2; 134 iov[0].iov_base = &eid; 135 iov[0].iov_len = 1; 136 iov[1].iov_base = msg; 137 iov[1].iov_len = len; 138 139 for (i = 0; i < ctx->n_clients; i++) { 140 struct client *client = &ctx->clients[i]; 141 142 if (client->type != type) 143 continue; 144 145 if (ctx->verbose) 146 fprintf(stderr, " forwarding to client %d\n", i); 147 148 rc = sendmsg(client->sock, &msghdr, 0); 149 if (rc != (ssize_t)(len + 1)) { 150 client->active = false; 151 removed = true; 152 } 153 } 154 155 if (removed) 156 client_remove_inactive(ctx); 157 } 158 159 static int binding_null_init(struct mctp *mctp __unused, 160 struct binding *binding __unused, 161 mctp_eid_t eid __unused, int n_params, 162 char *const *params __unused) 163 { 164 if (n_params != 0) { 165 warnx("null binding doesn't accept parameters"); 166 return -1; 167 } 168 return 0; 169 } 170 171 static int binding_serial_init(struct mctp *mctp, struct binding *binding, 172 mctp_eid_t eid, int n_params, 173 char *const *params) 174 { 175 struct mctp_binding_serial *serial; 176 const char *path; 177 int rc; 178 179 if (n_params != 1) { 180 warnx("serial binding requires device param"); 181 return -1; 182 } 183 184 path = params[0]; 185 186 serial = mctp_serial_init(); 187 assert(serial); 188 189 rc = mctp_serial_open_path(serial, path); 190 if (rc) 191 return -1; 192 193 mctp_register_bus(mctp, mctp_binding_serial_core(serial), eid); 194 195 binding->data = serial; 196 197 return 0; 198 } 199 200 static int binding_serial_init_pollfd(struct binding *binding, 201 struct pollfd *pollfd) 202 { 203 return mctp_serial_init_pollfd(binding->data, pollfd); 204 } 205 206 static int binding_serial_process(struct binding *binding) 207 { 208 return mctp_serial_read(binding->data); 209 } 210 211 static int binding_astlpc_init(struct mctp *mctp, struct binding *binding, 212 mctp_eid_t eid, int n_params, 213 char *const *params __attribute__((unused))) 214 { 215 struct mctp_binding_astlpc *astlpc; 216 const char *path; 217 218 if (n_params != 1) { 219 warnx("astlpc binding requires kcs device param"); 220 return -1; 221 } 222 223 path = params[0]; 224 225 astlpc = mctp_astlpc_init_fileio(path); 226 if (!astlpc) { 227 warnx("could not initialise astlpc binding"); 228 return -1; 229 } 230 231 mctp_register_bus(mctp, mctp_binding_astlpc_core(astlpc), eid); 232 233 binding->data = astlpc; 234 return 0; 235 } 236 237 static void binding_astlpc_destroy(struct mctp *mctp, struct binding *binding) 238 { 239 struct mctp_binding_astlpc *astlpc = binding->data; 240 241 mctp_unregister_bus(mctp, mctp_binding_astlpc_core(astlpc)); 242 243 mctp_astlpc_destroy(astlpc); 244 } 245 246 static int binding_astlpc_init_pollfd(struct binding *binding, 247 struct pollfd *pollfd) 248 { 249 return mctp_astlpc_init_pollfd(binding->data, pollfd); 250 } 251 252 static int binding_astlpc_process(struct binding *binding) 253 { 254 return mctp_astlpc_poll(binding->data); 255 } 256 257 struct binding bindings[] = { { 258 .name = "null", 259 .init = binding_null_init, 260 }, 261 { 262 .name = "serial", 263 .init = binding_serial_init, 264 .destroy = NULL, 265 .init_pollfd = binding_serial_init_pollfd, 266 .process = binding_serial_process, 267 }, 268 { 269 .name = "astlpc", 270 .init = binding_astlpc_init, 271 .destroy = binding_astlpc_destroy, 272 .init_pollfd = binding_astlpc_init_pollfd, 273 .process = binding_astlpc_process, 274 } }; 275 276 struct binding *binding_lookup(const char *name) 277 { 278 struct binding *binding; 279 unsigned int i; 280 281 for (i = 0; i < ARRAY_SIZE(bindings); i++) { 282 binding = &bindings[i]; 283 284 if (!strcmp(binding->name, name)) 285 return binding; 286 } 287 288 return NULL; 289 } 290 291 static int socket_init(struct ctx *ctx) 292 { 293 struct sockaddr_un addr; 294 int namelen, rc; 295 296 namelen = sizeof(sockname) - 1; 297 addr.sun_family = AF_UNIX; 298 memcpy(addr.sun_path, sockname, namelen); 299 300 ctx->sock = socket(AF_UNIX, SOCK_SEQPACKET, 0); 301 if (ctx->sock < 0) { 302 warn("can't create socket"); 303 return -1; 304 } 305 306 rc = bind(ctx->sock, (struct sockaddr *)&addr, 307 sizeof(addr.sun_family) + namelen); 308 if (rc) { 309 warn("can't bind socket"); 310 goto err_close; 311 } 312 313 rc = listen(ctx->sock, 1); 314 if (rc) { 315 warn("can't listen on socket"); 316 goto err_close; 317 } 318 319 return 0; 320 321 err_close: 322 close(ctx->sock); 323 return -1; 324 } 325 326 static int socket_process(struct ctx *ctx) 327 { 328 struct client *client; 329 int fd; 330 331 fd = accept4(ctx->sock, NULL, 0, SOCK_NONBLOCK); 332 if (fd < 0) 333 return -1; 334 335 ctx->n_clients++; 336 ctx->clients = 337 realloc(ctx->clients, ctx->n_clients * sizeof(struct client)); 338 339 client = &ctx->clients[ctx->n_clients - 1]; 340 memset(client, 0, sizeof(*client)); 341 client->active = true; 342 client->sock = fd; 343 344 return 0; 345 } 346 347 static int client_process_recv(struct ctx *ctx, int idx) 348 { 349 struct client *client = &ctx->clients[idx]; 350 uint8_t eid; 351 ssize_t len; 352 int rc; 353 354 /* are we waiting for a type message? */ 355 if (!client->type) { 356 uint8_t type; 357 rc = read(client->sock, &type, 1); 358 if (rc <= 0) 359 goto out_close; 360 361 if (type == 0) { 362 rc = -1; 363 goto out_close; 364 } 365 if (ctx->verbose) 366 fprintf(stderr, "client[%d] registered for type %u\n", 367 idx, type); 368 client->type = type; 369 return 0; 370 } 371 372 len = recv(client->sock, NULL, 0, MSG_PEEK | MSG_TRUNC); 373 if (len < 0) { 374 if (errno != ECONNRESET) 375 warn("can't receive (peek) from client"); 376 377 rc = -1; 378 goto out_close; 379 } 380 381 if ((size_t)len > ctx->buf_size) { 382 void *tmp; 383 384 tmp = realloc(ctx->buf, len); 385 if (!tmp) { 386 warn("can't allocate for incoming message"); 387 rc = -1; 388 goto out_close; 389 } 390 ctx->buf = tmp; 391 ctx->buf_size = len; 392 } 393 394 rc = recv(client->sock, ctx->buf, ctx->buf_size, 0); 395 if (rc < 0) { 396 if (errno != ECONNRESET) 397 warn("can't receive from client"); 398 rc = -1; 399 goto out_close; 400 } 401 402 if (rc <= 0) { 403 rc = -1; 404 goto out_close; 405 } 406 407 eid = *(uint8_t *)ctx->buf; 408 409 if (ctx->pcap.socket.path) 410 capture_socket(ctx->pcap.socket.dumper, ctx->buf, rc, 411 MCTP_MESSAGE_CAPTURE_OUTGOING, eid); 412 413 if (ctx->verbose) 414 fprintf(stderr, "client[%d] sent message: dest 0x%02x len %d\n", 415 idx, eid, rc - 1); 416 417 if (eid == ctx->local_eid) 418 rx_message(eid, MCTP_MESSAGE_TO_DST, 0, ctx, ctx->buf + 1, 419 rc - 1); 420 else 421 tx_message(ctx, eid, ctx->buf + 1, rc - 1); 422 423 return 0; 424 425 out_close: 426 client->active = false; 427 return rc; 428 } 429 430 static int binding_init(struct ctx *ctx, const char *name, int argc, 431 char *const *argv) 432 { 433 int rc; 434 435 ctx->binding = binding_lookup(name); 436 if (!ctx->binding) { 437 warnx("no such binding '%s'", name); 438 return -1; 439 } 440 441 rc = ctx->binding->init(ctx->mctp, ctx->binding, ctx->local_eid, argc, 442 argv); 443 return rc; 444 } 445 446 static void binding_destroy(struct ctx *ctx) 447 { 448 if (ctx->binding->destroy) 449 ctx->binding->destroy(ctx->mctp, ctx->binding); 450 } 451 452 enum { 453 FD_BINDING = 0, 454 FD_SOCKET, 455 FD_SIGNAL, 456 FD_NR, 457 }; 458 459 static int run_daemon(struct ctx *ctx) 460 { 461 bool clients_changed = false; 462 sigset_t mask; 463 int rc, i; 464 int n_clients; 465 466 ctx->pollfds = malloc(FD_NR * sizeof(struct pollfd)); 467 468 if (!ctx->binding->init_pollfd) { 469 ctx->pollfds[FD_BINDING].fd = -1; 470 ctx->pollfds[FD_BINDING].events = 0; 471 } 472 473 sigemptyset(&mask); 474 sigaddset(&mask, SIGINT); 475 sigaddset(&mask, SIGTERM); 476 sigaddset(&mask, SIGQUIT); 477 478 if ((rc = sigprocmask(SIG_BLOCK, &mask, NULL)) == -1) { 479 warn("sigprocmask"); 480 return rc; 481 } 482 483 ctx->pollfds[FD_SIGNAL].fd = signalfd(-1, &mask, 0); 484 ctx->pollfds[FD_SIGNAL].events = POLLIN; 485 486 ctx->pollfds[FD_SOCKET].fd = ctx->sock; 487 ctx->pollfds[FD_SOCKET].events = POLLIN; 488 489 mctp_set_rx_all(ctx->mctp, rx_message, ctx); 490 491 for (;;) { 492 if (clients_changed) { 493 int i; 494 495 ctx->pollfds = realloc(ctx->pollfds, 496 (ctx->n_clients + FD_NR) * 497 sizeof(struct pollfd)); 498 499 for (i = 0; i < ctx->n_clients; i++) { 500 ctx->pollfds[FD_NR + i].fd = 501 ctx->clients[i].sock; 502 ctx->pollfds[FD_NR + i].events = POLLIN; 503 } 504 clients_changed = false; 505 } 506 507 if (ctx->binding->init_pollfd) 508 ctx->binding->init_pollfd(ctx->binding, 509 &ctx->pollfds[FD_BINDING]); 510 rc = poll(ctx->pollfds, ctx->n_clients + FD_NR, -1); 511 if (rc < 0) { 512 warn("poll failed"); 513 break; 514 } 515 516 if (!rc) 517 continue; 518 519 if (ctx->pollfds[FD_SIGNAL].revents) { 520 struct signalfd_siginfo si; 521 ssize_t got; 522 523 got = read(ctx->pollfds[FD_SIGNAL].fd, &si, sizeof(si)); 524 if (got == sizeof(si)) { 525 warnx("Received %s, quitting", 526 strsignal(si.ssi_signo)); 527 rc = 0; 528 break; 529 } else { 530 warnx("Unexpected read result for signalfd: %d", 531 rc); 532 warnx("Quitting on the basis that signalfd became ready"); 533 rc = -1; 534 break; 535 } 536 } 537 538 n_clients = ctx->n_clients; 539 if (ctx->pollfds[FD_BINDING].revents) { 540 rc = 0; 541 if (ctx->binding->process) 542 rc = ctx->binding->process(ctx->binding); 543 if (rc) 544 break; 545 } 546 if (n_clients != ctx->n_clients) { 547 /* 548 * Clients (i.e. sockets) were removed in the binding->process() function 549 * call above. More specifically in function rx_message(), invoked through 550 * the binding->process() call. 551 * We must go back to the top of the loop to realign the pollfds sockets array 552 */ 553 clients_changed = true; 554 continue; 555 } 556 557 for (i = 0; i < ctx->n_clients; i++) { 558 if (!ctx->pollfds[FD_NR + i].revents) 559 continue; 560 561 rc = client_process_recv(ctx, i); 562 if (rc) 563 clients_changed = true; 564 } 565 566 if (ctx->pollfds[FD_SOCKET].revents) { 567 rc = socket_process(ctx); 568 if (rc) 569 break; 570 clients_changed = true; 571 } 572 573 if (clients_changed) 574 client_remove_inactive(ctx); 575 } 576 577 free(ctx->pollfds); 578 579 return rc; 580 } 581 582 static const struct option options[] = { 583 { "capture-binding", required_argument, 0, 'b' }, 584 { "capture-socket", required_argument, 0, 's' }, 585 { "binding-linktype", required_argument, 0, 'B' }, 586 { "socket-linktype", required_argument, 0, 'S' }, 587 { "verbose", no_argument, 0, 'v' }, 588 { "eid", required_argument, 0, 'e' }, 589 { 0 }, 590 }; 591 592 static void usage(const char *progname) 593 { 594 unsigned int i; 595 596 fprintf(stderr, "usage: %s <binding> [params]\n", progname); 597 fprintf(stderr, "Available bindings:\n"); 598 for (i = 0; i < ARRAY_SIZE(bindings); i++) 599 fprintf(stderr, " %s\n", bindings[i].name); 600 } 601 602 int main(int argc, char *const *argv) 603 { 604 struct ctx *ctx, _ctx; 605 int rc; 606 607 ctx = &_ctx; 608 ctx->clients = NULL; 609 ctx->n_clients = 0; 610 ctx->local_eid = local_eid_default; 611 ctx->verbose = false; 612 ctx->pcap.binding.path = NULL; 613 ctx->pcap.socket.path = NULL; 614 615 for (;;) { 616 rc = getopt_long(argc, argv, "b:es::v", options, NULL); 617 if (rc == -1) 618 break; 619 switch (rc) { 620 case 'b': 621 ctx->pcap.binding.path = optarg; 622 break; 623 case 's': 624 ctx->pcap.socket.path = optarg; 625 break; 626 case 'B': 627 fprintf(stderr, 628 "binding-linktype argument is deprecated\n"); 629 break; 630 case 'S': 631 fprintf(stderr, 632 "socket-linktype argument is deprecated\n"); 633 break; 634 case 'v': 635 ctx->verbose = true; 636 break; 637 case 'e': 638 ctx->local_eid = atoi(optarg); 639 break; 640 default: 641 fprintf(stderr, "Invalid argument\n"); 642 return EXIT_FAILURE; 643 } 644 } 645 646 if (optind >= argc) { 647 fprintf(stderr, "missing binding argument\n"); 648 usage(argv[0]); 649 return EXIT_FAILURE; 650 } 651 652 /* setup initial buffer */ 653 ctx->buf_size = 4096; 654 ctx->buf = malloc(ctx->buf_size); 655 656 mctp_set_log_stdio(ctx->verbose ? MCTP_LOG_DEBUG : MCTP_LOG_NOTICE); 657 658 ctx->mctp = mctp_init(); 659 assert(ctx->mctp); 660 661 if (ctx->pcap.binding.path || ctx->pcap.socket.path) { 662 if (capture_init()) { 663 rc = EXIT_FAILURE; 664 goto cleanup_mctp; 665 } 666 } 667 668 if (ctx->pcap.binding.path) { 669 rc = capture_prepare(&ctx->pcap.binding); 670 if (rc == -1) { 671 fprintf(stderr, "Failed to initialise capture: %d\n", 672 rc); 673 rc = EXIT_FAILURE; 674 goto cleanup_mctp; 675 } 676 677 mctp_set_capture_handler(ctx->mctp, capture_binding, 678 ctx->pcap.binding.dumper); 679 } 680 681 if (ctx->pcap.socket.path) { 682 rc = capture_prepare(&ctx->pcap.socket); 683 if (rc == -1) { 684 fprintf(stderr, "Failed to initialise capture: %d\n", 685 rc); 686 rc = EXIT_FAILURE; 687 goto cleanup_pcap_binding; 688 } 689 } 690 691 rc = binding_init(ctx, argv[optind], argc - optind - 1, 692 argv + optind + 1); 693 if (rc) { 694 fprintf(stderr, "Failed to initialise binding: %d\n", rc); 695 rc = EXIT_FAILURE; 696 goto cleanup_pcap_socket; 697 } 698 699 rc = sd_listen_fds(true); 700 if (rc <= 0) { 701 rc = socket_init(ctx); 702 if (rc) { 703 fprintf(stderr, "Failed to initialse socket: %d\n", rc); 704 goto cleanup_binding; 705 } 706 } else { 707 ctx->sock = SD_LISTEN_FDS_START; 708 } 709 710 rc = run_daemon(ctx); 711 712 cleanup_binding: 713 binding_destroy(ctx); 714 715 cleanup_pcap_socket: 716 if (ctx->pcap.socket.path) 717 capture_close(&ctx->pcap.socket); 718 719 cleanup_pcap_binding: 720 if (ctx->pcap.binding.path) 721 capture_close(&ctx->pcap.binding); 722 723 rc = rc ? EXIT_FAILURE : EXIT_SUCCESS; 724 cleanup_mctp: 725 726 return rc; 727 } 728