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