xref: /openbmc/libmctp/utils/mctp-demux-daemon.c (revision 3ef47785)
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