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