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
sd_listen_fds(int i __unused)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
tx_message(struct ctx * ctx,mctp_eid_t eid,void * msg,size_t len)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
client_remove_inactive(struct ctx * ctx)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
rx_message(uint8_t eid,bool tag_owner __unused,uint8_t msg_tag __unused,void * data,void * msg,size_t len)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
binding_null_init(struct mctp * mctp __unused,struct binding * binding __unused,mctp_eid_t eid __unused,int n_params,char * const * params __unused)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
binding_serial_init(struct mctp * mctp,struct binding * binding,mctp_eid_t eid,int n_params,char * const * params)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
binding_serial_init_pollfd(struct binding * binding,struct pollfd * pollfd)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
binding_serial_process(struct binding * binding)206 static int binding_serial_process(struct binding *binding)
207 {
208 return mctp_serial_read(binding->data);
209 }
210
binding_astlpc_init(struct mctp * mctp,struct binding * binding,mctp_eid_t eid,int n_params,char * const * params)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
binding_astlpc_destroy(struct mctp * mctp,struct binding * binding)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
binding_astlpc_init_pollfd(struct binding * binding,struct pollfd * pollfd)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
binding_astlpc_process(struct binding * binding)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
binding_lookup(const char * name)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
socket_init(struct ctx * ctx)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
socket_process(struct ctx * ctx)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
client_process_recv(struct ctx * ctx,int idx)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
binding_init(struct ctx * ctx,const char * name,int argc,char * const * argv)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
binding_destroy(struct ctx * ctx)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
run_daemon(struct ctx * ctx)459 static int run_daemon(struct ctx *ctx)
460 {
461 bool clients_changed = false;
462 sigset_t mask;
463 int rc, i;
464
465 ctx->pollfds = malloc(FD_NR * sizeof(struct pollfd));
466
467 if (!ctx->binding->init_pollfd) {
468 ctx->pollfds[FD_BINDING].fd = -1;
469 ctx->pollfds[FD_BINDING].events = 0;
470 }
471
472 sigemptyset(&mask);
473 sigaddset(&mask, SIGINT);
474 sigaddset(&mask, SIGTERM);
475 sigaddset(&mask, SIGQUIT);
476
477 if ((rc = sigprocmask(SIG_BLOCK, &mask, NULL)) == -1) {
478 warn("sigprocmask");
479 return rc;
480 }
481
482 ctx->pollfds[FD_SIGNAL].fd = signalfd(-1, &mask, 0);
483 ctx->pollfds[FD_SIGNAL].events = POLLIN;
484
485 ctx->pollfds[FD_SOCKET].fd = ctx->sock;
486 ctx->pollfds[FD_SOCKET].events = POLLIN;
487
488 mctp_set_rx_all(ctx->mctp, rx_message, ctx);
489
490 for (;;) {
491 if (clients_changed) {
492 int i;
493
494 ctx->pollfds = realloc(ctx->pollfds,
495 (ctx->n_clients + FD_NR) *
496 sizeof(struct pollfd));
497
498 for (i = 0; i < ctx->n_clients; i++) {
499 ctx->pollfds[FD_NR + i].fd =
500 ctx->clients[i].sock;
501 ctx->pollfds[FD_NR + i].events = POLLIN;
502 }
503 clients_changed = false;
504 }
505
506 if (ctx->binding->init_pollfd)
507 ctx->binding->init_pollfd(ctx->binding,
508 &ctx->pollfds[FD_BINDING]);
509 rc = poll(ctx->pollfds, ctx->n_clients + FD_NR, -1);
510 if (rc < 0) {
511 warn("poll failed");
512 break;
513 }
514
515 if (!rc)
516 continue;
517
518 if (ctx->pollfds[FD_SIGNAL].revents) {
519 struct signalfd_siginfo si;
520 ssize_t got;
521
522 got = read(ctx->pollfds[FD_SIGNAL].fd, &si, sizeof(si));
523 if (got == sizeof(si)) {
524 warnx("Received %s, quitting",
525 strsignal(si.ssi_signo));
526 rc = 0;
527 break;
528 } else {
529 warnx("Unexpected read result for signalfd: %d",
530 rc);
531 warnx("Quitting on the basis that signalfd became ready");
532 rc = -1;
533 break;
534 }
535 }
536
537 if (ctx->pollfds[FD_BINDING].revents) {
538 rc = 0;
539 if (ctx->binding->process)
540 rc = ctx->binding->process(ctx->binding);
541 if (rc)
542 break;
543 }
544
545 for (i = 0; i < ctx->n_clients; i++) {
546 if (!ctx->pollfds[FD_NR + i].revents)
547 continue;
548
549 rc = client_process_recv(ctx, i);
550 if (rc)
551 clients_changed = true;
552 }
553
554 if (ctx->pollfds[FD_SOCKET].revents) {
555 rc = socket_process(ctx);
556 if (rc)
557 break;
558 clients_changed = true;
559 }
560
561 if (clients_changed)
562 client_remove_inactive(ctx);
563 }
564
565 free(ctx->pollfds);
566
567 return rc;
568 }
569
570 static const struct option options[] = {
571 { "capture-binding", required_argument, 0, 'b' },
572 { "capture-socket", required_argument, 0, 's' },
573 { "binding-linktype", required_argument, 0, 'B' },
574 { "socket-linktype", required_argument, 0, 'S' },
575 { "verbose", no_argument, 0, 'v' },
576 { "eid", required_argument, 0, 'e' },
577 { 0 },
578 };
579
usage(const char * progname)580 static void usage(const char *progname)
581 {
582 unsigned int i;
583
584 fprintf(stderr, "usage: %s <binding> [params]\n", progname);
585 fprintf(stderr, "Available bindings:\n");
586 for (i = 0; i < ARRAY_SIZE(bindings); i++)
587 fprintf(stderr, " %s\n", bindings[i].name);
588 }
589
main(int argc,char * const * argv)590 int main(int argc, char *const *argv)
591 {
592 struct ctx *ctx, _ctx;
593 int rc;
594
595 ctx = &_ctx;
596 ctx->clients = NULL;
597 ctx->n_clients = 0;
598 ctx->local_eid = local_eid_default;
599 ctx->verbose = false;
600 ctx->pcap.binding.path = NULL;
601 ctx->pcap.socket.path = NULL;
602
603 for (;;) {
604 rc = getopt_long(argc, argv, "b:es::v", options, NULL);
605 if (rc == -1)
606 break;
607 switch (rc) {
608 case 'b':
609 ctx->pcap.binding.path = optarg;
610 break;
611 case 's':
612 ctx->pcap.socket.path = optarg;
613 break;
614 case 'B':
615 fprintf(stderr,
616 "binding-linktype argument is deprecated\n");
617 break;
618 case 'S':
619 fprintf(stderr,
620 "socket-linktype argument is deprecated\n");
621 break;
622 case 'v':
623 ctx->verbose = true;
624 break;
625 case 'e':
626 ctx->local_eid = atoi(optarg);
627 break;
628 default:
629 fprintf(stderr, "Invalid argument\n");
630 return EXIT_FAILURE;
631 }
632 }
633
634 if (optind >= argc) {
635 fprintf(stderr, "missing binding argument\n");
636 usage(argv[0]);
637 return EXIT_FAILURE;
638 }
639
640 /* setup initial buffer */
641 ctx->buf_size = 4096;
642 ctx->buf = malloc(ctx->buf_size);
643
644 mctp_set_log_stdio(ctx->verbose ? MCTP_LOG_DEBUG : MCTP_LOG_NOTICE);
645
646 ctx->mctp = mctp_init();
647 assert(ctx->mctp);
648
649 if (ctx->pcap.binding.path || ctx->pcap.socket.path) {
650 if (capture_init()) {
651 rc = EXIT_FAILURE;
652 goto cleanup_mctp;
653 }
654 }
655
656 if (ctx->pcap.binding.path) {
657 rc = capture_prepare(&ctx->pcap.binding);
658 if (rc == -1) {
659 fprintf(stderr, "Failed to initialise capture: %d\n",
660 rc);
661 rc = EXIT_FAILURE;
662 goto cleanup_mctp;
663 }
664
665 mctp_set_capture_handler(ctx->mctp, capture_binding,
666 ctx->pcap.binding.dumper);
667 }
668
669 if (ctx->pcap.socket.path) {
670 rc = capture_prepare(&ctx->pcap.socket);
671 if (rc == -1) {
672 fprintf(stderr, "Failed to initialise capture: %d\n",
673 rc);
674 rc = EXIT_FAILURE;
675 goto cleanup_pcap_binding;
676 }
677 }
678
679 rc = binding_init(ctx, argv[optind], argc - optind - 1,
680 argv + optind + 1);
681 if (rc) {
682 fprintf(stderr, "Failed to initialise binding: %d\n", rc);
683 rc = EXIT_FAILURE;
684 goto cleanup_pcap_socket;
685 }
686
687 rc = sd_listen_fds(true);
688 if (rc <= 0) {
689 rc = socket_init(ctx);
690 if (rc) {
691 fprintf(stderr, "Failed to initialse socket: %d\n", rc);
692 goto cleanup_binding;
693 }
694 } else {
695 ctx->sock = SD_LISTEN_FDS_START;
696 }
697
698 rc = run_daemon(ctx);
699
700 cleanup_binding:
701 binding_destroy(ctx);
702
703 cleanup_pcap_socket:
704 if (ctx->pcap.socket.path)
705 capture_close(&ctx->pcap.socket);
706
707 cleanup_pcap_binding:
708 if (ctx->pcap.binding.path)
709 capture_close(&ctx->pcap.binding);
710
711 rc = rc ? EXIT_FAILURE : EXIT_SUCCESS;
712 cleanup_mctp:
713
714 return rc;
715 }
716