xref: /openbmc/libmctp/utils/mctp-demux-daemon.c (revision 06735055)
13d36ee2eSJeremy Kerr /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
23d36ee2eSJeremy Kerr 
38e31cfd1SJeremy Kerr #define _GNU_SOURCE
48e31cfd1SJeremy Kerr 
58e31cfd1SJeremy Kerr #include <assert.h>
68e31cfd1SJeremy Kerr #include <err.h>
76896d41eSAndrew Jeffery #include <errno.h>
88e31cfd1SJeremy Kerr #include <getopt.h>
9b93b6112SAndrew Jeffery #include <limits.h>
108e31cfd1SJeremy Kerr #include <poll.h>
1104b81fc7SAndrew Jeffery #include <stdbool.h>
128e31cfd1SJeremy Kerr #include <stdio.h>
138e31cfd1SJeremy Kerr #include <stdlib.h>
148e31cfd1SJeremy Kerr #include <string.h>
158e31cfd1SJeremy Kerr #include <unistd.h>
168e31cfd1SJeremy Kerr 
178e31cfd1SJeremy Kerr #include <sys/socket.h>
188e31cfd1SJeremy Kerr #include <sys/un.h>
198e31cfd1SJeremy Kerr 
208e31cfd1SJeremy Kerr #include "libmctp.h"
218e31cfd1SJeremy Kerr #include "libmctp-serial.h"
228e31cfd1SJeremy Kerr #include "libmctp-astlpc.h"
238e31cfd1SJeremy Kerr 
248e31cfd1SJeremy Kerr #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
2534b9b3d8SJeremy Kerr #define __unused __attribute__((unused))
268e31cfd1SJeremy Kerr 
278e31cfd1SJeremy Kerr static const mctp_eid_t local_eid_default = 8;
288e31cfd1SJeremy Kerr static char sockname[] = "\0mctp-mux";
298e31cfd1SJeremy Kerr 
308e31cfd1SJeremy Kerr struct binding {
318e31cfd1SJeremy Kerr 	const char	*name;
328e31cfd1SJeremy Kerr 	int		(*init)(struct mctp *mctp, struct binding *binding,
338e31cfd1SJeremy Kerr 				mctp_eid_t eid, int n_params,
348e31cfd1SJeremy Kerr 				char * const * params);
358e31cfd1SJeremy Kerr 	int		(*get_fd)(struct binding *binding);
368e31cfd1SJeremy Kerr 	int		(*process)(struct binding *binding);
378e31cfd1SJeremy Kerr 	void		*data;
388e31cfd1SJeremy Kerr };
398e31cfd1SJeremy Kerr 
408e31cfd1SJeremy Kerr struct client {
418e31cfd1SJeremy Kerr 	bool		active;
428e31cfd1SJeremy Kerr 	int		sock;
438e31cfd1SJeremy Kerr 	uint8_t		type;
448e31cfd1SJeremy Kerr };
458e31cfd1SJeremy Kerr 
468e31cfd1SJeremy Kerr struct ctx {
478e31cfd1SJeremy Kerr 	struct mctp	*mctp;
488e31cfd1SJeremy Kerr 	struct binding	*binding;
498e31cfd1SJeremy Kerr 	bool		verbose;
508e31cfd1SJeremy Kerr 	int		local_eid;
51f49b2ac8SJeremy Kerr 	void		*buf;
52f49b2ac8SJeremy Kerr 	size_t		buf_size;
538e31cfd1SJeremy Kerr 
548e31cfd1SJeremy Kerr 	int		sock;
558e31cfd1SJeremy Kerr 	struct pollfd	*pollfds;
568e31cfd1SJeremy Kerr 
578e31cfd1SJeremy Kerr 	struct client	*clients;
588e31cfd1SJeremy Kerr 	int		n_clients;
598e31cfd1SJeremy Kerr };
608e31cfd1SJeremy Kerr 
618e31cfd1SJeremy Kerr static void tx_message(struct ctx *ctx, mctp_eid_t eid, void *msg, size_t len)
628e31cfd1SJeremy Kerr {
63*06735055SAndrew Jeffery 	int rc;
64*06735055SAndrew Jeffery 
65*06735055SAndrew Jeffery 	rc = mctp_message_tx(ctx->mctp, eid, msg, len);
66*06735055SAndrew Jeffery 	if (rc)
67*06735055SAndrew Jeffery 		warnx("Failed to send message: %d", rc);
688e31cfd1SJeremy Kerr }
698e31cfd1SJeremy Kerr 
708e31cfd1SJeremy Kerr static void client_remove_inactive(struct ctx *ctx)
718e31cfd1SJeremy Kerr {
728e31cfd1SJeremy Kerr 	int i;
738e31cfd1SJeremy Kerr 
748e31cfd1SJeremy Kerr 	for (i = 0; i < ctx->n_clients; i++) {
758e31cfd1SJeremy Kerr 		struct client *client = &ctx->clients[i];
768e31cfd1SJeremy Kerr 		if (client->active)
778e31cfd1SJeremy Kerr 			continue;
788e31cfd1SJeremy Kerr 		close(client->sock);
798e31cfd1SJeremy Kerr 
808e31cfd1SJeremy Kerr 		ctx->n_clients--;
818e31cfd1SJeremy Kerr 		memmove(&ctx->clients[i], &ctx->clients[i+1],
828e31cfd1SJeremy Kerr 				(ctx->n_clients - i) * sizeof(*ctx->clients));
838e31cfd1SJeremy Kerr 		ctx->clients = realloc(ctx->clients,
848e31cfd1SJeremy Kerr 				ctx->n_clients * sizeof(*ctx->clients));
858e31cfd1SJeremy Kerr 	}
868e31cfd1SJeremy Kerr }
878e31cfd1SJeremy Kerr 
888e31cfd1SJeremy Kerr static void rx_message(uint8_t eid, void *data, void *msg, size_t len)
898e31cfd1SJeremy Kerr {
908e31cfd1SJeremy Kerr 	struct ctx *ctx = data;
918e31cfd1SJeremy Kerr 	struct iovec iov[2];
928e31cfd1SJeremy Kerr 	struct msghdr msghdr;
938e31cfd1SJeremy Kerr 	bool removed;
948e31cfd1SJeremy Kerr 	uint8_t type;
958e31cfd1SJeremy Kerr 	int i, rc;
968e31cfd1SJeremy Kerr 
978e31cfd1SJeremy Kerr 	if (len < 2)
988e31cfd1SJeremy Kerr 		return;
998e31cfd1SJeremy Kerr 
1008e31cfd1SJeremy Kerr 	type = *(uint8_t *)msg;
1018e31cfd1SJeremy Kerr 
1028e31cfd1SJeremy Kerr 	if (ctx->verbose)
1038e31cfd1SJeremy Kerr 		fprintf(stderr, "MCTP message received: len %zd, type %d\n",
1048e31cfd1SJeremy Kerr 				len, type);
1058e31cfd1SJeremy Kerr 
1068e31cfd1SJeremy Kerr 	memset(&msghdr, 0, sizeof(msghdr));
1078e31cfd1SJeremy Kerr 	msghdr.msg_iov = iov;
1088e31cfd1SJeremy Kerr 	msghdr.msg_iovlen = 2;
1098e31cfd1SJeremy Kerr 	iov[0].iov_base = &eid;
1108e31cfd1SJeremy Kerr 	iov[0].iov_len = 1;
1118e31cfd1SJeremy Kerr 	iov[1].iov_base = msg;
1128e31cfd1SJeremy Kerr 	iov[1].iov_len = len;
1138e31cfd1SJeremy Kerr 
1148e31cfd1SJeremy Kerr 	for (i = 0; i < ctx->n_clients; i++) {
1158e31cfd1SJeremy Kerr 		struct client *client = &ctx->clients[i];
1168e31cfd1SJeremy Kerr 
1178e31cfd1SJeremy Kerr 		if (client->type != type)
1188e31cfd1SJeremy Kerr 			continue;
1198e31cfd1SJeremy Kerr 
1208e31cfd1SJeremy Kerr 		if (ctx->verbose)
1218e31cfd1SJeremy Kerr 			fprintf(stderr, "  forwarding to client %d\n", i);
1228e31cfd1SJeremy Kerr 
1238e31cfd1SJeremy Kerr 		rc = sendmsg(client->sock, &msghdr, 0);
1248e31cfd1SJeremy Kerr 		if (rc != (ssize_t)(len + 1)) {
1258e31cfd1SJeremy Kerr 			client->active = false;
1268e31cfd1SJeremy Kerr 			removed = true;
1278e31cfd1SJeremy Kerr 		}
1288e31cfd1SJeremy Kerr 	}
1298e31cfd1SJeremy Kerr 
1308e31cfd1SJeremy Kerr 	if (removed)
1318e31cfd1SJeremy Kerr 		client_remove_inactive(ctx);
1328e31cfd1SJeremy Kerr 
1338e31cfd1SJeremy Kerr }
1348e31cfd1SJeremy Kerr 
13534b9b3d8SJeremy Kerr static int binding_null_init(struct mctp *mctp __unused,
13634b9b3d8SJeremy Kerr 		struct binding *binding __unused,
13734b9b3d8SJeremy Kerr 		mctp_eid_t eid __unused,
13834b9b3d8SJeremy Kerr 		int n_params, char * const *params __unused)
13934b9b3d8SJeremy Kerr {
14034b9b3d8SJeremy Kerr 	if (n_params != 0) {
14134b9b3d8SJeremy Kerr 		warnx("null binding doesn't accept parameters");
14234b9b3d8SJeremy Kerr 		return -1;
14334b9b3d8SJeremy Kerr 	}
14434b9b3d8SJeremy Kerr 	return 0;
14534b9b3d8SJeremy Kerr }
14634b9b3d8SJeremy Kerr 
1478e31cfd1SJeremy Kerr static int binding_serial_init(struct mctp *mctp, struct binding *binding,
1488e31cfd1SJeremy Kerr 		mctp_eid_t eid, int n_params, char * const *params)
1498e31cfd1SJeremy Kerr {
1508e31cfd1SJeremy Kerr 	struct mctp_binding_serial *serial;
1518e31cfd1SJeremy Kerr 	const char *path;
1528e31cfd1SJeremy Kerr 	int rc;
1538e31cfd1SJeremy Kerr 
1548e31cfd1SJeremy Kerr 	if (n_params != 1) {
1558e31cfd1SJeremy Kerr 		warnx("serial binding requires device param");
1568e31cfd1SJeremy Kerr 		return -1;
1578e31cfd1SJeremy Kerr 	}
1588e31cfd1SJeremy Kerr 
1598e31cfd1SJeremy Kerr 	path = params[0];
1608e31cfd1SJeremy Kerr 
1618e31cfd1SJeremy Kerr 	serial = mctp_serial_init();
1628e31cfd1SJeremy Kerr 	assert(serial);
1638e31cfd1SJeremy Kerr 
1648e31cfd1SJeremy Kerr 	rc = mctp_serial_open_path(serial, path);
1658e31cfd1SJeremy Kerr 	if (rc)
1668e31cfd1SJeremy Kerr 		return -1;
1678e31cfd1SJeremy Kerr 
1683b36d17cSJeremy Kerr 	mctp_register_bus(mctp, mctp_binding_serial_core(serial), eid);
1698e31cfd1SJeremy Kerr 
1708e31cfd1SJeremy Kerr 	binding->data = serial;
1718e31cfd1SJeremy Kerr 
1728e31cfd1SJeremy Kerr 	return 0;
1738e31cfd1SJeremy Kerr }
1748e31cfd1SJeremy Kerr 
1758e31cfd1SJeremy Kerr static int binding_serial_get_fd(struct binding *binding)
1768e31cfd1SJeremy Kerr {
1778e31cfd1SJeremy Kerr 	return mctp_serial_get_fd(binding->data);
1788e31cfd1SJeremy Kerr }
1798e31cfd1SJeremy Kerr 
1808e31cfd1SJeremy Kerr static int binding_serial_process(struct binding *binding)
1818e31cfd1SJeremy Kerr {
1828e31cfd1SJeremy Kerr 	return mctp_serial_read(binding->data);
1838e31cfd1SJeremy Kerr }
1848e31cfd1SJeremy Kerr 
1858e31cfd1SJeremy Kerr static int binding_astlpc_init(struct mctp *mctp, struct binding *binding,
1868e31cfd1SJeremy Kerr 		mctp_eid_t eid, int n_params,
1878e31cfd1SJeremy Kerr 		char * const *params __attribute__((unused)))
1888e31cfd1SJeremy Kerr {
1898e31cfd1SJeremy Kerr 	struct mctp_binding_astlpc *astlpc;
1908e31cfd1SJeremy Kerr 
1918e31cfd1SJeremy Kerr 	if (n_params) {
1928e31cfd1SJeremy Kerr 		warnx("astlpc binding does not accept parameters");
1938e31cfd1SJeremy Kerr 		return -1;
1948e31cfd1SJeremy Kerr 	}
1958e31cfd1SJeremy Kerr 
196bc53d35aSJeremy Kerr 	astlpc = mctp_astlpc_init_fileio();
1978e31cfd1SJeremy Kerr 	if (!astlpc) {
1988e31cfd1SJeremy Kerr 		warnx("could not initialise astlpc binding");
1998e31cfd1SJeremy Kerr 		return -1;
2008e31cfd1SJeremy Kerr 	}
2018e31cfd1SJeremy Kerr 
2023b36d17cSJeremy Kerr 	mctp_register_bus(mctp, mctp_binding_astlpc_core(astlpc), eid);
2033b36d17cSJeremy Kerr 
2048e31cfd1SJeremy Kerr 	binding->data = astlpc;
2058e31cfd1SJeremy Kerr 	return 0;
2068e31cfd1SJeremy Kerr }
2078e31cfd1SJeremy Kerr 
2088e31cfd1SJeremy Kerr static int binding_astlpc_get_fd(struct binding *binding)
2098e31cfd1SJeremy Kerr {
2108e31cfd1SJeremy Kerr 	return mctp_astlpc_get_fd(binding->data);
2118e31cfd1SJeremy Kerr }
2128e31cfd1SJeremy Kerr 
2138e31cfd1SJeremy Kerr static int binding_astlpc_process(struct binding *binding)
2148e31cfd1SJeremy Kerr {
2158e31cfd1SJeremy Kerr 	return mctp_astlpc_poll(binding->data);
2168e31cfd1SJeremy Kerr }
2178e31cfd1SJeremy Kerr 
2188e31cfd1SJeremy Kerr struct binding bindings[] = {
2198e31cfd1SJeremy Kerr 	{
22034b9b3d8SJeremy Kerr 		.name = "null",
22134b9b3d8SJeremy Kerr 		.init = binding_null_init,
22234b9b3d8SJeremy Kerr 	},
22334b9b3d8SJeremy Kerr 	{
2248e31cfd1SJeremy Kerr 		.name = "serial",
2258e31cfd1SJeremy Kerr 		.init = binding_serial_init,
2268e31cfd1SJeremy Kerr 		.get_fd = binding_serial_get_fd,
2278e31cfd1SJeremy Kerr 		.process = binding_serial_process,
2288e31cfd1SJeremy Kerr 	},
2298e31cfd1SJeremy Kerr 	{
2308e31cfd1SJeremy Kerr 		.name = "astlpc",
2318e31cfd1SJeremy Kerr 		.init = binding_astlpc_init,
2328e31cfd1SJeremy Kerr 		.get_fd = binding_astlpc_get_fd,
2338e31cfd1SJeremy Kerr 		.process = binding_astlpc_process,
2348e31cfd1SJeremy Kerr 	}
2358e31cfd1SJeremy Kerr };
2368e31cfd1SJeremy Kerr 
2378e31cfd1SJeremy Kerr struct binding *binding_lookup(const char *name)
2388e31cfd1SJeremy Kerr {
2398e31cfd1SJeremy Kerr 	struct binding *binding;
2408e31cfd1SJeremy Kerr 	unsigned int i;
2418e31cfd1SJeremy Kerr 
2428e31cfd1SJeremy Kerr 	for (i = 0; i < ARRAY_SIZE(bindings); i++) {
2438e31cfd1SJeremy Kerr 		binding = &bindings[i];
2448e31cfd1SJeremy Kerr 
2458e31cfd1SJeremy Kerr 		if (!strcmp(binding->name, name))
2468e31cfd1SJeremy Kerr 			return binding;
2478e31cfd1SJeremy Kerr 	}
2488e31cfd1SJeremy Kerr 
2498e31cfd1SJeremy Kerr 	return NULL;
2508e31cfd1SJeremy Kerr }
2518e31cfd1SJeremy Kerr 
2528e31cfd1SJeremy Kerr static int socket_init(struct ctx *ctx)
2538e31cfd1SJeremy Kerr {
2548e31cfd1SJeremy Kerr 	struct sockaddr_un addr;
2558e31cfd1SJeremy Kerr 	int namelen, rc;
2568e31cfd1SJeremy Kerr 
2578e31cfd1SJeremy Kerr 	namelen = sizeof(sockname) - 1;
2588e31cfd1SJeremy Kerr 	addr.sun_family = AF_UNIX;
2598e31cfd1SJeremy Kerr 	memcpy(addr.sun_path, sockname, namelen);
2608e31cfd1SJeremy Kerr 
2618e31cfd1SJeremy Kerr 	ctx->sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
2628e31cfd1SJeremy Kerr 	if (ctx->sock < 0) {
2638e31cfd1SJeremy Kerr 		warn("can't create socket");
2648e31cfd1SJeremy Kerr 		return -1;
2658e31cfd1SJeremy Kerr 	}
2668e31cfd1SJeremy Kerr 
2678e31cfd1SJeremy Kerr 	rc = bind(ctx->sock, (struct sockaddr *)&addr,
2688e31cfd1SJeremy Kerr 			sizeof(addr.sun_family) + namelen);
2698e31cfd1SJeremy Kerr 	if (rc) {
2708e31cfd1SJeremy Kerr 		warn("can't bind socket");
2718e31cfd1SJeremy Kerr 		goto err_close;
2728e31cfd1SJeremy Kerr 	}
2738e31cfd1SJeremy Kerr 
2748e31cfd1SJeremy Kerr 	rc = listen(ctx->sock, 1);
2758e31cfd1SJeremy Kerr 	if (rc) {
2768e31cfd1SJeremy Kerr 		warn("can't listen on socket");
2778e31cfd1SJeremy Kerr 		goto err_close;
2788e31cfd1SJeremy Kerr 	}
2798e31cfd1SJeremy Kerr 
2808e31cfd1SJeremy Kerr 	return 0;
2818e31cfd1SJeremy Kerr 
2828e31cfd1SJeremy Kerr err_close:
2838e31cfd1SJeremy Kerr 	close(ctx->sock);
2848e31cfd1SJeremy Kerr 	return -1;
2858e31cfd1SJeremy Kerr }
2868e31cfd1SJeremy Kerr 
2878e31cfd1SJeremy Kerr static int socket_process(struct ctx *ctx)
2888e31cfd1SJeremy Kerr {
2898e31cfd1SJeremy Kerr 	struct client *client;
2908e31cfd1SJeremy Kerr 	int fd;
2918e31cfd1SJeremy Kerr 
2928e31cfd1SJeremy Kerr 	fd = accept4(ctx->sock, NULL, 0, SOCK_NONBLOCK);
2938e31cfd1SJeremy Kerr 	if (fd < 0)
2948e31cfd1SJeremy Kerr 		return -1;
2958e31cfd1SJeremy Kerr 
2968e31cfd1SJeremy Kerr 	ctx->n_clients++;
2978e31cfd1SJeremy Kerr 	ctx->clients = realloc(ctx->clients,
2988e31cfd1SJeremy Kerr 			ctx->n_clients * sizeof(struct client));
2998e31cfd1SJeremy Kerr 
3008e31cfd1SJeremy Kerr 	client = &ctx->clients[ctx->n_clients-1];
3018676c934SAndrew Jeffery 	memset(client, 0, sizeof(*client));
3028e31cfd1SJeremy Kerr 	client->active = true;
3038e31cfd1SJeremy Kerr 	client->sock = fd;
3048e31cfd1SJeremy Kerr 
3058e31cfd1SJeremy Kerr 	return 0;
3068e31cfd1SJeremy Kerr }
3078e31cfd1SJeremy Kerr 
3088e31cfd1SJeremy Kerr static int client_process_recv(struct ctx *ctx, int idx)
3098e31cfd1SJeremy Kerr {
3108e31cfd1SJeremy Kerr 	struct client *client = &ctx->clients[idx];
311f49b2ac8SJeremy Kerr 	uint8_t eid;
312f49b2ac8SJeremy Kerr 	ssize_t len;
3138e31cfd1SJeremy Kerr 	int rc;
3148e31cfd1SJeremy Kerr 
3158e31cfd1SJeremy Kerr 	/* are we waiting for a type message? */
3168e31cfd1SJeremy Kerr 	if (!client->type) {
3178e31cfd1SJeremy Kerr 		uint8_t type;
3188e31cfd1SJeremy Kerr 		rc = read(client->sock, &type, 1);
3198e31cfd1SJeremy Kerr 		if (rc <= 0)
3208e31cfd1SJeremy Kerr 			goto out_close;
3218e31cfd1SJeremy Kerr 
3228e31cfd1SJeremy Kerr 		if (type == 0) {
3238e31cfd1SJeremy Kerr 			rc = -1;
3248e31cfd1SJeremy Kerr 			goto out_close;
3258e31cfd1SJeremy Kerr 		}
3268e31cfd1SJeremy Kerr 		if (ctx->verbose)
3278e31cfd1SJeremy Kerr 			fprintf(stderr, "client[%d] registered for type %u\n",
3288e31cfd1SJeremy Kerr 					idx, type);
3298e31cfd1SJeremy Kerr 		client->type = type;
3308e31cfd1SJeremy Kerr 		return 0;
3318e31cfd1SJeremy Kerr 	}
3328e31cfd1SJeremy Kerr 
333f49b2ac8SJeremy Kerr 	len = recv(client->sock, NULL, 0, MSG_PEEK | MSG_TRUNC);
334f49b2ac8SJeremy Kerr 	if (len < 0) {
3356896d41eSAndrew Jeffery 		if (errno != ECONNRESET)
336f49b2ac8SJeremy Kerr 			warn("can't receive (peek) from client");
3376896d41eSAndrew Jeffery 
33813a4041fSAndrew Jeffery 		rc = -1;
339f49b2ac8SJeremy Kerr 		goto out_close;
340f49b2ac8SJeremy Kerr 	}
341f49b2ac8SJeremy Kerr 
342b93b6112SAndrew Jeffery 	if ((size_t)len > ctx->buf_size) {
343f49b2ac8SJeremy Kerr 		void *tmp;
344f49b2ac8SJeremy Kerr 
345f49b2ac8SJeremy Kerr 		tmp = realloc(ctx->buf, len);
346f49b2ac8SJeremy Kerr 		if (!tmp) {
347f49b2ac8SJeremy Kerr 			warn("can't allocate for incoming message");
34813a4041fSAndrew Jeffery 			rc = -1;
349f49b2ac8SJeremy Kerr 			goto out_close;
350f49b2ac8SJeremy Kerr 		}
351f49b2ac8SJeremy Kerr 		ctx->buf = tmp;
352f49b2ac8SJeremy Kerr 		ctx->buf_size = len;
353f49b2ac8SJeremy Kerr 	}
354f49b2ac8SJeremy Kerr 
355f49b2ac8SJeremy Kerr 	rc = recv(client->sock, ctx->buf, ctx->buf_size, 0);
3568e31cfd1SJeremy Kerr 	if (rc < 0) {
3576896d41eSAndrew Jeffery 		if (errno != ECONNRESET)
3588e31cfd1SJeremy Kerr 			warn("can't receive from client");
35913a4041fSAndrew Jeffery 		rc = -1;
3608e31cfd1SJeremy Kerr 		goto out_close;
3618e31cfd1SJeremy Kerr 	}
3628e31cfd1SJeremy Kerr 
363195a7c5eSJeremy Kerr 	if (rc <= 0) {
3648e31cfd1SJeremy Kerr 		rc = -1;
3658e31cfd1SJeremy Kerr 		goto out_close;
3668e31cfd1SJeremy Kerr 	}
3678e31cfd1SJeremy Kerr 
368f49b2ac8SJeremy Kerr 	eid = *(uint8_t *)ctx->buf;
369d690d8eaSJeremy Kerr 
3708e31cfd1SJeremy Kerr 	if (ctx->verbose)
3718e31cfd1SJeremy Kerr 		fprintf(stderr,
3728e31cfd1SJeremy Kerr 			"client[%d] sent message: dest 0x%02x len %d\n",
3738e31cfd1SJeremy Kerr 			idx, eid, rc - 1);
3748e31cfd1SJeremy Kerr 
375195a7c5eSJeremy Kerr 
376195a7c5eSJeremy Kerr 	if (eid == ctx->local_eid)
377f49b2ac8SJeremy Kerr 		rx_message(eid, ctx, ctx->buf + 1, rc - 1);
378195a7c5eSJeremy Kerr 	else
379f49b2ac8SJeremy Kerr 		tx_message(ctx, eid, ctx->buf + 1, rc - 1);
3808e31cfd1SJeremy Kerr 
3818e31cfd1SJeremy Kerr 	return 0;
3828e31cfd1SJeremy Kerr 
3838e31cfd1SJeremy Kerr out_close:
3848e31cfd1SJeremy Kerr 	client->active = false;
3858e31cfd1SJeremy Kerr 	return rc;
3868e31cfd1SJeremy Kerr }
3878e31cfd1SJeremy Kerr 
3888e31cfd1SJeremy Kerr static int binding_init(struct ctx *ctx, const char *name,
3898e31cfd1SJeremy Kerr 		int argc, char * const *argv)
3908e31cfd1SJeremy Kerr {
3918e31cfd1SJeremy Kerr 	int rc;
3928e31cfd1SJeremy Kerr 
3938e31cfd1SJeremy Kerr 	ctx->binding = binding_lookup(name);
3948e31cfd1SJeremy Kerr 	if (!ctx->binding) {
3958e31cfd1SJeremy Kerr 		warnx("no such binding '%s'", name);
3968e31cfd1SJeremy Kerr 		return -1;
3978e31cfd1SJeremy Kerr 	}
3988e31cfd1SJeremy Kerr 
3998e31cfd1SJeremy Kerr 	rc = ctx->binding->init(ctx->mctp, ctx->binding, ctx->local_eid,
4008e31cfd1SJeremy Kerr 			argc, argv);
4018e31cfd1SJeremy Kerr 	return rc;
4028e31cfd1SJeremy Kerr }
4038e31cfd1SJeremy Kerr 
4048e31cfd1SJeremy Kerr enum {
4058e31cfd1SJeremy Kerr 	FD_BINDING = 0,
4068e31cfd1SJeremy Kerr 	FD_SOCKET,
4078e31cfd1SJeremy Kerr 	FD_NR,
4088e31cfd1SJeremy Kerr };
4098e31cfd1SJeremy Kerr 
4108e31cfd1SJeremy Kerr static int run_daemon(struct ctx *ctx)
4118e31cfd1SJeremy Kerr {
4128e31cfd1SJeremy Kerr 	bool clients_changed = false;
4138e31cfd1SJeremy Kerr 	int rc, i;
4148e31cfd1SJeremy Kerr 
4158e31cfd1SJeremy Kerr 	ctx->pollfds = malloc(FD_NR * sizeof(struct pollfd));
4168e31cfd1SJeremy Kerr 
41734b9b3d8SJeremy Kerr 	if (ctx->binding->get_fd) {
4188e31cfd1SJeremy Kerr 		ctx->pollfds[FD_BINDING].fd =
4198e31cfd1SJeremy Kerr 			ctx->binding->get_fd(ctx->binding);
4208e31cfd1SJeremy Kerr 		ctx->pollfds[FD_BINDING].events = POLLIN;
42134b9b3d8SJeremy Kerr 	} else {
42234b9b3d8SJeremy Kerr 		ctx->pollfds[FD_BINDING].fd = -1;
42334b9b3d8SJeremy Kerr 		ctx->pollfds[FD_BINDING].events = 0;
42434b9b3d8SJeremy Kerr 	}
4258e31cfd1SJeremy Kerr 
4268e31cfd1SJeremy Kerr 	ctx->pollfds[FD_SOCKET].fd = ctx->sock;
4278e31cfd1SJeremy Kerr 	ctx->pollfds[FD_SOCKET].events = POLLIN;
4288e31cfd1SJeremy Kerr 
4298e31cfd1SJeremy Kerr 	mctp_set_rx_all(ctx->mctp, rx_message, ctx);
4308e31cfd1SJeremy Kerr 
4318e31cfd1SJeremy Kerr 	for (;;) {
4328e31cfd1SJeremy Kerr 		if (clients_changed) {
4338e31cfd1SJeremy Kerr 			int i;
4348e31cfd1SJeremy Kerr 
4358e31cfd1SJeremy Kerr 			ctx->pollfds = realloc(ctx->pollfds,
4368e31cfd1SJeremy Kerr 					(ctx->n_clients + FD_NR) *
4378e31cfd1SJeremy Kerr 						sizeof(struct pollfd));
4388e31cfd1SJeremy Kerr 
4398e31cfd1SJeremy Kerr 			for (i = 0; i < ctx->n_clients; i++) {
4408e31cfd1SJeremy Kerr 				ctx->pollfds[FD_NR+i].fd =
4418e31cfd1SJeremy Kerr 					ctx->clients[i].sock;
4428e31cfd1SJeremy Kerr 				ctx->pollfds[FD_NR+i].events = POLLIN;
4438e31cfd1SJeremy Kerr 			}
4448e31cfd1SJeremy Kerr 			clients_changed = false;
4458e31cfd1SJeremy Kerr 		}
4468e31cfd1SJeremy Kerr 
4478e31cfd1SJeremy Kerr 		rc = poll(ctx->pollfds, ctx->n_clients + FD_NR, -1);
4488e31cfd1SJeremy Kerr 		if (rc < 0) {
4498e31cfd1SJeremy Kerr 			warn("poll failed");
4508e31cfd1SJeremy Kerr 			break;
4518e31cfd1SJeremy Kerr 		}
4528e31cfd1SJeremy Kerr 
4538e31cfd1SJeremy Kerr 		if (!rc)
4548e31cfd1SJeremy Kerr 			continue;
4558e31cfd1SJeremy Kerr 
4568e31cfd1SJeremy Kerr 		if (ctx->pollfds[FD_BINDING].revents) {
45734b9b3d8SJeremy Kerr 			rc = 0;
45834b9b3d8SJeremy Kerr 			if (ctx->binding->process)
4598e31cfd1SJeremy Kerr 				rc = ctx->binding->process(ctx->binding);
4608e31cfd1SJeremy Kerr 			if (rc)
4618e31cfd1SJeremy Kerr 				break;
4628e31cfd1SJeremy Kerr 		}
4638e31cfd1SJeremy Kerr 
4648e31cfd1SJeremy Kerr 		for (i = 0; i < ctx->n_clients; i++) {
4658e31cfd1SJeremy Kerr 			if (!ctx->pollfds[FD_NR+i].revents)
4668e31cfd1SJeremy Kerr 				continue;
4678e31cfd1SJeremy Kerr 
4688e31cfd1SJeremy Kerr 			rc = client_process_recv(ctx, i);
4698e31cfd1SJeremy Kerr 			if (rc)
4708e31cfd1SJeremy Kerr 				clients_changed = true;
4718e31cfd1SJeremy Kerr 		}
4728e31cfd1SJeremy Kerr 
4738e31cfd1SJeremy Kerr 		if (ctx->pollfds[FD_SOCKET].revents) {
4748e31cfd1SJeremy Kerr 			rc = socket_process(ctx);
4758e31cfd1SJeremy Kerr 			if (rc)
4768e31cfd1SJeremy Kerr 				break;
4778e31cfd1SJeremy Kerr 			clients_changed = true;
4788e31cfd1SJeremy Kerr 		}
4798e31cfd1SJeremy Kerr 
4808e31cfd1SJeremy Kerr 		if (clients_changed)
4818e31cfd1SJeremy Kerr 			client_remove_inactive(ctx);
4828e31cfd1SJeremy Kerr 
4838e31cfd1SJeremy Kerr 	}
4848e31cfd1SJeremy Kerr 
4858e31cfd1SJeremy Kerr 
4868e31cfd1SJeremy Kerr 	free(ctx->pollfds);
4878e31cfd1SJeremy Kerr 
4888e31cfd1SJeremy Kerr 	return rc;
4898e31cfd1SJeremy Kerr }
4908e31cfd1SJeremy Kerr 
4918e31cfd1SJeremy Kerr static const struct option options[] = {
4928e31cfd1SJeremy Kerr 	{ "verbose", no_argument, 0, 'v' },
4938e31cfd1SJeremy Kerr 	{ "eid", required_argument, 0, 'e' },
4948e31cfd1SJeremy Kerr 	{ 0 },
4958e31cfd1SJeremy Kerr };
4968e31cfd1SJeremy Kerr 
4978e31cfd1SJeremy Kerr static void usage(const char *progname)
4988e31cfd1SJeremy Kerr {
4998e31cfd1SJeremy Kerr 	unsigned int i;
5008e31cfd1SJeremy Kerr 
5018e31cfd1SJeremy Kerr 	fprintf(stderr, "usage: %s <binding> [params]\n", progname);
5028e31cfd1SJeremy Kerr 	fprintf(stderr, "Available bindings:\n");
5038e31cfd1SJeremy Kerr 	for (i = 0; i < ARRAY_SIZE(bindings); i++)
5048e31cfd1SJeremy Kerr 		fprintf(stderr, "  %s\n", bindings[i].name);
5058e31cfd1SJeremy Kerr }
5068e31cfd1SJeremy Kerr 
5078e31cfd1SJeremy Kerr int main(int argc, char * const *argv)
5088e31cfd1SJeremy Kerr {
5098e31cfd1SJeremy Kerr 	struct ctx *ctx, _ctx;
5108e31cfd1SJeremy Kerr 	int rc;
5118e31cfd1SJeremy Kerr 
5128e31cfd1SJeremy Kerr 	ctx = &_ctx;
5138e31cfd1SJeremy Kerr 	ctx->clients = NULL;
5148e31cfd1SJeremy Kerr 	ctx->n_clients = 0;
5158e31cfd1SJeremy Kerr 	ctx->local_eid = local_eid_default;
51604b81fc7SAndrew Jeffery 	ctx->verbose = false;
5178e31cfd1SJeremy Kerr 
5188e31cfd1SJeremy Kerr 	for (;;) {
5198e31cfd1SJeremy Kerr 		rc = getopt_long(argc, argv, "e:v", options, NULL);
5208e31cfd1SJeremy Kerr 		if (rc == -1)
5218e31cfd1SJeremy Kerr 			break;
5228e31cfd1SJeremy Kerr 		switch (rc) {
5238e31cfd1SJeremy Kerr 		case 'v':
5248e31cfd1SJeremy Kerr 			ctx->verbose = true;
5258e31cfd1SJeremy Kerr 			break;
5268e31cfd1SJeremy Kerr 		case 'e':
5278e31cfd1SJeremy Kerr 			ctx->local_eid = atoi(optarg);
5288e31cfd1SJeremy Kerr 			break;
5298e31cfd1SJeremy Kerr 		default:
5308e31cfd1SJeremy Kerr 			fprintf(stderr, "Invalid argument\n");
5318e31cfd1SJeremy Kerr 			return EXIT_FAILURE;
5328e31cfd1SJeremy Kerr 		}
5338e31cfd1SJeremy Kerr 	}
5348e31cfd1SJeremy Kerr 
5358e31cfd1SJeremy Kerr 	if (optind >= argc) {
5368e31cfd1SJeremy Kerr 		fprintf(stderr, "missing binding argument\n");
5378e31cfd1SJeremy Kerr 		usage(argv[0]);
5388e31cfd1SJeremy Kerr 		return EXIT_FAILURE;
5398e31cfd1SJeremy Kerr 	}
5408e31cfd1SJeremy Kerr 
541f49b2ac8SJeremy Kerr 	/* setup initial buffer */
542f49b2ac8SJeremy Kerr 	ctx->buf_size = 4096;
543f49b2ac8SJeremy Kerr 	ctx->buf = malloc(ctx->buf_size);
544f49b2ac8SJeremy Kerr 
5450b278a63SJeremy Kerr 	mctp_set_log_stdio(ctx->verbose ? MCTP_LOG_DEBUG : MCTP_LOG_WARNING);
5460b278a63SJeremy Kerr 
5478e31cfd1SJeremy Kerr 	ctx->mctp = mctp_init();
5488e31cfd1SJeremy Kerr 	assert(ctx->mctp);
5498e31cfd1SJeremy Kerr 
5508e31cfd1SJeremy Kerr 	rc = binding_init(ctx, argv[optind], argc - optind - 1, argv + optind + 1);
5518e31cfd1SJeremy Kerr 	if (rc)
5528e31cfd1SJeremy Kerr 		return EXIT_FAILURE;
5538e31cfd1SJeremy Kerr 
5548e31cfd1SJeremy Kerr 	rc = socket_init(ctx);
5558e31cfd1SJeremy Kerr 	if (rc)
5568e31cfd1SJeremy Kerr 		return EXIT_FAILURE;
5578e31cfd1SJeremy Kerr 
5588e31cfd1SJeremy Kerr 	rc = run_daemon(ctx);
5598e31cfd1SJeremy Kerr 
5608e31cfd1SJeremy Kerr 	return rc ? EXIT_FAILURE : EXIT_SUCCESS;
5618e31cfd1SJeremy Kerr 
5628e31cfd1SJeremy Kerr }
563