1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 3 #define _GNU_SOURCE 4 5 #include "config.h" 6 7 #include <assert.h> 8 #include <err.h> 9 #include <errno.h> 10 #include <getopt.h> 11 #include <limits.h> 12 #include <poll.h> 13 #include <stdbool.h> 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #include <unistd.h> 18 19 #include <sys/socket.h> 20 #include <sys/un.h> 21 22 #define SD_LISTEN_FDS_START 3 23 24 #include "libmctp.h" 25 #include "libmctp-serial.h" 26 #include "libmctp-astlpc.h" 27 28 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 29 #define __unused __attribute__((unused)) 30 31 #if HAVE_SYSTEMD_SD_DAEMON_H 32 #include <systemd/sd-daemon.h> 33 #else 34 static inline int sd_listen_fds(int i __unused) 35 { 36 return -1; 37 } 38 #endif 39 40 static const mctp_eid_t local_eid_default = 8; 41 static char sockname[] = "\0mctp-mux"; 42 43 struct binding { 44 const char *name; 45 int (*init)(struct mctp *mctp, struct binding *binding, 46 mctp_eid_t eid, int n_params, 47 char * const * params); 48 int (*get_fd)(struct binding *binding); 49 int (*process)(struct binding *binding); 50 void *data; 51 }; 52 53 struct client { 54 bool active; 55 int sock; 56 uint8_t type; 57 }; 58 59 struct ctx { 60 struct mctp *mctp; 61 struct binding *binding; 62 bool verbose; 63 int local_eid; 64 void *buf; 65 size_t buf_size; 66 67 int sock; 68 struct pollfd *pollfds; 69 70 struct client *clients; 71 int n_clients; 72 }; 73 74 static void tx_message(struct ctx *ctx, mctp_eid_t eid, void *msg, size_t len) 75 { 76 int rc; 77 78 rc = mctp_message_tx(ctx->mctp, eid, msg, len); 79 if (rc) 80 warnx("Failed to send message: %d", rc); 81 } 82 83 static void client_remove_inactive(struct ctx *ctx) 84 { 85 int i; 86 87 for (i = 0; i < ctx->n_clients; i++) { 88 struct client *client = &ctx->clients[i]; 89 if (client->active) 90 continue; 91 close(client->sock); 92 93 ctx->n_clients--; 94 memmove(&ctx->clients[i], &ctx->clients[i+1], 95 (ctx->n_clients - i) * sizeof(*ctx->clients)); 96 ctx->clients = realloc(ctx->clients, 97 ctx->n_clients * sizeof(*ctx->clients)); 98 } 99 } 100 101 static void rx_message(uint8_t eid, void *data, void *msg, size_t len) 102 { 103 struct ctx *ctx = data; 104 struct iovec iov[2]; 105 struct msghdr msghdr; 106 bool removed; 107 uint8_t type; 108 int i, rc; 109 110 if (len < 2) 111 return; 112 113 type = *(uint8_t *)msg; 114 115 if (ctx->verbose) 116 fprintf(stderr, "MCTP message received: len %zd, type %d\n", 117 len, type); 118 119 memset(&msghdr, 0, sizeof(msghdr)); 120 msghdr.msg_iov = iov; 121 msghdr.msg_iovlen = 2; 122 iov[0].iov_base = &eid; 123 iov[0].iov_len = 1; 124 iov[1].iov_base = msg; 125 iov[1].iov_len = len; 126 127 for (i = 0; i < ctx->n_clients; i++) { 128 struct client *client = &ctx->clients[i]; 129 130 if (client->type != type) 131 continue; 132 133 if (ctx->verbose) 134 fprintf(stderr, " forwarding to client %d\n", i); 135 136 rc = sendmsg(client->sock, &msghdr, 0); 137 if (rc != (ssize_t)(len + 1)) { 138 client->active = false; 139 removed = true; 140 } 141 } 142 143 if (removed) 144 client_remove_inactive(ctx); 145 146 } 147 148 static int binding_null_init(struct mctp *mctp __unused, 149 struct binding *binding __unused, 150 mctp_eid_t eid __unused, 151 int n_params, char * const *params __unused) 152 { 153 if (n_params != 0) { 154 warnx("null binding doesn't accept parameters"); 155 return -1; 156 } 157 return 0; 158 } 159 160 static int binding_serial_init(struct mctp *mctp, struct binding *binding, 161 mctp_eid_t eid, int n_params, char * const *params) 162 { 163 struct mctp_binding_serial *serial; 164 const char *path; 165 int rc; 166 167 if (n_params != 1) { 168 warnx("serial binding requires device param"); 169 return -1; 170 } 171 172 path = params[0]; 173 174 serial = mctp_serial_init(); 175 assert(serial); 176 177 rc = mctp_serial_open_path(serial, path); 178 if (rc) 179 return -1; 180 181 mctp_register_bus(mctp, mctp_binding_serial_core(serial), eid); 182 183 binding->data = serial; 184 185 return 0; 186 } 187 188 static int binding_serial_get_fd(struct binding *binding) 189 { 190 return mctp_serial_get_fd(binding->data); 191 } 192 193 static int binding_serial_process(struct binding *binding) 194 { 195 return mctp_serial_read(binding->data); 196 } 197 198 static int binding_astlpc_init(struct mctp *mctp, struct binding *binding, 199 mctp_eid_t eid, int n_params, 200 char * const *params __attribute__((unused))) 201 { 202 struct mctp_binding_astlpc *astlpc; 203 204 if (n_params) { 205 warnx("astlpc binding does not accept parameters"); 206 return -1; 207 } 208 209 astlpc = mctp_astlpc_init_fileio(); 210 if (!astlpc) { 211 warnx("could not initialise astlpc binding"); 212 return -1; 213 } 214 215 mctp_register_bus(mctp, mctp_binding_astlpc_core(astlpc), eid); 216 217 binding->data = astlpc; 218 return 0; 219 } 220 221 static int binding_astlpc_get_fd(struct binding *binding) 222 { 223 return mctp_astlpc_get_fd(binding->data); 224 } 225 226 static int binding_astlpc_process(struct binding *binding) 227 { 228 return mctp_astlpc_poll(binding->data); 229 } 230 231 struct binding bindings[] = { 232 { 233 .name = "null", 234 .init = binding_null_init, 235 }, 236 { 237 .name = "serial", 238 .init = binding_serial_init, 239 .get_fd = binding_serial_get_fd, 240 .process = binding_serial_process, 241 }, 242 { 243 .name = "astlpc", 244 .init = binding_astlpc_init, 245 .get_fd = binding_astlpc_get_fd, 246 .process = binding_astlpc_process, 247 } 248 }; 249 250 struct binding *binding_lookup(const char *name) 251 { 252 struct binding *binding; 253 unsigned int i; 254 255 for (i = 0; i < ARRAY_SIZE(bindings); i++) { 256 binding = &bindings[i]; 257 258 if (!strcmp(binding->name, name)) 259 return binding; 260 } 261 262 return NULL; 263 } 264 265 static int socket_init(struct ctx *ctx) 266 { 267 struct sockaddr_un addr; 268 int namelen, rc; 269 270 namelen = sizeof(sockname) - 1; 271 addr.sun_family = AF_UNIX; 272 memcpy(addr.sun_path, sockname, namelen); 273 274 ctx->sock = socket(AF_UNIX, SOCK_SEQPACKET, 0); 275 if (ctx->sock < 0) { 276 warn("can't create socket"); 277 return -1; 278 } 279 280 rc = bind(ctx->sock, (struct sockaddr *)&addr, 281 sizeof(addr.sun_family) + namelen); 282 if (rc) { 283 warn("can't bind socket"); 284 goto err_close; 285 } 286 287 rc = listen(ctx->sock, 1); 288 if (rc) { 289 warn("can't listen on socket"); 290 goto err_close; 291 } 292 293 return 0; 294 295 err_close: 296 close(ctx->sock); 297 return -1; 298 } 299 300 static int socket_process(struct ctx *ctx) 301 { 302 struct client *client; 303 int fd; 304 305 fd = accept4(ctx->sock, NULL, 0, SOCK_NONBLOCK); 306 if (fd < 0) 307 return -1; 308 309 ctx->n_clients++; 310 ctx->clients = realloc(ctx->clients, 311 ctx->n_clients * sizeof(struct client)); 312 313 client = &ctx->clients[ctx->n_clients-1]; 314 memset(client, 0, sizeof(*client)); 315 client->active = true; 316 client->sock = fd; 317 318 return 0; 319 } 320 321 static int client_process_recv(struct ctx *ctx, int idx) 322 { 323 struct client *client = &ctx->clients[idx]; 324 uint8_t eid; 325 ssize_t len; 326 int rc; 327 328 /* are we waiting for a type message? */ 329 if (!client->type) { 330 uint8_t type; 331 rc = read(client->sock, &type, 1); 332 if (rc <= 0) 333 goto out_close; 334 335 if (type == 0) { 336 rc = -1; 337 goto out_close; 338 } 339 if (ctx->verbose) 340 fprintf(stderr, "client[%d] registered for type %u\n", 341 idx, type); 342 client->type = type; 343 return 0; 344 } 345 346 len = recv(client->sock, NULL, 0, MSG_PEEK | MSG_TRUNC); 347 if (len < 0) { 348 if (errno != ECONNRESET) 349 warn("can't receive (peek) from client"); 350 351 rc = -1; 352 goto out_close; 353 } 354 355 if ((size_t)len > ctx->buf_size) { 356 void *tmp; 357 358 tmp = realloc(ctx->buf, len); 359 if (!tmp) { 360 warn("can't allocate for incoming message"); 361 rc = -1; 362 goto out_close; 363 } 364 ctx->buf = tmp; 365 ctx->buf_size = len; 366 } 367 368 rc = recv(client->sock, ctx->buf, ctx->buf_size, 0); 369 if (rc < 0) { 370 if (errno != ECONNRESET) 371 warn("can't receive from client"); 372 rc = -1; 373 goto out_close; 374 } 375 376 if (rc <= 0) { 377 rc = -1; 378 goto out_close; 379 } 380 381 eid = *(uint8_t *)ctx->buf; 382 383 if (ctx->verbose) 384 fprintf(stderr, 385 "client[%d] sent message: dest 0x%02x len %d\n", 386 idx, eid, rc - 1); 387 388 389 if (eid == ctx->local_eid) 390 rx_message(eid, ctx, ctx->buf + 1, rc - 1); 391 else 392 tx_message(ctx, eid, ctx->buf + 1, rc - 1); 393 394 return 0; 395 396 out_close: 397 client->active = false; 398 return rc; 399 } 400 401 static int binding_init(struct ctx *ctx, const char *name, 402 int argc, char * const *argv) 403 { 404 int rc; 405 406 ctx->binding = binding_lookup(name); 407 if (!ctx->binding) { 408 warnx("no such binding '%s'", name); 409 return -1; 410 } 411 412 rc = ctx->binding->init(ctx->mctp, ctx->binding, ctx->local_eid, 413 argc, argv); 414 return rc; 415 } 416 417 enum { 418 FD_BINDING = 0, 419 FD_SOCKET, 420 FD_NR, 421 }; 422 423 static int run_daemon(struct ctx *ctx) 424 { 425 bool clients_changed = false; 426 int rc, i; 427 428 ctx->pollfds = malloc(FD_NR * sizeof(struct pollfd)); 429 430 if (ctx->binding->get_fd) { 431 ctx->pollfds[FD_BINDING].fd = 432 ctx->binding->get_fd(ctx->binding); 433 ctx->pollfds[FD_BINDING].events = POLLIN; 434 } else { 435 ctx->pollfds[FD_BINDING].fd = -1; 436 ctx->pollfds[FD_BINDING].events = 0; 437 } 438 439 ctx->pollfds[FD_SOCKET].fd = ctx->sock; 440 ctx->pollfds[FD_SOCKET].events = POLLIN; 441 442 mctp_set_rx_all(ctx->mctp, rx_message, ctx); 443 444 for (;;) { 445 if (clients_changed) { 446 int i; 447 448 ctx->pollfds = realloc(ctx->pollfds, 449 (ctx->n_clients + FD_NR) * 450 sizeof(struct pollfd)); 451 452 for (i = 0; i < ctx->n_clients; i++) { 453 ctx->pollfds[FD_NR+i].fd = 454 ctx->clients[i].sock; 455 ctx->pollfds[FD_NR+i].events = POLLIN; 456 } 457 clients_changed = false; 458 } 459 460 rc = poll(ctx->pollfds, ctx->n_clients + FD_NR, -1); 461 if (rc < 0) { 462 warn("poll failed"); 463 break; 464 } 465 466 if (!rc) 467 continue; 468 469 if (ctx->pollfds[FD_BINDING].revents) { 470 rc = 0; 471 if (ctx->binding->process) 472 rc = ctx->binding->process(ctx->binding); 473 if (rc) 474 break; 475 } 476 477 for (i = 0; i < ctx->n_clients; i++) { 478 if (!ctx->pollfds[FD_NR+i].revents) 479 continue; 480 481 rc = client_process_recv(ctx, i); 482 if (rc) 483 clients_changed = true; 484 } 485 486 if (ctx->pollfds[FD_SOCKET].revents) { 487 rc = socket_process(ctx); 488 if (rc) 489 break; 490 clients_changed = true; 491 } 492 493 if (clients_changed) 494 client_remove_inactive(ctx); 495 496 } 497 498 499 free(ctx->pollfds); 500 501 return rc; 502 } 503 504 static const struct option options[] = { 505 { "verbose", no_argument, 0, 'v' }, 506 { "eid", required_argument, 0, 'e' }, 507 { 0 }, 508 }; 509 510 static void usage(const char *progname) 511 { 512 unsigned int i; 513 514 fprintf(stderr, "usage: %s <binding> [params]\n", progname); 515 fprintf(stderr, "Available bindings:\n"); 516 for (i = 0; i < ARRAY_SIZE(bindings); i++) 517 fprintf(stderr, " %s\n", bindings[i].name); 518 } 519 520 int main(int argc, char * const *argv) 521 { 522 struct ctx *ctx, _ctx; 523 int rc; 524 525 ctx = &_ctx; 526 ctx->clients = NULL; 527 ctx->n_clients = 0; 528 ctx->local_eid = local_eid_default; 529 ctx->verbose = false; 530 531 for (;;) { 532 rc = getopt_long(argc, argv, "e:v", options, NULL); 533 if (rc == -1) 534 break; 535 switch (rc) { 536 case 'v': 537 ctx->verbose = true; 538 break; 539 case 'e': 540 ctx->local_eid = atoi(optarg); 541 break; 542 default: 543 fprintf(stderr, "Invalid argument\n"); 544 return EXIT_FAILURE; 545 } 546 } 547 548 if (optind >= argc) { 549 fprintf(stderr, "missing binding argument\n"); 550 usage(argv[0]); 551 return EXIT_FAILURE; 552 } 553 554 /* setup initial buffer */ 555 ctx->buf_size = 4096; 556 ctx->buf = malloc(ctx->buf_size); 557 558 mctp_set_log_stdio(ctx->verbose ? MCTP_LOG_DEBUG : MCTP_LOG_WARNING); 559 560 ctx->mctp = mctp_init(); 561 assert(ctx->mctp); 562 563 rc = binding_init(ctx, argv[optind], argc - optind - 1, argv + optind + 1); 564 if (rc) 565 return EXIT_FAILURE; 566 567 rc = sd_listen_fds(true); 568 if (rc <= 0) { 569 rc = socket_init(ctx); 570 if (rc) 571 return EXIT_FAILURE; 572 } else { 573 ctx->sock = SD_LISTEN_FDS_START; 574 } 575 576 rc = run_daemon(ctx); 577 578 return rc ? EXIT_FAILURE : EXIT_SUCCESS; 579 580 } 581