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