xref: /openbmc/libmctp/utils/mctp-demux-daemon.c (revision edebe169)
13d36ee2eSJeremy Kerr /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
23d36ee2eSJeremy Kerr 
38e31cfd1SJeremy Kerr #define _GNU_SOURCE
48e31cfd1SJeremy Kerr 
5d4103f8fSAndrew Jeffery #include "config.h"
6cad47301SAndrew Jeffery #include "utils/mctp-capture.h"
7d4103f8fSAndrew Jeffery 
88e31cfd1SJeremy Kerr #include <assert.h>
98e31cfd1SJeremy Kerr #include <err.h>
106896d41eSAndrew Jeffery #include <errno.h>
118e31cfd1SJeremy Kerr #include <getopt.h>
12b93b6112SAndrew Jeffery #include <limits.h>
138e31cfd1SJeremy Kerr #include <poll.h>
14490e3873SAndrew Jeffery #include <signal.h>
1504b81fc7SAndrew Jeffery #include <stdbool.h>
168e31cfd1SJeremy Kerr #include <stdio.h>
178e31cfd1SJeremy Kerr #include <stdlib.h>
188e31cfd1SJeremy Kerr #include <string.h>
198e31cfd1SJeremy Kerr #include <unistd.h>
208e31cfd1SJeremy Kerr 
21490e3873SAndrew Jeffery #include <sys/signalfd.h>
228e31cfd1SJeremy Kerr #include <sys/socket.h>
238e31cfd1SJeremy Kerr #include <sys/un.h>
248e31cfd1SJeremy Kerr 
25d4103f8fSAndrew Jeffery #define SD_LISTEN_FDS_START 3
26d4103f8fSAndrew Jeffery 
278e31cfd1SJeremy Kerr #include "libmctp.h"
288e31cfd1SJeremy Kerr #include "libmctp-serial.h"
298e31cfd1SJeremy Kerr #include "libmctp-astlpc.h"
308e31cfd1SJeremy Kerr 
318e31cfd1SJeremy Kerr #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
3234b9b3d8SJeremy Kerr #define __unused __attribute__((unused))
338e31cfd1SJeremy Kerr 
34d4103f8fSAndrew Jeffery #if HAVE_SYSTEMD_SD_DAEMON_H
35d4103f8fSAndrew Jeffery #include <systemd/sd-daemon.h>
36d4103f8fSAndrew Jeffery #else
37d4103f8fSAndrew Jeffery static inline int sd_listen_fds(int i __unused)
38d4103f8fSAndrew Jeffery {
39d4103f8fSAndrew Jeffery 	return -1;
40d4103f8fSAndrew Jeffery }
41d4103f8fSAndrew Jeffery #endif
42d4103f8fSAndrew Jeffery 
438e31cfd1SJeremy Kerr static const mctp_eid_t local_eid_default = 8;
448e31cfd1SJeremy Kerr static char sockname[] = "\0mctp-mux";
458e31cfd1SJeremy Kerr 
468e31cfd1SJeremy Kerr struct binding {
478e31cfd1SJeremy Kerr 	const char	*name;
488e31cfd1SJeremy Kerr 	int		(*init)(struct mctp *mctp, struct binding *binding,
498e31cfd1SJeremy Kerr 				mctp_eid_t eid, int n_params,
508e31cfd1SJeremy Kerr 				char * const * params);
51*edebe169SAndrew Jeffery 	void		(*destroy)(struct mctp *mctp, struct binding *binding);
528e31cfd1SJeremy Kerr 	int		(*get_fd)(struct binding *binding);
538e31cfd1SJeremy Kerr 	int		(*process)(struct binding *binding);
548e31cfd1SJeremy Kerr 	void		*data;
558e31cfd1SJeremy Kerr };
568e31cfd1SJeremy Kerr 
578e31cfd1SJeremy Kerr struct client {
588e31cfd1SJeremy Kerr 	bool		active;
598e31cfd1SJeremy Kerr 	int		sock;
608e31cfd1SJeremy Kerr 	uint8_t		type;
618e31cfd1SJeremy Kerr };
628e31cfd1SJeremy Kerr 
638e31cfd1SJeremy Kerr struct ctx {
648e31cfd1SJeremy Kerr 	struct mctp	*mctp;
658e31cfd1SJeremy Kerr 	struct binding	*binding;
668e31cfd1SJeremy Kerr 	bool		verbose;
678e31cfd1SJeremy Kerr 	int		local_eid;
68f49b2ac8SJeremy Kerr 	void		*buf;
69f49b2ac8SJeremy Kerr 	size_t		buf_size;
708e31cfd1SJeremy Kerr 
718e31cfd1SJeremy Kerr 	int		sock;
728e31cfd1SJeremy Kerr 	struct pollfd	*pollfds;
738e31cfd1SJeremy Kerr 
748e31cfd1SJeremy Kerr 	struct client	*clients;
758e31cfd1SJeremy Kerr 	int		n_clients;
76cad47301SAndrew Jeffery 
77cad47301SAndrew Jeffery 	struct {
78cad47301SAndrew Jeffery 		struct capture binding;
79cad47301SAndrew Jeffery 		struct capture socket;
80cad47301SAndrew Jeffery 	} pcap;
818e31cfd1SJeremy Kerr };
828e31cfd1SJeremy Kerr 
838e31cfd1SJeremy Kerr static void tx_message(struct ctx *ctx, mctp_eid_t eid, void *msg, size_t len)
848e31cfd1SJeremy Kerr {
8506735055SAndrew Jeffery 	int rc;
8606735055SAndrew Jeffery 
8706735055SAndrew Jeffery 	rc = mctp_message_tx(ctx->mctp, eid, msg, len);
8806735055SAndrew Jeffery 	if (rc)
8906735055SAndrew Jeffery 		warnx("Failed to send message: %d", rc);
908e31cfd1SJeremy Kerr }
918e31cfd1SJeremy Kerr 
928e31cfd1SJeremy Kerr static void client_remove_inactive(struct ctx *ctx)
938e31cfd1SJeremy Kerr {
948e31cfd1SJeremy Kerr 	int i;
958e31cfd1SJeremy Kerr 
968e31cfd1SJeremy Kerr 	for (i = 0; i < ctx->n_clients; i++) {
978e31cfd1SJeremy Kerr 		struct client *client = &ctx->clients[i];
988e31cfd1SJeremy Kerr 		if (client->active)
998e31cfd1SJeremy Kerr 			continue;
1008e31cfd1SJeremy Kerr 		close(client->sock);
1018e31cfd1SJeremy Kerr 
1028e31cfd1SJeremy Kerr 		ctx->n_clients--;
1038e31cfd1SJeremy Kerr 		memmove(&ctx->clients[i], &ctx->clients[i+1],
1048e31cfd1SJeremy Kerr 				(ctx->n_clients - i) * sizeof(*ctx->clients));
1058e31cfd1SJeremy Kerr 		ctx->clients = realloc(ctx->clients,
1068e31cfd1SJeremy Kerr 				ctx->n_clients * sizeof(*ctx->clients));
1078e31cfd1SJeremy Kerr 	}
1088e31cfd1SJeremy Kerr }
1098e31cfd1SJeremy Kerr 
1108e31cfd1SJeremy Kerr static void rx_message(uint8_t eid, void *data, void *msg, size_t len)
1118e31cfd1SJeremy Kerr {
1128e31cfd1SJeremy Kerr 	struct ctx *ctx = data;
1138e31cfd1SJeremy Kerr 	struct iovec iov[2];
1148e31cfd1SJeremy Kerr 	struct msghdr msghdr;
1158e31cfd1SJeremy Kerr 	bool removed;
1168e31cfd1SJeremy Kerr 	uint8_t type;
1178e31cfd1SJeremy Kerr 	int i, rc;
1188e31cfd1SJeremy Kerr 
1198e31cfd1SJeremy Kerr 	if (len < 2)
1208e31cfd1SJeremy Kerr 		return;
1218e31cfd1SJeremy Kerr 
1228e31cfd1SJeremy Kerr 	type = *(uint8_t *)msg;
1238e31cfd1SJeremy Kerr 
1248e31cfd1SJeremy Kerr 	if (ctx->verbose)
1258e31cfd1SJeremy Kerr 		fprintf(stderr, "MCTP message received: len %zd, type %d\n",
1268e31cfd1SJeremy Kerr 				len, type);
1278e31cfd1SJeremy Kerr 
1288e31cfd1SJeremy Kerr 	memset(&msghdr, 0, sizeof(msghdr));
1298e31cfd1SJeremy Kerr 	msghdr.msg_iov = iov;
1308e31cfd1SJeremy Kerr 	msghdr.msg_iovlen = 2;
1318e31cfd1SJeremy Kerr 	iov[0].iov_base = &eid;
1328e31cfd1SJeremy Kerr 	iov[0].iov_len = 1;
1338e31cfd1SJeremy Kerr 	iov[1].iov_base = msg;
1348e31cfd1SJeremy Kerr 	iov[1].iov_len = len;
1358e31cfd1SJeremy Kerr 
1368e31cfd1SJeremy Kerr 	for (i = 0; i < ctx->n_clients; i++) {
1378e31cfd1SJeremy Kerr 		struct client *client = &ctx->clients[i];
1388e31cfd1SJeremy Kerr 
1398e31cfd1SJeremy Kerr 		if (client->type != type)
1408e31cfd1SJeremy Kerr 			continue;
1418e31cfd1SJeremy Kerr 
1428e31cfd1SJeremy Kerr 		if (ctx->verbose)
1438e31cfd1SJeremy Kerr 			fprintf(stderr, "  forwarding to client %d\n", i);
1448e31cfd1SJeremy Kerr 
1458e31cfd1SJeremy Kerr 		rc = sendmsg(client->sock, &msghdr, 0);
1468e31cfd1SJeremy Kerr 		if (rc != (ssize_t)(len + 1)) {
1478e31cfd1SJeremy Kerr 			client->active = false;
1488e31cfd1SJeremy Kerr 			removed = true;
1498e31cfd1SJeremy Kerr 		}
1508e31cfd1SJeremy Kerr 	}
1518e31cfd1SJeremy Kerr 
1528e31cfd1SJeremy Kerr 	if (removed)
1538e31cfd1SJeremy Kerr 		client_remove_inactive(ctx);
1548e31cfd1SJeremy Kerr 
1558e31cfd1SJeremy Kerr }
1568e31cfd1SJeremy Kerr 
15734b9b3d8SJeremy Kerr static int binding_null_init(struct mctp *mctp __unused,
15834b9b3d8SJeremy Kerr 		struct binding *binding __unused,
15934b9b3d8SJeremy Kerr 		mctp_eid_t eid __unused,
16034b9b3d8SJeremy Kerr 		int n_params, char * const *params __unused)
16134b9b3d8SJeremy Kerr {
16234b9b3d8SJeremy Kerr 	if (n_params != 0) {
16334b9b3d8SJeremy Kerr 		warnx("null binding doesn't accept parameters");
16434b9b3d8SJeremy Kerr 		return -1;
16534b9b3d8SJeremy Kerr 	}
16634b9b3d8SJeremy Kerr 	return 0;
16734b9b3d8SJeremy Kerr }
16834b9b3d8SJeremy Kerr 
1698e31cfd1SJeremy Kerr static int binding_serial_init(struct mctp *mctp, struct binding *binding,
1708e31cfd1SJeremy Kerr 		mctp_eid_t eid, int n_params, char * const *params)
1718e31cfd1SJeremy Kerr {
1728e31cfd1SJeremy Kerr 	struct mctp_binding_serial *serial;
1738e31cfd1SJeremy Kerr 	const char *path;
1748e31cfd1SJeremy Kerr 	int rc;
1758e31cfd1SJeremy Kerr 
1768e31cfd1SJeremy Kerr 	if (n_params != 1) {
1778e31cfd1SJeremy Kerr 		warnx("serial binding requires device param");
1788e31cfd1SJeremy Kerr 		return -1;
1798e31cfd1SJeremy Kerr 	}
1808e31cfd1SJeremy Kerr 
1818e31cfd1SJeremy Kerr 	path = params[0];
1828e31cfd1SJeremy Kerr 
1838e31cfd1SJeremy Kerr 	serial = mctp_serial_init();
1848e31cfd1SJeremy Kerr 	assert(serial);
1858e31cfd1SJeremy Kerr 
1868e31cfd1SJeremy Kerr 	rc = mctp_serial_open_path(serial, path);
1878e31cfd1SJeremy Kerr 	if (rc)
1888e31cfd1SJeremy Kerr 		return -1;
1898e31cfd1SJeremy Kerr 
1903b36d17cSJeremy Kerr 	mctp_register_bus(mctp, mctp_binding_serial_core(serial), eid);
1918e31cfd1SJeremy Kerr 
1928e31cfd1SJeremy Kerr 	binding->data = serial;
1938e31cfd1SJeremy Kerr 
1948e31cfd1SJeremy Kerr 	return 0;
1958e31cfd1SJeremy Kerr }
1968e31cfd1SJeremy Kerr 
1978e31cfd1SJeremy Kerr static int binding_serial_get_fd(struct binding *binding)
1988e31cfd1SJeremy Kerr {
1998e31cfd1SJeremy Kerr 	return mctp_serial_get_fd(binding->data);
2008e31cfd1SJeremy Kerr }
2018e31cfd1SJeremy Kerr 
2028e31cfd1SJeremy Kerr static int binding_serial_process(struct binding *binding)
2038e31cfd1SJeremy Kerr {
2048e31cfd1SJeremy Kerr 	return mctp_serial_read(binding->data);
2058e31cfd1SJeremy Kerr }
2068e31cfd1SJeremy Kerr 
2078e31cfd1SJeremy Kerr static int binding_astlpc_init(struct mctp *mctp, struct binding *binding,
2088e31cfd1SJeremy Kerr 		mctp_eid_t eid, int n_params,
2098e31cfd1SJeremy Kerr 		char * const *params __attribute__((unused)))
2108e31cfd1SJeremy Kerr {
2118e31cfd1SJeremy Kerr 	struct mctp_binding_astlpc *astlpc;
2128e31cfd1SJeremy Kerr 
2138e31cfd1SJeremy Kerr 	if (n_params) {
2148e31cfd1SJeremy Kerr 		warnx("astlpc binding does not accept parameters");
2158e31cfd1SJeremy Kerr 		return -1;
2168e31cfd1SJeremy Kerr 	}
2178e31cfd1SJeremy Kerr 
218bc53d35aSJeremy Kerr 	astlpc = mctp_astlpc_init_fileio();
2198e31cfd1SJeremy Kerr 	if (!astlpc) {
2208e31cfd1SJeremy Kerr 		warnx("could not initialise astlpc binding");
2218e31cfd1SJeremy Kerr 		return -1;
2228e31cfd1SJeremy Kerr 	}
2238e31cfd1SJeremy Kerr 
2243b36d17cSJeremy Kerr 	mctp_register_bus(mctp, mctp_binding_astlpc_core(astlpc), eid);
2253b36d17cSJeremy Kerr 
2268e31cfd1SJeremy Kerr 	binding->data = astlpc;
2278e31cfd1SJeremy Kerr 	return 0;
2288e31cfd1SJeremy Kerr }
2298e31cfd1SJeremy Kerr 
230*edebe169SAndrew Jeffery static void binding_astlpc_destroy(struct mctp *mctp, struct binding *binding)
231*edebe169SAndrew Jeffery {
232*edebe169SAndrew Jeffery 	struct mctp_binding_astlpc *astlpc = binding->data;
233*edebe169SAndrew Jeffery 
234*edebe169SAndrew Jeffery 	mctp_unregister_bus(mctp, mctp_binding_astlpc_core(astlpc));
235*edebe169SAndrew Jeffery 
236*edebe169SAndrew Jeffery 	mctp_astlpc_destroy(astlpc);
237*edebe169SAndrew Jeffery }
238*edebe169SAndrew Jeffery 
2398e31cfd1SJeremy Kerr static int binding_astlpc_get_fd(struct binding *binding)
2408e31cfd1SJeremy Kerr {
2418e31cfd1SJeremy Kerr 	return mctp_astlpc_get_fd(binding->data);
2428e31cfd1SJeremy Kerr }
2438e31cfd1SJeremy Kerr 
2448e31cfd1SJeremy Kerr static int binding_astlpc_process(struct binding *binding)
2458e31cfd1SJeremy Kerr {
2468e31cfd1SJeremy Kerr 	return mctp_astlpc_poll(binding->data);
2478e31cfd1SJeremy Kerr }
2488e31cfd1SJeremy Kerr 
2498e31cfd1SJeremy Kerr struct binding bindings[] = {
2508e31cfd1SJeremy Kerr 	{
25134b9b3d8SJeremy Kerr 		.name = "null",
25234b9b3d8SJeremy Kerr 		.init = binding_null_init,
25334b9b3d8SJeremy Kerr 	},
25434b9b3d8SJeremy Kerr 	{
2558e31cfd1SJeremy Kerr 		.name = "serial",
2568e31cfd1SJeremy Kerr 		.init = binding_serial_init,
257*edebe169SAndrew Jeffery 		.destroy = NULL,
2588e31cfd1SJeremy Kerr 		.get_fd = binding_serial_get_fd,
2598e31cfd1SJeremy Kerr 		.process = binding_serial_process,
2608e31cfd1SJeremy Kerr 	},
2618e31cfd1SJeremy Kerr 	{
2628e31cfd1SJeremy Kerr 		.name = "astlpc",
2638e31cfd1SJeremy Kerr 		.init = binding_astlpc_init,
264*edebe169SAndrew Jeffery 		.destroy = binding_astlpc_destroy,
2658e31cfd1SJeremy Kerr 		.get_fd = binding_astlpc_get_fd,
2668e31cfd1SJeremy Kerr 		.process = binding_astlpc_process,
2678e31cfd1SJeremy Kerr 	}
2688e31cfd1SJeremy Kerr };
2698e31cfd1SJeremy Kerr 
2708e31cfd1SJeremy Kerr struct binding *binding_lookup(const char *name)
2718e31cfd1SJeremy Kerr {
2728e31cfd1SJeremy Kerr 	struct binding *binding;
2738e31cfd1SJeremy Kerr 	unsigned int i;
2748e31cfd1SJeremy Kerr 
2758e31cfd1SJeremy Kerr 	for (i = 0; i < ARRAY_SIZE(bindings); i++) {
2768e31cfd1SJeremy Kerr 		binding = &bindings[i];
2778e31cfd1SJeremy Kerr 
2788e31cfd1SJeremy Kerr 		if (!strcmp(binding->name, name))
2798e31cfd1SJeremy Kerr 			return binding;
2808e31cfd1SJeremy Kerr 	}
2818e31cfd1SJeremy Kerr 
2828e31cfd1SJeremy Kerr 	return NULL;
2838e31cfd1SJeremy Kerr }
2848e31cfd1SJeremy Kerr 
2858e31cfd1SJeremy Kerr static int socket_init(struct ctx *ctx)
2868e31cfd1SJeremy Kerr {
2878e31cfd1SJeremy Kerr 	struct sockaddr_un addr;
2888e31cfd1SJeremy Kerr 	int namelen, rc;
2898e31cfd1SJeremy Kerr 
2908e31cfd1SJeremy Kerr 	namelen = sizeof(sockname) - 1;
2918e31cfd1SJeremy Kerr 	addr.sun_family = AF_UNIX;
2928e31cfd1SJeremy Kerr 	memcpy(addr.sun_path, sockname, namelen);
2938e31cfd1SJeremy Kerr 
2948e31cfd1SJeremy Kerr 	ctx->sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
2958e31cfd1SJeremy Kerr 	if (ctx->sock < 0) {
2968e31cfd1SJeremy Kerr 		warn("can't create socket");
2978e31cfd1SJeremy Kerr 		return -1;
2988e31cfd1SJeremy Kerr 	}
2998e31cfd1SJeremy Kerr 
3008e31cfd1SJeremy Kerr 	rc = bind(ctx->sock, (struct sockaddr *)&addr,
3018e31cfd1SJeremy Kerr 			sizeof(addr.sun_family) + namelen);
3028e31cfd1SJeremy Kerr 	if (rc) {
3038e31cfd1SJeremy Kerr 		warn("can't bind socket");
3048e31cfd1SJeremy Kerr 		goto err_close;
3058e31cfd1SJeremy Kerr 	}
3068e31cfd1SJeremy Kerr 
3078e31cfd1SJeremy Kerr 	rc = listen(ctx->sock, 1);
3088e31cfd1SJeremy Kerr 	if (rc) {
3098e31cfd1SJeremy Kerr 		warn("can't listen on socket");
3108e31cfd1SJeremy Kerr 		goto err_close;
3118e31cfd1SJeremy Kerr 	}
3128e31cfd1SJeremy Kerr 
3138e31cfd1SJeremy Kerr 	return 0;
3148e31cfd1SJeremy Kerr 
3158e31cfd1SJeremy Kerr err_close:
3168e31cfd1SJeremy Kerr 	close(ctx->sock);
3178e31cfd1SJeremy Kerr 	return -1;
3188e31cfd1SJeremy Kerr }
3198e31cfd1SJeremy Kerr 
3208e31cfd1SJeremy Kerr static int socket_process(struct ctx *ctx)
3218e31cfd1SJeremy Kerr {
3228e31cfd1SJeremy Kerr 	struct client *client;
3238e31cfd1SJeremy Kerr 	int fd;
3248e31cfd1SJeremy Kerr 
3258e31cfd1SJeremy Kerr 	fd = accept4(ctx->sock, NULL, 0, SOCK_NONBLOCK);
3268e31cfd1SJeremy Kerr 	if (fd < 0)
3278e31cfd1SJeremy Kerr 		return -1;
3288e31cfd1SJeremy Kerr 
3298e31cfd1SJeremy Kerr 	ctx->n_clients++;
3308e31cfd1SJeremy Kerr 	ctx->clients = realloc(ctx->clients,
3318e31cfd1SJeremy Kerr 			ctx->n_clients * sizeof(struct client));
3328e31cfd1SJeremy Kerr 
3338e31cfd1SJeremy Kerr 	client = &ctx->clients[ctx->n_clients-1];
3348676c934SAndrew Jeffery 	memset(client, 0, sizeof(*client));
3358e31cfd1SJeremy Kerr 	client->active = true;
3368e31cfd1SJeremy Kerr 	client->sock = fd;
3378e31cfd1SJeremy Kerr 
3388e31cfd1SJeremy Kerr 	return 0;
3398e31cfd1SJeremy Kerr }
3408e31cfd1SJeremy Kerr 
3418e31cfd1SJeremy Kerr static int client_process_recv(struct ctx *ctx, int idx)
3428e31cfd1SJeremy Kerr {
3438e31cfd1SJeremy Kerr 	struct client *client = &ctx->clients[idx];
344f49b2ac8SJeremy Kerr 	uint8_t eid;
345f49b2ac8SJeremy Kerr 	ssize_t len;
3468e31cfd1SJeremy Kerr 	int rc;
3478e31cfd1SJeremy Kerr 
3488e31cfd1SJeremy Kerr 	/* are we waiting for a type message? */
3498e31cfd1SJeremy Kerr 	if (!client->type) {
3508e31cfd1SJeremy Kerr 		uint8_t type;
3518e31cfd1SJeremy Kerr 		rc = read(client->sock, &type, 1);
3528e31cfd1SJeremy Kerr 		if (rc <= 0)
3538e31cfd1SJeremy Kerr 			goto out_close;
3548e31cfd1SJeremy Kerr 
3558e31cfd1SJeremy Kerr 		if (type == 0) {
3568e31cfd1SJeremy Kerr 			rc = -1;
3578e31cfd1SJeremy Kerr 			goto out_close;
3588e31cfd1SJeremy Kerr 		}
3598e31cfd1SJeremy Kerr 		if (ctx->verbose)
3608e31cfd1SJeremy Kerr 			fprintf(stderr, "client[%d] registered for type %u\n",
3618e31cfd1SJeremy Kerr 					idx, type);
3628e31cfd1SJeremy Kerr 		client->type = type;
3638e31cfd1SJeremy Kerr 		return 0;
3648e31cfd1SJeremy Kerr 	}
3658e31cfd1SJeremy Kerr 
366f49b2ac8SJeremy Kerr 	len = recv(client->sock, NULL, 0, MSG_PEEK | MSG_TRUNC);
367f49b2ac8SJeremy Kerr 	if (len < 0) {
3686896d41eSAndrew Jeffery 		if (errno != ECONNRESET)
369f49b2ac8SJeremy Kerr 			warn("can't receive (peek) from client");
3706896d41eSAndrew Jeffery 
37113a4041fSAndrew Jeffery 		rc = -1;
372f49b2ac8SJeremy Kerr 		goto out_close;
373f49b2ac8SJeremy Kerr 	}
374f49b2ac8SJeremy Kerr 
375b93b6112SAndrew Jeffery 	if ((size_t)len > ctx->buf_size) {
376f49b2ac8SJeremy Kerr 		void *tmp;
377f49b2ac8SJeremy Kerr 
378f49b2ac8SJeremy Kerr 		tmp = realloc(ctx->buf, len);
379f49b2ac8SJeremy Kerr 		if (!tmp) {
380f49b2ac8SJeremy Kerr 			warn("can't allocate for incoming message");
38113a4041fSAndrew Jeffery 			rc = -1;
382f49b2ac8SJeremy Kerr 			goto out_close;
383f49b2ac8SJeremy Kerr 		}
384f49b2ac8SJeremy Kerr 		ctx->buf = tmp;
385f49b2ac8SJeremy Kerr 		ctx->buf_size = len;
386f49b2ac8SJeremy Kerr 	}
387f49b2ac8SJeremy Kerr 
388f49b2ac8SJeremy Kerr 	rc = recv(client->sock, ctx->buf, ctx->buf_size, 0);
3898e31cfd1SJeremy Kerr 	if (rc < 0) {
3906896d41eSAndrew Jeffery 		if (errno != ECONNRESET)
3918e31cfd1SJeremy Kerr 			warn("can't receive from client");
39213a4041fSAndrew Jeffery 		rc = -1;
3938e31cfd1SJeremy Kerr 		goto out_close;
3948e31cfd1SJeremy Kerr 	}
3958e31cfd1SJeremy Kerr 
396195a7c5eSJeremy Kerr 	if (rc <= 0) {
3978e31cfd1SJeremy Kerr 		rc = -1;
3988e31cfd1SJeremy Kerr 		goto out_close;
3998e31cfd1SJeremy Kerr 	}
4008e31cfd1SJeremy Kerr 
401cad47301SAndrew Jeffery 	if (ctx->pcap.socket.path)
402cad47301SAndrew Jeffery 		capture_socket(ctx->pcap.socket.dumper, ctx->buf, rc);
403cad47301SAndrew Jeffery 
404f49b2ac8SJeremy Kerr 	eid = *(uint8_t *)ctx->buf;
405d690d8eaSJeremy Kerr 
4068e31cfd1SJeremy Kerr 	if (ctx->verbose)
4078e31cfd1SJeremy Kerr 		fprintf(stderr,
4088e31cfd1SJeremy Kerr 			"client[%d] sent message: dest 0x%02x len %d\n",
4098e31cfd1SJeremy Kerr 			idx, eid, rc - 1);
4108e31cfd1SJeremy Kerr 
411195a7c5eSJeremy Kerr 
412195a7c5eSJeremy Kerr 	if (eid == ctx->local_eid)
413f49b2ac8SJeremy Kerr 		rx_message(eid, ctx, ctx->buf + 1, rc - 1);
414195a7c5eSJeremy Kerr 	else
415f49b2ac8SJeremy Kerr 		tx_message(ctx, eid, ctx->buf + 1, rc - 1);
4168e31cfd1SJeremy Kerr 
4178e31cfd1SJeremy Kerr 	return 0;
4188e31cfd1SJeremy Kerr 
4198e31cfd1SJeremy Kerr out_close:
4208e31cfd1SJeremy Kerr 	client->active = false;
4218e31cfd1SJeremy Kerr 	return rc;
4228e31cfd1SJeremy Kerr }
4238e31cfd1SJeremy Kerr 
4248e31cfd1SJeremy Kerr static int binding_init(struct ctx *ctx, const char *name,
4258e31cfd1SJeremy Kerr 		int argc, char * const *argv)
4268e31cfd1SJeremy Kerr {
4278e31cfd1SJeremy Kerr 	int rc;
4288e31cfd1SJeremy Kerr 
4298e31cfd1SJeremy Kerr 	ctx->binding = binding_lookup(name);
4308e31cfd1SJeremy Kerr 	if (!ctx->binding) {
4318e31cfd1SJeremy Kerr 		warnx("no such binding '%s'", name);
4328e31cfd1SJeremy Kerr 		return -1;
4338e31cfd1SJeremy Kerr 	}
4348e31cfd1SJeremy Kerr 
4358e31cfd1SJeremy Kerr 	rc = ctx->binding->init(ctx->mctp, ctx->binding, ctx->local_eid,
4368e31cfd1SJeremy Kerr 			argc, argv);
4378e31cfd1SJeremy Kerr 	return rc;
4388e31cfd1SJeremy Kerr }
4398e31cfd1SJeremy Kerr 
440*edebe169SAndrew Jeffery static void binding_destroy(struct ctx *ctx)
441*edebe169SAndrew Jeffery {
442*edebe169SAndrew Jeffery 	if (ctx->binding->destroy)
443*edebe169SAndrew Jeffery 		ctx->binding->destroy(ctx->mctp, ctx->binding);
444*edebe169SAndrew Jeffery }
445*edebe169SAndrew Jeffery 
4468e31cfd1SJeremy Kerr enum {
4478e31cfd1SJeremy Kerr 	FD_BINDING = 0,
4488e31cfd1SJeremy Kerr 	FD_SOCKET,
449490e3873SAndrew Jeffery 	FD_SIGNAL,
4508e31cfd1SJeremy Kerr 	FD_NR,
4518e31cfd1SJeremy Kerr };
4528e31cfd1SJeremy Kerr 
4538e31cfd1SJeremy Kerr static int run_daemon(struct ctx *ctx)
4548e31cfd1SJeremy Kerr {
4558e31cfd1SJeremy Kerr 	bool clients_changed = false;
456490e3873SAndrew Jeffery 	sigset_t mask;
4578e31cfd1SJeremy Kerr 	int rc, i;
4588e31cfd1SJeremy Kerr 
4598e31cfd1SJeremy Kerr 	ctx->pollfds = malloc(FD_NR * sizeof(struct pollfd));
4608e31cfd1SJeremy Kerr 
46134b9b3d8SJeremy Kerr 	if (ctx->binding->get_fd) {
4628e31cfd1SJeremy Kerr 		ctx->pollfds[FD_BINDING].fd =
4638e31cfd1SJeremy Kerr 			ctx->binding->get_fd(ctx->binding);
4648e31cfd1SJeremy Kerr 		ctx->pollfds[FD_BINDING].events = POLLIN;
46534b9b3d8SJeremy Kerr 	} else {
46634b9b3d8SJeremy Kerr 		ctx->pollfds[FD_BINDING].fd = -1;
46734b9b3d8SJeremy Kerr 		ctx->pollfds[FD_BINDING].events = 0;
46834b9b3d8SJeremy Kerr 	}
4698e31cfd1SJeremy Kerr 
470490e3873SAndrew Jeffery 	sigemptyset(&mask);
471490e3873SAndrew Jeffery 	sigaddset(&mask, SIGINT);
472490e3873SAndrew Jeffery 	sigaddset(&mask, SIGTERM);
473490e3873SAndrew Jeffery 	sigaddset(&mask, SIGQUIT);
474490e3873SAndrew Jeffery 
475490e3873SAndrew Jeffery 	if ((rc = sigprocmask(SIG_BLOCK, &mask, NULL)) == -1) {
476490e3873SAndrew Jeffery 		warn("sigprocmask");
477490e3873SAndrew Jeffery 		return rc;
478490e3873SAndrew Jeffery 	}
479490e3873SAndrew Jeffery 
480490e3873SAndrew Jeffery 	ctx->pollfds[FD_SIGNAL].fd = signalfd(-1, &mask, 0);
481490e3873SAndrew Jeffery 	ctx->pollfds[FD_SIGNAL].events = POLLIN;
482490e3873SAndrew Jeffery 
4838e31cfd1SJeremy Kerr 	ctx->pollfds[FD_SOCKET].fd = ctx->sock;
4848e31cfd1SJeremy Kerr 	ctx->pollfds[FD_SOCKET].events = POLLIN;
4858e31cfd1SJeremy Kerr 
4868e31cfd1SJeremy Kerr 	mctp_set_rx_all(ctx->mctp, rx_message, ctx);
4878e31cfd1SJeremy Kerr 
4888e31cfd1SJeremy Kerr 	for (;;) {
4898e31cfd1SJeremy Kerr 		if (clients_changed) {
4908e31cfd1SJeremy Kerr 			int i;
4918e31cfd1SJeremy Kerr 
4928e31cfd1SJeremy Kerr 			ctx->pollfds = realloc(ctx->pollfds,
4938e31cfd1SJeremy Kerr 					(ctx->n_clients + FD_NR) *
4948e31cfd1SJeremy Kerr 						sizeof(struct pollfd));
4958e31cfd1SJeremy Kerr 
4968e31cfd1SJeremy Kerr 			for (i = 0; i < ctx->n_clients; i++) {
4978e31cfd1SJeremy Kerr 				ctx->pollfds[FD_NR+i].fd =
4988e31cfd1SJeremy Kerr 					ctx->clients[i].sock;
4998e31cfd1SJeremy Kerr 				ctx->pollfds[FD_NR+i].events = POLLIN;
5008e31cfd1SJeremy Kerr 			}
5018e31cfd1SJeremy Kerr 			clients_changed = false;
5028e31cfd1SJeremy Kerr 		}
5038e31cfd1SJeremy Kerr 
5048e31cfd1SJeremy Kerr 		rc = poll(ctx->pollfds, ctx->n_clients + FD_NR, -1);
5058e31cfd1SJeremy Kerr 		if (rc < 0) {
5068e31cfd1SJeremy Kerr 			warn("poll failed");
5078e31cfd1SJeremy Kerr 			break;
5088e31cfd1SJeremy Kerr 		}
5098e31cfd1SJeremy Kerr 
5108e31cfd1SJeremy Kerr 		if (!rc)
5118e31cfd1SJeremy Kerr 			continue;
5128e31cfd1SJeremy Kerr 
513490e3873SAndrew Jeffery 		if (ctx->pollfds[FD_SIGNAL].revents) {
514490e3873SAndrew Jeffery 			struct signalfd_siginfo si;
515490e3873SAndrew Jeffery 			ssize_t got;
516490e3873SAndrew Jeffery 
517490e3873SAndrew Jeffery 			got = read(ctx->pollfds[FD_SIGNAL].fd, &si, sizeof(si));
518490e3873SAndrew Jeffery 			if (got == sizeof(si)) {
519490e3873SAndrew Jeffery 				warnx("Received %s, quitting",
520490e3873SAndrew Jeffery 				      strsignal(si.ssi_signo));
521490e3873SAndrew Jeffery 				rc = 0;
522490e3873SAndrew Jeffery 				break;
523490e3873SAndrew Jeffery 			} else {
524490e3873SAndrew Jeffery 				warnx("Unexpected read result for signalfd: %d",
525490e3873SAndrew Jeffery 				      rc);
526490e3873SAndrew Jeffery 				warnx("Quitting on the basis that signalfd became ready");
527490e3873SAndrew Jeffery 				rc = -1;
528490e3873SAndrew Jeffery 				break;
529490e3873SAndrew Jeffery 			}
530490e3873SAndrew Jeffery 		}
531490e3873SAndrew Jeffery 
5328e31cfd1SJeremy Kerr 		if (ctx->pollfds[FD_BINDING].revents) {
53334b9b3d8SJeremy Kerr 			rc = 0;
53434b9b3d8SJeremy Kerr 			if (ctx->binding->process)
5358e31cfd1SJeremy Kerr 				rc = ctx->binding->process(ctx->binding);
5368e31cfd1SJeremy Kerr 			if (rc)
5378e31cfd1SJeremy Kerr 				break;
5388e31cfd1SJeremy Kerr 		}
5398e31cfd1SJeremy Kerr 
5408e31cfd1SJeremy Kerr 		for (i = 0; i < ctx->n_clients; i++) {
5418e31cfd1SJeremy Kerr 			if (!ctx->pollfds[FD_NR+i].revents)
5428e31cfd1SJeremy Kerr 				continue;
5438e31cfd1SJeremy Kerr 
5448e31cfd1SJeremy Kerr 			rc = client_process_recv(ctx, i);
5458e31cfd1SJeremy Kerr 			if (rc)
5468e31cfd1SJeremy Kerr 				clients_changed = true;
5478e31cfd1SJeremy Kerr 		}
5488e31cfd1SJeremy Kerr 
5498e31cfd1SJeremy Kerr 		if (ctx->pollfds[FD_SOCKET].revents) {
5508e31cfd1SJeremy Kerr 			rc = socket_process(ctx);
5518e31cfd1SJeremy Kerr 			if (rc)
5528e31cfd1SJeremy Kerr 				break;
5538e31cfd1SJeremy Kerr 			clients_changed = true;
5548e31cfd1SJeremy Kerr 		}
5558e31cfd1SJeremy Kerr 
5568e31cfd1SJeremy Kerr 		if (clients_changed)
5578e31cfd1SJeremy Kerr 			client_remove_inactive(ctx);
5588e31cfd1SJeremy Kerr 	}
5598e31cfd1SJeremy Kerr 
5608e31cfd1SJeremy Kerr 
5618e31cfd1SJeremy Kerr 	free(ctx->pollfds);
5628e31cfd1SJeremy Kerr 
5638e31cfd1SJeremy Kerr 	return rc;
5648e31cfd1SJeremy Kerr }
5658e31cfd1SJeremy Kerr 
5668e31cfd1SJeremy Kerr static const struct option options[] = {
567cad47301SAndrew Jeffery 	{ "capture-binding", required_argument, 0, 'b' },
568cad47301SAndrew Jeffery 	{ "capture-socket", required_argument, 0, 's' },
569cad47301SAndrew Jeffery 	{ "binding-linktype", required_argument, 0, 'B' },
570cad47301SAndrew Jeffery 	{ "socket-linktype", required_argument, 0, 'S' },
5718e31cfd1SJeremy Kerr 	{ "verbose", no_argument, 0, 'v' },
5728e31cfd1SJeremy Kerr 	{ "eid", required_argument, 0, 'e' },
5738e31cfd1SJeremy Kerr 	{ 0 },
5748e31cfd1SJeremy Kerr };
5758e31cfd1SJeremy Kerr 
5768e31cfd1SJeremy Kerr static void usage(const char *progname)
5778e31cfd1SJeremy Kerr {
5788e31cfd1SJeremy Kerr 	unsigned int i;
5798e31cfd1SJeremy Kerr 
5808e31cfd1SJeremy Kerr 	fprintf(stderr, "usage: %s <binding> [params]\n", progname);
5818e31cfd1SJeremy Kerr 	fprintf(stderr, "Available bindings:\n");
5828e31cfd1SJeremy Kerr 	for (i = 0; i < ARRAY_SIZE(bindings); i++)
5838e31cfd1SJeremy Kerr 		fprintf(stderr, "  %s\n", bindings[i].name);
5848e31cfd1SJeremy Kerr }
5858e31cfd1SJeremy Kerr 
5868e31cfd1SJeremy Kerr int main(int argc, char * const *argv)
5878e31cfd1SJeremy Kerr {
5888e31cfd1SJeremy Kerr 	struct ctx *ctx, _ctx;
5898e31cfd1SJeremy Kerr 	int rc;
5908e31cfd1SJeremy Kerr 
5918e31cfd1SJeremy Kerr 	ctx = &_ctx;
5928e31cfd1SJeremy Kerr 	ctx->clients = NULL;
5938e31cfd1SJeremy Kerr 	ctx->n_clients = 0;
5948e31cfd1SJeremy Kerr 	ctx->local_eid = local_eid_default;
59504b81fc7SAndrew Jeffery 	ctx->verbose = false;
596cad47301SAndrew Jeffery 	ctx->pcap.binding.path = NULL;
597cad47301SAndrew Jeffery 	ctx->pcap.socket.path = NULL;
5988e31cfd1SJeremy Kerr 
5998e31cfd1SJeremy Kerr 	for (;;) {
600cad47301SAndrew Jeffery 		rc = getopt_long(argc, argv, "b:es::v", options, NULL);
6018e31cfd1SJeremy Kerr 		if (rc == -1)
6028e31cfd1SJeremy Kerr 			break;
6038e31cfd1SJeremy Kerr 		switch (rc) {
604cad47301SAndrew Jeffery 		case 'b':
605cad47301SAndrew Jeffery 			ctx->pcap.binding.path = optarg;
606cad47301SAndrew Jeffery 			break;
607cad47301SAndrew Jeffery 		case 's':
608cad47301SAndrew Jeffery 			ctx->pcap.socket.path = optarg;
609cad47301SAndrew Jeffery 			break;
610cad47301SAndrew Jeffery 		case 'B':
611cad47301SAndrew Jeffery 			ctx->pcap.binding.linktype = atoi(optarg);
612cad47301SAndrew Jeffery 			break;
613cad47301SAndrew Jeffery 		case 'S':
614cad47301SAndrew Jeffery 			ctx->pcap.socket.linktype = atoi(optarg);
615cad47301SAndrew Jeffery 			break;
6168e31cfd1SJeremy Kerr 		case 'v':
6178e31cfd1SJeremy Kerr 			ctx->verbose = true;
6188e31cfd1SJeremy Kerr 			break;
6198e31cfd1SJeremy Kerr 		case 'e':
6208e31cfd1SJeremy Kerr 			ctx->local_eid = atoi(optarg);
6218e31cfd1SJeremy Kerr 			break;
6228e31cfd1SJeremy Kerr 		default:
6238e31cfd1SJeremy Kerr 			fprintf(stderr, "Invalid argument\n");
6248e31cfd1SJeremy Kerr 			return EXIT_FAILURE;
6258e31cfd1SJeremy Kerr 		}
6268e31cfd1SJeremy Kerr 	}
6278e31cfd1SJeremy Kerr 
6288e31cfd1SJeremy Kerr 	if (optind >= argc) {
6298e31cfd1SJeremy Kerr 		fprintf(stderr, "missing binding argument\n");
6308e31cfd1SJeremy Kerr 		usage(argv[0]);
6318e31cfd1SJeremy Kerr 		return EXIT_FAILURE;
6328e31cfd1SJeremy Kerr 	}
6338e31cfd1SJeremy Kerr 
634f49b2ac8SJeremy Kerr 	/* setup initial buffer */
635f49b2ac8SJeremy Kerr 	ctx->buf_size = 4096;
636f49b2ac8SJeremy Kerr 	ctx->buf = malloc(ctx->buf_size);
637f49b2ac8SJeremy Kerr 
6380b278a63SJeremy Kerr 	mctp_set_log_stdio(ctx->verbose ? MCTP_LOG_DEBUG : MCTP_LOG_WARNING);
6390b278a63SJeremy Kerr 
6408e31cfd1SJeremy Kerr 	ctx->mctp = mctp_init();
6418e31cfd1SJeremy Kerr 	assert(ctx->mctp);
6428e31cfd1SJeremy Kerr 
643cad47301SAndrew Jeffery 	if (ctx->pcap.binding.path || ctx->pcap.socket.path) {
644cad47301SAndrew Jeffery 		if (capture_init()) {
645cad47301SAndrew Jeffery 			rc = EXIT_FAILURE;
646cad47301SAndrew Jeffery 			goto cleanup_mctp;
647cad47301SAndrew Jeffery 		}
648cad47301SAndrew Jeffery 	}
649cad47301SAndrew Jeffery 
650cad47301SAndrew Jeffery 	if (ctx->pcap.binding.path) {
651cad47301SAndrew Jeffery 		rc = capture_prepare(&ctx->pcap.binding);
652cad47301SAndrew Jeffery 		if (rc == -1) {
653cad47301SAndrew Jeffery 			fprintf(stderr, "Failed to initialise capture: %d\n", rc);
654cad47301SAndrew Jeffery 			rc = EXIT_FAILURE;
655cad47301SAndrew Jeffery 			goto cleanup_mctp;
656cad47301SAndrew Jeffery 		}
657cad47301SAndrew Jeffery 
658cad47301SAndrew Jeffery 		mctp_set_capture_handler(ctx->mctp, capture_binding,
659cad47301SAndrew Jeffery 					 ctx->pcap.binding.dumper);
660cad47301SAndrew Jeffery 	}
661cad47301SAndrew Jeffery 
662cad47301SAndrew Jeffery 	if (ctx->pcap.socket.path) {
663cad47301SAndrew Jeffery 		rc = capture_prepare(&ctx->pcap.socket);
664cad47301SAndrew Jeffery 		if (rc == -1) {
665cad47301SAndrew Jeffery 			fprintf(stderr, "Failed to initialise capture: %d\n", rc);
666cad47301SAndrew Jeffery 			rc = EXIT_FAILURE;
667cad47301SAndrew Jeffery 			goto cleanup_pcap_binding;
668cad47301SAndrew Jeffery 		}
669cad47301SAndrew Jeffery 	}
670cad47301SAndrew Jeffery 
6718e31cfd1SJeremy Kerr 	rc = binding_init(ctx, argv[optind], argc - optind - 1, argv + optind + 1);
672cad47301SAndrew Jeffery 	if (rc) {
673cad47301SAndrew Jeffery 		fprintf(stderr, "Failed to initialise binding: %d\n", rc);
674cad47301SAndrew Jeffery 		rc = EXIT_FAILURE;
675cad47301SAndrew Jeffery 		goto cleanup_pcap_socket;
676cad47301SAndrew Jeffery 	}
6778e31cfd1SJeremy Kerr 
678d4103f8fSAndrew Jeffery 	rc = sd_listen_fds(true);
679d4103f8fSAndrew Jeffery 	if (rc <= 0) {
6808e31cfd1SJeremy Kerr 		rc = socket_init(ctx);
681cad47301SAndrew Jeffery 		if (rc) {
682cad47301SAndrew Jeffery 			fprintf(stderr, "Failed to initialse socket: %d\n", rc);
683*edebe169SAndrew Jeffery 			goto cleanup_binding;
684cad47301SAndrew Jeffery 		}
685d4103f8fSAndrew Jeffery 	} else {
686d4103f8fSAndrew Jeffery 		ctx->sock = SD_LISTEN_FDS_START;
687d4103f8fSAndrew Jeffery 	}
6888e31cfd1SJeremy Kerr 
6898e31cfd1SJeremy Kerr 	rc = run_daemon(ctx);
6908e31cfd1SJeremy Kerr 
691*edebe169SAndrew Jeffery cleanup_binding:
692*edebe169SAndrew Jeffery 	binding_destroy(ctx);
693*edebe169SAndrew Jeffery 
694cad47301SAndrew Jeffery cleanup_pcap_socket:
695cad47301SAndrew Jeffery 	if (ctx->pcap.socket.path)
696cad47301SAndrew Jeffery 		capture_close(&ctx->pcap.socket);
697cad47301SAndrew Jeffery 
698cad47301SAndrew Jeffery cleanup_pcap_binding:
699cad47301SAndrew Jeffery 	if (ctx->pcap.binding.path)
700cad47301SAndrew Jeffery 		capture_close(&ctx->pcap.binding);
701cad47301SAndrew Jeffery 
702cad47301SAndrew Jeffery 	rc = rc ? EXIT_FAILURE : EXIT_SUCCESS;
703cad47301SAndrew Jeffery cleanup_mctp:
704cad47301SAndrew Jeffery 
705cad47301SAndrew Jeffery 	return rc;
7068e31cfd1SJeremy Kerr 
7078e31cfd1SJeremy Kerr }
708