xref: /openbmc/libmctp/utils/mctp-demux-daemon.c (revision 400766f9)
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 #define SD_LISTEN_FDS_START 3
8 
9 #include "compiler.h"
10 #include "libmctp.h"
11 #include "libmctp-serial.h"
12 #include "libmctp-astlpc.h"
13 #include "utils/mctp-capture.h"
14 
15 #include <assert.h>
16 #include <err.h>
17 #include <errno.h>
18 #include <getopt.h>
19 #include <limits.h>
20 #include <poll.h>
21 #include <signal.h>
22 #include <stdbool.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 
28 #include <sys/signalfd.h>
29 #include <sys/socket.h>
30 #include <sys/un.h>
31 
32 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
33 
34 #if HAVE_SYSTEMD_SD_DAEMON_H
35 #include <systemd/sd-daemon.h>
36 #else
sd_listen_fds(int i __unused)37 static inline int sd_listen_fds(int i __unused)
38 {
39 	return -1;
40 }
41 #endif
42 
43 static const mctp_eid_t local_eid_default = 8;
44 static char sockname[] = "\0mctp-mux";
45 
46 struct binding {
47 	const char *name;
48 	int (*init)(struct mctp *mctp, struct binding *binding, mctp_eid_t eid,
49 		    int n_params, char *const *params);
50 	void (*destroy)(struct mctp *mctp, struct binding *binding);
51 	int (*init_pollfd)(struct binding *binding, struct pollfd *pollfd);
52 	int (*process)(struct binding *binding);
53 	void *data;
54 };
55 
56 struct client {
57 	bool active;
58 	int sock;
59 	uint8_t type;
60 };
61 
62 struct ctx {
63 	struct mctp *mctp;
64 	struct binding *binding;
65 	bool verbose;
66 	int local_eid;
67 	void *buf;
68 	size_t buf_size;
69 
70 	int sock;
71 	struct pollfd *pollfds;
72 
73 	struct client *clients;
74 	int n_clients;
75 
76 	struct {
77 		struct capture binding;
78 		struct capture socket;
79 	} pcap;
80 };
81 
tx_message(struct ctx * ctx,mctp_eid_t eid,void * msg,size_t len)82 static void tx_message(struct ctx *ctx, mctp_eid_t eid, void *msg, size_t len)
83 {
84 	int rc;
85 
86 	rc = mctp_message_tx(ctx->mctp, eid, MCTP_MESSAGE_TO_SRC, 0, msg, len);
87 	if (rc)
88 		warnx("Failed to send message: %d", rc);
89 }
90 
client_remove_inactive(struct ctx * ctx)91 static void client_remove_inactive(struct ctx *ctx)
92 {
93 	int i;
94 
95 	for (i = 0; i < ctx->n_clients; i++) {
96 		struct client *client = &ctx->clients[i];
97 		if (client->active)
98 			continue;
99 		close(client->sock);
100 
101 		ctx->n_clients--;
102 		memmove(&ctx->clients[i], &ctx->clients[i + 1],
103 			(ctx->n_clients - i) * sizeof(*ctx->clients));
104 		ctx->clients = realloc(ctx->clients,
105 				       ctx->n_clients * sizeof(*ctx->clients));
106 	}
107 }
108 
rx_message(uint8_t eid,bool tag_owner __unused,uint8_t msg_tag __unused,void * data,void * msg,size_t len)109 static void rx_message(uint8_t eid, bool tag_owner __unused,
110 		       uint8_t msg_tag __unused, void *data, void *msg,
111 		       size_t len)
112 {
113 	struct ctx *ctx = data;
114 	struct iovec iov[2];
115 	struct msghdr msghdr;
116 	bool removed;
117 	uint8_t type;
118 	int i, rc;
119 
120 	if (len < 2)
121 		return;
122 
123 	type = *(uint8_t *)msg;
124 
125 	if (ctx->verbose)
126 		fprintf(stderr, "MCTP message received: len %zd, type %d\n",
127 			len, type);
128 
129 	memset(&msghdr, 0, sizeof(msghdr));
130 	msghdr.msg_iov = iov;
131 	msghdr.msg_iovlen = 2;
132 	iov[0].iov_base = &eid;
133 	iov[0].iov_len = 1;
134 	iov[1].iov_base = msg;
135 	iov[1].iov_len = len;
136 
137 	for (i = 0; i < ctx->n_clients; i++) {
138 		struct client *client = &ctx->clients[i];
139 
140 		if (client->type != type)
141 			continue;
142 
143 		if (ctx->verbose)
144 			fprintf(stderr, "  forwarding to client %d\n", i);
145 
146 		rc = sendmsg(client->sock, &msghdr, 0);
147 		if (rc != (ssize_t)(len + 1)) {
148 			client->active = false;
149 			removed = true;
150 		}
151 	}
152 
153 	if (removed)
154 		client_remove_inactive(ctx);
155 }
156 
binding_null_init(struct mctp * mctp __unused,struct binding * binding __unused,mctp_eid_t eid __unused,int n_params,char * const * params __unused)157 static int binding_null_init(struct mctp *mctp __unused,
158 			     struct binding *binding __unused,
159 			     mctp_eid_t eid __unused, int n_params,
160 			     char *const *params __unused)
161 {
162 	if (n_params != 0) {
163 		warnx("null binding doesn't accept parameters");
164 		return -1;
165 	}
166 	return 0;
167 }
168 
binding_serial_init(struct mctp * mctp,struct binding * binding,mctp_eid_t eid,int n_params,char * const * params)169 static int binding_serial_init(struct mctp *mctp, struct binding *binding,
170 			       mctp_eid_t eid, int n_params,
171 			       char *const *params)
172 {
173 	struct mctp_binding_serial *serial;
174 	const char *path;
175 	int rc;
176 
177 	if (n_params != 1) {
178 		warnx("serial binding requires device param");
179 		return -1;
180 	}
181 
182 	path = params[0];
183 
184 	serial = mctp_serial_init();
185 	assert(serial);
186 
187 	rc = mctp_serial_open_path(serial, path);
188 	if (rc)
189 		return -1;
190 
191 	mctp_register_bus(mctp, mctp_binding_serial_core(serial), eid);
192 
193 	binding->data = serial;
194 
195 	return 0;
196 }
197 
binding_serial_init_pollfd(struct binding * binding,struct pollfd * pollfd)198 static int binding_serial_init_pollfd(struct binding *binding,
199 				      struct pollfd *pollfd)
200 {
201 	return mctp_serial_init_pollfd(binding->data, pollfd);
202 }
203 
binding_serial_process(struct binding * binding)204 static int binding_serial_process(struct binding *binding)
205 {
206 	return mctp_serial_read(binding->data);
207 }
208 
binding_astlpc_init(struct mctp * mctp,struct binding * binding,mctp_eid_t eid,int n_params,char * const * params)209 static int binding_astlpc_init(struct mctp *mctp, struct binding *binding,
210 			       mctp_eid_t eid, int n_params,
211 			       char *const *params __attribute__((unused)))
212 {
213 	struct mctp_binding_astlpc *astlpc;
214 	const char *path;
215 
216 	if (n_params != 1) {
217 		warnx("astlpc binding requires kcs device param");
218 		return -1;
219 	}
220 
221 	path = params[0];
222 
223 	astlpc = mctp_astlpc_init_fileio(path);
224 	if (!astlpc) {
225 		warnx("could not initialise astlpc binding");
226 		return -1;
227 	}
228 
229 	mctp_register_bus(mctp, mctp_binding_astlpc_core(astlpc), eid);
230 
231 	binding->data = astlpc;
232 	return 0;
233 }
234 
binding_astlpc_destroy(struct mctp * mctp,struct binding * binding)235 static void binding_astlpc_destroy(struct mctp *mctp, struct binding *binding)
236 {
237 	struct mctp_binding_astlpc *astlpc = binding->data;
238 
239 	mctp_unregister_bus(mctp, mctp_binding_astlpc_core(astlpc));
240 
241 	mctp_astlpc_destroy(astlpc);
242 }
243 
binding_astlpc_init_pollfd(struct binding * binding,struct pollfd * pollfd)244 static int binding_astlpc_init_pollfd(struct binding *binding,
245 				      struct pollfd *pollfd)
246 {
247 	return mctp_astlpc_init_pollfd(binding->data, pollfd);
248 }
249 
binding_astlpc_process(struct binding * binding)250 static int binding_astlpc_process(struct binding *binding)
251 {
252 	return mctp_astlpc_poll(binding->data);
253 }
254 
255 struct binding bindings[] = { {
256 				      .name = "null",
257 				      .init = binding_null_init,
258 			      },
259 			      {
260 				      .name = "serial",
261 				      .init = binding_serial_init,
262 				      .destroy = NULL,
263 				      .init_pollfd = binding_serial_init_pollfd,
264 				      .process = binding_serial_process,
265 			      },
266 			      {
267 				      .name = "astlpc",
268 				      .init = binding_astlpc_init,
269 				      .destroy = binding_astlpc_destroy,
270 				      .init_pollfd = binding_astlpc_init_pollfd,
271 				      .process = binding_astlpc_process,
272 			      } };
273 
binding_lookup(const char * name)274 struct binding *binding_lookup(const char *name)
275 {
276 	struct binding *binding;
277 	unsigned int i;
278 
279 	for (i = 0; i < ARRAY_SIZE(bindings); i++) {
280 		binding = &bindings[i];
281 
282 		if (!strcmp(binding->name, name))
283 			return binding;
284 	}
285 
286 	return NULL;
287 }
288 
socket_init(struct ctx * ctx)289 static int socket_init(struct ctx *ctx)
290 {
291 	struct sockaddr_un addr;
292 	int namelen, rc;
293 
294 	namelen = sizeof(sockname) - 1;
295 	addr.sun_family = AF_UNIX;
296 	memcpy(addr.sun_path, sockname, namelen);
297 
298 	ctx->sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
299 	if (ctx->sock < 0) {
300 		warn("can't create socket");
301 		return -1;
302 	}
303 
304 	rc = bind(ctx->sock, (struct sockaddr *)&addr,
305 		  sizeof(addr.sun_family) + namelen);
306 	if (rc) {
307 		warn("can't bind socket");
308 		goto err_close;
309 	}
310 
311 	rc = listen(ctx->sock, 1);
312 	if (rc) {
313 		warn("can't listen on socket");
314 		goto err_close;
315 	}
316 
317 	return 0;
318 
319 err_close:
320 	close(ctx->sock);
321 	return -1;
322 }
323 
socket_process(struct ctx * ctx)324 static int socket_process(struct ctx *ctx)
325 {
326 	struct client *client;
327 	int fd;
328 
329 	fd = accept4(ctx->sock, NULL, 0, SOCK_NONBLOCK);
330 	if (fd < 0)
331 		return -1;
332 
333 	ctx->n_clients++;
334 	ctx->clients =
335 		realloc(ctx->clients, ctx->n_clients * sizeof(struct client));
336 
337 	client = &ctx->clients[ctx->n_clients - 1];
338 	memset(client, 0, sizeof(*client));
339 	client->active = true;
340 	client->sock = fd;
341 
342 	return 0;
343 }
344 
client_process_recv(struct ctx * ctx,int idx)345 static int client_process_recv(struct ctx *ctx, int idx)
346 {
347 	struct client *client = &ctx->clients[idx];
348 	uint8_t eid;
349 	ssize_t len;
350 	int rc;
351 
352 	/* are we waiting for a type message? */
353 	if (!client->type) {
354 		uint8_t type;
355 		rc = read(client->sock, &type, 1);
356 		if (rc <= 0)
357 			goto out_close;
358 
359 		if (type == 0) {
360 			rc = -1;
361 			goto out_close;
362 		}
363 		if (ctx->verbose)
364 			fprintf(stderr, "client[%d] registered for type %u\n",
365 				idx, type);
366 		client->type = type;
367 		return 0;
368 	}
369 
370 	len = recv(client->sock, NULL, 0, MSG_PEEK | MSG_TRUNC);
371 	if (len < 0) {
372 		if (errno != ECONNRESET)
373 			warn("can't receive (peek) from client");
374 
375 		rc = -1;
376 		goto out_close;
377 	}
378 
379 	if ((size_t)len > ctx->buf_size) {
380 		void *tmp;
381 
382 		tmp = realloc(ctx->buf, len);
383 		if (!tmp) {
384 			warn("can't allocate for incoming message");
385 			rc = -1;
386 			goto out_close;
387 		}
388 		ctx->buf = tmp;
389 		ctx->buf_size = len;
390 	}
391 
392 	rc = recv(client->sock, ctx->buf, ctx->buf_size, 0);
393 	if (rc < 0) {
394 		if (errno != ECONNRESET)
395 			warn("can't receive from client");
396 		rc = -1;
397 		goto out_close;
398 	}
399 
400 	if (rc <= 0) {
401 		rc = -1;
402 		goto out_close;
403 	}
404 
405 	eid = *(uint8_t *)ctx->buf;
406 
407 	if (ctx->pcap.socket.path)
408 		capture_socket(ctx->pcap.socket.dumper, ctx->buf, rc,
409 			       MCTP_MESSAGE_CAPTURE_OUTGOING, eid);
410 
411 	if (ctx->verbose)
412 		fprintf(stderr, "client[%d] sent message: dest 0x%02x len %d\n",
413 			idx, eid, rc - 1);
414 
415 	if (eid == ctx->local_eid)
416 		rx_message(eid, MCTP_MESSAGE_TO_DST, 0, ctx, ctx->buf + 1,
417 			   rc - 1);
418 	else
419 		tx_message(ctx, eid, ctx->buf + 1, rc - 1);
420 
421 	return 0;
422 
423 out_close:
424 	client->active = false;
425 	return rc;
426 }
427 
binding_init(struct ctx * ctx,const char * name,int argc,char * const * argv)428 static int binding_init(struct ctx *ctx, const char *name, int argc,
429 			char *const *argv)
430 {
431 	int rc;
432 
433 	ctx->binding = binding_lookup(name);
434 	if (!ctx->binding) {
435 		warnx("no such binding '%s'", name);
436 		return -1;
437 	}
438 
439 	rc = ctx->binding->init(ctx->mctp, ctx->binding, ctx->local_eid, argc,
440 				argv);
441 	return rc;
442 }
443 
binding_destroy(struct ctx * ctx)444 static void binding_destroy(struct ctx *ctx)
445 {
446 	if (ctx->binding->destroy)
447 		ctx->binding->destroy(ctx->mctp, ctx->binding);
448 }
449 
450 enum {
451 	FD_BINDING = 0,
452 	FD_SOCKET,
453 	FD_SIGNAL,
454 	FD_NR,
455 };
456 
run_daemon(struct ctx * ctx)457 static int run_daemon(struct ctx *ctx)
458 {
459 	bool clients_changed = false;
460 	sigset_t mask;
461 	int rc, i;
462 
463 	ctx->pollfds = malloc(FD_NR * sizeof(struct pollfd));
464 
465 	if (!ctx->binding->init_pollfd) {
466 		ctx->pollfds[FD_BINDING].fd = -1;
467 		ctx->pollfds[FD_BINDING].events = 0;
468 	}
469 
470 	sigemptyset(&mask);
471 	sigaddset(&mask, SIGINT);
472 	sigaddset(&mask, SIGTERM);
473 	sigaddset(&mask, SIGQUIT);
474 
475 	if ((rc = sigprocmask(SIG_BLOCK, &mask, NULL)) == -1) {
476 		warn("sigprocmask");
477 		return rc;
478 	}
479 
480 	ctx->pollfds[FD_SIGNAL].fd = signalfd(-1, &mask, 0);
481 	ctx->pollfds[FD_SIGNAL].events = POLLIN;
482 
483 	ctx->pollfds[FD_SOCKET].fd = ctx->sock;
484 	ctx->pollfds[FD_SOCKET].events = POLLIN;
485 
486 	mctp_set_rx_all(ctx->mctp, rx_message, ctx);
487 
488 	for (;;) {
489 		if (clients_changed) {
490 			int i;
491 
492 			ctx->pollfds = realloc(ctx->pollfds,
493 					       (ctx->n_clients + FD_NR) *
494 						       sizeof(struct pollfd));
495 
496 			for (i = 0; i < ctx->n_clients; i++) {
497 				ctx->pollfds[FD_NR + i].fd =
498 					ctx->clients[i].sock;
499 				ctx->pollfds[FD_NR + i].events = POLLIN;
500 			}
501 			clients_changed = false;
502 		}
503 
504 		if (ctx->binding->init_pollfd)
505 			ctx->binding->init_pollfd(ctx->binding,
506 						  &ctx->pollfds[FD_BINDING]);
507 		rc = poll(ctx->pollfds, ctx->n_clients + FD_NR, -1);
508 		if (rc < 0) {
509 			warn("poll failed");
510 			break;
511 		}
512 
513 		if (!rc)
514 			continue;
515 
516 		if (ctx->pollfds[FD_SIGNAL].revents) {
517 			struct signalfd_siginfo si;
518 			ssize_t got;
519 
520 			got = read(ctx->pollfds[FD_SIGNAL].fd, &si, sizeof(si));
521 			if (got == sizeof(si)) {
522 				warnx("Received %s, quitting",
523 				      strsignal(si.ssi_signo));
524 				rc = 0;
525 				break;
526 			} else {
527 				warnx("Unexpected read result for signalfd: %d",
528 				      rc);
529 				warnx("Quitting on the basis that signalfd became ready");
530 				rc = -1;
531 				break;
532 			}
533 		}
534 
535 		if (ctx->pollfds[FD_BINDING].revents) {
536 			rc = 0;
537 			if (ctx->binding->process)
538 				rc = ctx->binding->process(ctx->binding);
539 			if (rc)
540 				break;
541 		}
542 
543 		for (i = 0; i < ctx->n_clients; i++) {
544 			if (!ctx->pollfds[FD_NR + i].revents)
545 				continue;
546 
547 			rc = client_process_recv(ctx, i);
548 			if (rc)
549 				clients_changed = true;
550 		}
551 
552 		if (ctx->pollfds[FD_SOCKET].revents) {
553 			rc = socket_process(ctx);
554 			if (rc)
555 				break;
556 			clients_changed = true;
557 		}
558 
559 		if (clients_changed)
560 			client_remove_inactive(ctx);
561 	}
562 
563 	free(ctx->pollfds);
564 
565 	return rc;
566 }
567 
568 static const struct option options[] = {
569 	{ "capture-binding", required_argument, 0, 'b' },
570 	{ "capture-socket", required_argument, 0, 's' },
571 	{ "binding-linktype", required_argument, 0, 'B' },
572 	{ "socket-linktype", required_argument, 0, 'S' },
573 	{ "verbose", no_argument, 0, 'v' },
574 	{ "eid", required_argument, 0, 'e' },
575 	{ 0 },
576 };
577 
usage(const char * progname)578 static void usage(const char *progname)
579 {
580 	unsigned int i;
581 
582 	fprintf(stderr, "usage: %s <binding> [params]\n", progname);
583 	fprintf(stderr, "Available bindings:\n");
584 	for (i = 0; i < ARRAY_SIZE(bindings); i++)
585 		fprintf(stderr, "  %s\n", bindings[i].name);
586 }
587 
main(int argc,char * const * argv)588 int main(int argc, char *const *argv)
589 {
590 	struct ctx *ctx, _ctx;
591 	int rc;
592 
593 	ctx = &_ctx;
594 	ctx->clients = NULL;
595 	ctx->n_clients = 0;
596 	ctx->local_eid = local_eid_default;
597 	ctx->verbose = false;
598 	ctx->pcap.binding.path = NULL;
599 	ctx->pcap.socket.path = NULL;
600 
601 	for (;;) {
602 		rc = getopt_long(argc, argv, "b:es::v", options, NULL);
603 		if (rc == -1)
604 			break;
605 		switch (rc) {
606 		case 'b':
607 			ctx->pcap.binding.path = optarg;
608 			break;
609 		case 's':
610 			ctx->pcap.socket.path = optarg;
611 			break;
612 		case 'B':
613 			fprintf(stderr,
614 				"binding-linktype argument is deprecated\n");
615 			break;
616 		case 'S':
617 			fprintf(stderr,
618 				"socket-linktype argument is deprecated\n");
619 			break;
620 		case 'v':
621 			ctx->verbose = true;
622 			break;
623 		case 'e':
624 			ctx->local_eid = atoi(optarg);
625 			break;
626 		default:
627 			fprintf(stderr, "Invalid argument\n");
628 			return EXIT_FAILURE;
629 		}
630 	}
631 
632 	if (optind >= argc) {
633 		fprintf(stderr, "missing binding argument\n");
634 		usage(argv[0]);
635 		return EXIT_FAILURE;
636 	}
637 
638 	/* setup initial buffer */
639 	ctx->buf_size = 4096;
640 	ctx->buf = malloc(ctx->buf_size);
641 
642 	mctp_set_log_stdio(ctx->verbose ? MCTP_LOG_DEBUG : MCTP_LOG_NOTICE);
643 
644 	ctx->mctp = mctp_init();
645 	assert(ctx->mctp);
646 
647 	if (ctx->pcap.binding.path || ctx->pcap.socket.path) {
648 		if (capture_init()) {
649 			rc = EXIT_FAILURE;
650 			goto cleanup_mctp;
651 		}
652 	}
653 
654 	if (ctx->pcap.binding.path) {
655 		rc = capture_prepare(&ctx->pcap.binding);
656 		if (rc == -1) {
657 			fprintf(stderr, "Failed to initialise capture: %d\n",
658 				rc);
659 			rc = EXIT_FAILURE;
660 			goto cleanup_mctp;
661 		}
662 
663 		mctp_set_capture_handler(ctx->mctp, capture_binding,
664 					 ctx->pcap.binding.dumper);
665 	}
666 
667 	if (ctx->pcap.socket.path) {
668 		rc = capture_prepare(&ctx->pcap.socket);
669 		if (rc == -1) {
670 			fprintf(stderr, "Failed to initialise capture: %d\n",
671 				rc);
672 			rc = EXIT_FAILURE;
673 			goto cleanup_pcap_binding;
674 		}
675 	}
676 
677 	rc = binding_init(ctx, argv[optind], argc - optind - 1,
678 			  argv + optind + 1);
679 	if (rc) {
680 		fprintf(stderr, "Failed to initialise binding: %d\n", rc);
681 		rc = EXIT_FAILURE;
682 		goto cleanup_pcap_socket;
683 	}
684 
685 	rc = sd_listen_fds(true);
686 	if (rc <= 0) {
687 		rc = socket_init(ctx);
688 		if (rc) {
689 			fprintf(stderr, "Failed to initialse socket: %d\n", rc);
690 			goto cleanup_binding;
691 		}
692 	} else {
693 		ctx->sock = SD_LISTEN_FDS_START;
694 	}
695 
696 	rc = run_daemon(ctx);
697 
698 cleanup_binding:
699 	binding_destroy(ctx);
700 
701 cleanup_pcap_socket:
702 	if (ctx->pcap.socket.path)
703 		capture_close(&ctx->pcap.socket);
704 
705 cleanup_pcap_binding:
706 	if (ctx->pcap.binding.path)
707 		capture_close(&ctx->pcap.binding);
708 
709 	rc = rc ? EXIT_FAILURE : EXIT_SUCCESS;
710 cleanup_mctp:
711 
712 	return rc;
713 }
714