xref: /openbmc/libmctp/utils/mctp-demux-daemon.c (revision 13a4041f)
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>
78e31cfd1SJeremy Kerr #include <getopt.h>
88e31cfd1SJeremy Kerr #include <poll.h>
904b81fc7SAndrew Jeffery #include <stdbool.h>
108e31cfd1SJeremy Kerr #include <stdio.h>
118e31cfd1SJeremy Kerr #include <stdlib.h>
128e31cfd1SJeremy Kerr #include <string.h>
138e31cfd1SJeremy Kerr #include <unistd.h>
148e31cfd1SJeremy Kerr 
158e31cfd1SJeremy Kerr #include <sys/socket.h>
168e31cfd1SJeremy Kerr #include <sys/un.h>
178e31cfd1SJeremy Kerr 
188e31cfd1SJeremy Kerr #include "libmctp.h"
198e31cfd1SJeremy Kerr #include "libmctp-serial.h"
208e31cfd1SJeremy Kerr #include "libmctp-astlpc.h"
218e31cfd1SJeremy Kerr 
228e31cfd1SJeremy Kerr #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
2334b9b3d8SJeremy Kerr #define __unused __attribute__((unused))
248e31cfd1SJeremy Kerr 
258e31cfd1SJeremy Kerr static const mctp_eid_t local_eid_default = 8;
268e31cfd1SJeremy Kerr static char sockname[] = "\0mctp-mux";
278e31cfd1SJeremy Kerr 
288e31cfd1SJeremy Kerr struct binding {
298e31cfd1SJeremy Kerr 	const char	*name;
308e31cfd1SJeremy Kerr 	int		(*init)(struct mctp *mctp, struct binding *binding,
318e31cfd1SJeremy Kerr 				mctp_eid_t eid, int n_params,
328e31cfd1SJeremy Kerr 				char * const * params);
338e31cfd1SJeremy Kerr 	int		(*get_fd)(struct binding *binding);
348e31cfd1SJeremy Kerr 	int		(*process)(struct binding *binding);
358e31cfd1SJeremy Kerr 	void		*data;
368e31cfd1SJeremy Kerr };
378e31cfd1SJeremy Kerr 
388e31cfd1SJeremy Kerr struct client {
398e31cfd1SJeremy Kerr 	bool		active;
408e31cfd1SJeremy Kerr 	int		sock;
418e31cfd1SJeremy Kerr 	uint8_t		type;
428e31cfd1SJeremy Kerr };
438e31cfd1SJeremy Kerr 
448e31cfd1SJeremy Kerr struct ctx {
458e31cfd1SJeremy Kerr 	struct mctp	*mctp;
468e31cfd1SJeremy Kerr 	struct binding	*binding;
478e31cfd1SJeremy Kerr 	bool		verbose;
488e31cfd1SJeremy Kerr 	int		local_eid;
49f49b2ac8SJeremy Kerr 	void		*buf;
50f49b2ac8SJeremy Kerr 	size_t		buf_size;
518e31cfd1SJeremy Kerr 
528e31cfd1SJeremy Kerr 	int		sock;
538e31cfd1SJeremy Kerr 	struct pollfd	*pollfds;
548e31cfd1SJeremy Kerr 
558e31cfd1SJeremy Kerr 	struct client	*clients;
568e31cfd1SJeremy Kerr 	int		n_clients;
578e31cfd1SJeremy Kerr };
588e31cfd1SJeremy Kerr 
598e31cfd1SJeremy Kerr static void tx_message(struct ctx *ctx, mctp_eid_t eid, void *msg, size_t len)
608e31cfd1SJeremy Kerr {
618e31cfd1SJeremy Kerr 	mctp_message_tx(ctx->mctp, eid, msg, len);
628e31cfd1SJeremy Kerr }
638e31cfd1SJeremy Kerr 
648e31cfd1SJeremy Kerr static void client_remove_inactive(struct ctx *ctx)
658e31cfd1SJeremy Kerr {
668e31cfd1SJeremy Kerr 	int i;
678e31cfd1SJeremy Kerr 
688e31cfd1SJeremy Kerr 	for (i = 0; i < ctx->n_clients; i++) {
698e31cfd1SJeremy Kerr 		struct client *client = &ctx->clients[i];
708e31cfd1SJeremy Kerr 		if (client->active)
718e31cfd1SJeremy Kerr 			continue;
728e31cfd1SJeremy Kerr 		close(client->sock);
738e31cfd1SJeremy Kerr 
748e31cfd1SJeremy Kerr 		ctx->n_clients--;
758e31cfd1SJeremy Kerr 		memmove(&ctx->clients[i], &ctx->clients[i+1],
768e31cfd1SJeremy Kerr 				(ctx->n_clients - i) * sizeof(*ctx->clients));
778e31cfd1SJeremy Kerr 		ctx->clients = realloc(ctx->clients,
788e31cfd1SJeremy Kerr 				ctx->n_clients * sizeof(*ctx->clients));
798e31cfd1SJeremy Kerr 	}
808e31cfd1SJeremy Kerr }
818e31cfd1SJeremy Kerr 
828e31cfd1SJeremy Kerr static void rx_message(uint8_t eid, void *data, void *msg, size_t len)
838e31cfd1SJeremy Kerr {
848e31cfd1SJeremy Kerr 	struct ctx *ctx = data;
858e31cfd1SJeremy Kerr 	struct iovec iov[2];
868e31cfd1SJeremy Kerr 	struct msghdr msghdr;
878e31cfd1SJeremy Kerr 	bool removed;
888e31cfd1SJeremy Kerr 	uint8_t type;
898e31cfd1SJeremy Kerr 	int i, rc;
908e31cfd1SJeremy Kerr 
918e31cfd1SJeremy Kerr 	if (len < 2)
928e31cfd1SJeremy Kerr 		return;
938e31cfd1SJeremy Kerr 
948e31cfd1SJeremy Kerr 	type = *(uint8_t *)msg;
958e31cfd1SJeremy Kerr 
968e31cfd1SJeremy Kerr 	if (ctx->verbose)
978e31cfd1SJeremy Kerr 		fprintf(stderr, "MCTP message received: len %zd, type %d\n",
988e31cfd1SJeremy Kerr 				len, type);
998e31cfd1SJeremy Kerr 
1008e31cfd1SJeremy Kerr 	memset(&msghdr, 0, sizeof(msghdr));
1018e31cfd1SJeremy Kerr 	msghdr.msg_iov = iov;
1028e31cfd1SJeremy Kerr 	msghdr.msg_iovlen = 2;
1038e31cfd1SJeremy Kerr 	iov[0].iov_base = &eid;
1048e31cfd1SJeremy Kerr 	iov[0].iov_len = 1;
1058e31cfd1SJeremy Kerr 	iov[1].iov_base = msg;
1068e31cfd1SJeremy Kerr 	iov[1].iov_len = len;
1078e31cfd1SJeremy Kerr 
1088e31cfd1SJeremy Kerr 	for (i = 0; i < ctx->n_clients; i++) {
1098e31cfd1SJeremy Kerr 		struct client *client = &ctx->clients[i];
1108e31cfd1SJeremy Kerr 
1118e31cfd1SJeremy Kerr 		if (client->type != type)
1128e31cfd1SJeremy Kerr 			continue;
1138e31cfd1SJeremy Kerr 
1148e31cfd1SJeremy Kerr 		if (ctx->verbose)
1158e31cfd1SJeremy Kerr 			fprintf(stderr, "  forwarding to client %d\n", i);
1168e31cfd1SJeremy Kerr 
1178e31cfd1SJeremy Kerr 		rc = sendmsg(client->sock, &msghdr, 0);
1188e31cfd1SJeremy Kerr 		if (rc != (ssize_t)(len + 1)) {
1198e31cfd1SJeremy Kerr 			client->active = false;
1208e31cfd1SJeremy Kerr 			removed = true;
1218e31cfd1SJeremy Kerr 		}
1228e31cfd1SJeremy Kerr 	}
1238e31cfd1SJeremy Kerr 
1248e31cfd1SJeremy Kerr 	if (removed)
1258e31cfd1SJeremy Kerr 		client_remove_inactive(ctx);
1268e31cfd1SJeremy Kerr 
1278e31cfd1SJeremy Kerr }
1288e31cfd1SJeremy Kerr 
12934b9b3d8SJeremy Kerr static int binding_null_init(struct mctp *mctp __unused,
13034b9b3d8SJeremy Kerr 		struct binding *binding __unused,
13134b9b3d8SJeremy Kerr 		mctp_eid_t eid __unused,
13234b9b3d8SJeremy Kerr 		int n_params, char * const *params __unused)
13334b9b3d8SJeremy Kerr {
13434b9b3d8SJeremy Kerr 	if (n_params != 0) {
13534b9b3d8SJeremy Kerr 		warnx("null binding doesn't accept parameters");
13634b9b3d8SJeremy Kerr 		return -1;
13734b9b3d8SJeremy Kerr 	}
13834b9b3d8SJeremy Kerr 	return 0;
13934b9b3d8SJeremy Kerr }
14034b9b3d8SJeremy Kerr 
1418e31cfd1SJeremy Kerr static int binding_serial_init(struct mctp *mctp, struct binding *binding,
1428e31cfd1SJeremy Kerr 		mctp_eid_t eid, int n_params, char * const *params)
1438e31cfd1SJeremy Kerr {
1448e31cfd1SJeremy Kerr 	struct mctp_binding_serial *serial;
1458e31cfd1SJeremy Kerr 	const char *path;
1468e31cfd1SJeremy Kerr 	int rc;
1478e31cfd1SJeremy Kerr 
1488e31cfd1SJeremy Kerr 	if (n_params != 1) {
1498e31cfd1SJeremy Kerr 		warnx("serial binding requires device param");
1508e31cfd1SJeremy Kerr 		return -1;
1518e31cfd1SJeremy Kerr 	}
1528e31cfd1SJeremy Kerr 
1538e31cfd1SJeremy Kerr 	path = params[0];
1548e31cfd1SJeremy Kerr 
1558e31cfd1SJeremy Kerr 	serial = mctp_serial_init();
1568e31cfd1SJeremy Kerr 	assert(serial);
1578e31cfd1SJeremy Kerr 
1588e31cfd1SJeremy Kerr 	rc = mctp_serial_open_path(serial, path);
1598e31cfd1SJeremy Kerr 	if (rc)
1608e31cfd1SJeremy Kerr 		return -1;
1618e31cfd1SJeremy Kerr 
1623b36d17cSJeremy Kerr 	mctp_register_bus(mctp, mctp_binding_serial_core(serial), eid);
1638e31cfd1SJeremy Kerr 
1648e31cfd1SJeremy Kerr 	binding->data = serial;
1658e31cfd1SJeremy Kerr 
1668e31cfd1SJeremy Kerr 	return 0;
1678e31cfd1SJeremy Kerr }
1688e31cfd1SJeremy Kerr 
1698e31cfd1SJeremy Kerr static int binding_serial_get_fd(struct binding *binding)
1708e31cfd1SJeremy Kerr {
1718e31cfd1SJeremy Kerr 	return mctp_serial_get_fd(binding->data);
1728e31cfd1SJeremy Kerr }
1738e31cfd1SJeremy Kerr 
1748e31cfd1SJeremy Kerr static int binding_serial_process(struct binding *binding)
1758e31cfd1SJeremy Kerr {
1768e31cfd1SJeremy Kerr 	return mctp_serial_read(binding->data);
1778e31cfd1SJeremy Kerr }
1788e31cfd1SJeremy Kerr 
1798e31cfd1SJeremy Kerr static int binding_astlpc_init(struct mctp *mctp, struct binding *binding,
1808e31cfd1SJeremy Kerr 		mctp_eid_t eid, int n_params,
1818e31cfd1SJeremy Kerr 		char * const *params __attribute__((unused)))
1828e31cfd1SJeremy Kerr {
1838e31cfd1SJeremy Kerr 	struct mctp_binding_astlpc *astlpc;
1848e31cfd1SJeremy Kerr 
1858e31cfd1SJeremy Kerr 	if (n_params) {
1868e31cfd1SJeremy Kerr 		warnx("astlpc binding does not accept parameters");
1878e31cfd1SJeremy Kerr 		return -1;
1888e31cfd1SJeremy Kerr 	}
1898e31cfd1SJeremy Kerr 
190bc53d35aSJeremy Kerr 	astlpc = mctp_astlpc_init_fileio();
1918e31cfd1SJeremy Kerr 	if (!astlpc) {
1928e31cfd1SJeremy Kerr 		warnx("could not initialise astlpc binding");
1938e31cfd1SJeremy Kerr 		return -1;
1948e31cfd1SJeremy Kerr 	}
1958e31cfd1SJeremy Kerr 
1963b36d17cSJeremy Kerr 	mctp_register_bus(mctp, mctp_binding_astlpc_core(astlpc), eid);
1973b36d17cSJeremy Kerr 
1988e31cfd1SJeremy Kerr 	binding->data = astlpc;
1998e31cfd1SJeremy Kerr 	return 0;
2008e31cfd1SJeremy Kerr }
2018e31cfd1SJeremy Kerr 
2028e31cfd1SJeremy Kerr static int binding_astlpc_get_fd(struct binding *binding)
2038e31cfd1SJeremy Kerr {
2048e31cfd1SJeremy Kerr 	return mctp_astlpc_get_fd(binding->data);
2058e31cfd1SJeremy Kerr }
2068e31cfd1SJeremy Kerr 
2078e31cfd1SJeremy Kerr static int binding_astlpc_process(struct binding *binding)
2088e31cfd1SJeremy Kerr {
2098e31cfd1SJeremy Kerr 	return mctp_astlpc_poll(binding->data);
2108e31cfd1SJeremy Kerr }
2118e31cfd1SJeremy Kerr 
2128e31cfd1SJeremy Kerr struct binding bindings[] = {
2138e31cfd1SJeremy Kerr 	{
21434b9b3d8SJeremy Kerr 		.name = "null",
21534b9b3d8SJeremy Kerr 		.init = binding_null_init,
21634b9b3d8SJeremy Kerr 	},
21734b9b3d8SJeremy Kerr 	{
2188e31cfd1SJeremy Kerr 		.name = "serial",
2198e31cfd1SJeremy Kerr 		.init = binding_serial_init,
2208e31cfd1SJeremy Kerr 		.get_fd = binding_serial_get_fd,
2218e31cfd1SJeremy Kerr 		.process = binding_serial_process,
2228e31cfd1SJeremy Kerr 	},
2238e31cfd1SJeremy Kerr 	{
2248e31cfd1SJeremy Kerr 		.name = "astlpc",
2258e31cfd1SJeremy Kerr 		.init = binding_astlpc_init,
2268e31cfd1SJeremy Kerr 		.get_fd = binding_astlpc_get_fd,
2278e31cfd1SJeremy Kerr 		.process = binding_astlpc_process,
2288e31cfd1SJeremy Kerr 	}
2298e31cfd1SJeremy Kerr };
2308e31cfd1SJeremy Kerr 
2318e31cfd1SJeremy Kerr struct binding *binding_lookup(const char *name)
2328e31cfd1SJeremy Kerr {
2338e31cfd1SJeremy Kerr 	struct binding *binding;
2348e31cfd1SJeremy Kerr 	unsigned int i;
2358e31cfd1SJeremy Kerr 
2368e31cfd1SJeremy Kerr 	for (i = 0; i < ARRAY_SIZE(bindings); i++) {
2378e31cfd1SJeremy Kerr 		binding = &bindings[i];
2388e31cfd1SJeremy Kerr 
2398e31cfd1SJeremy Kerr 		if (!strcmp(binding->name, name))
2408e31cfd1SJeremy Kerr 			return binding;
2418e31cfd1SJeremy Kerr 	}
2428e31cfd1SJeremy Kerr 
2438e31cfd1SJeremy Kerr 	return NULL;
2448e31cfd1SJeremy Kerr }
2458e31cfd1SJeremy Kerr 
2468e31cfd1SJeremy Kerr static int socket_init(struct ctx *ctx)
2478e31cfd1SJeremy Kerr {
2488e31cfd1SJeremy Kerr 	struct sockaddr_un addr;
2498e31cfd1SJeremy Kerr 	int namelen, rc;
2508e31cfd1SJeremy Kerr 
2518e31cfd1SJeremy Kerr 	namelen = sizeof(sockname) - 1;
2528e31cfd1SJeremy Kerr 	addr.sun_family = AF_UNIX;
2538e31cfd1SJeremy Kerr 	memcpy(addr.sun_path, sockname, namelen);
2548e31cfd1SJeremy Kerr 
2558e31cfd1SJeremy Kerr 	ctx->sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
2568e31cfd1SJeremy Kerr 	if (ctx->sock < 0) {
2578e31cfd1SJeremy Kerr 		warn("can't create socket");
2588e31cfd1SJeremy Kerr 		return -1;
2598e31cfd1SJeremy Kerr 	}
2608e31cfd1SJeremy Kerr 
2618e31cfd1SJeremy Kerr 	rc = bind(ctx->sock, (struct sockaddr *)&addr,
2628e31cfd1SJeremy Kerr 			sizeof(addr.sun_family) + namelen);
2638e31cfd1SJeremy Kerr 	if (rc) {
2648e31cfd1SJeremy Kerr 		warn("can't bind socket");
2658e31cfd1SJeremy Kerr 		goto err_close;
2668e31cfd1SJeremy Kerr 	}
2678e31cfd1SJeremy Kerr 
2688e31cfd1SJeremy Kerr 	rc = listen(ctx->sock, 1);
2698e31cfd1SJeremy Kerr 	if (rc) {
2708e31cfd1SJeremy Kerr 		warn("can't listen on socket");
2718e31cfd1SJeremy Kerr 		goto err_close;
2728e31cfd1SJeremy Kerr 	}
2738e31cfd1SJeremy Kerr 
2748e31cfd1SJeremy Kerr 	return 0;
2758e31cfd1SJeremy Kerr 
2768e31cfd1SJeremy Kerr err_close:
2778e31cfd1SJeremy Kerr 	close(ctx->sock);
2788e31cfd1SJeremy Kerr 	return -1;
2798e31cfd1SJeremy Kerr }
2808e31cfd1SJeremy Kerr 
2818e31cfd1SJeremy Kerr static int socket_process(struct ctx *ctx)
2828e31cfd1SJeremy Kerr {
2838e31cfd1SJeremy Kerr 	struct client *client;
2848e31cfd1SJeremy Kerr 	int fd;
2858e31cfd1SJeremy Kerr 
2868e31cfd1SJeremy Kerr 	fd = accept4(ctx->sock, NULL, 0, SOCK_NONBLOCK);
2878e31cfd1SJeremy Kerr 	if (fd < 0)
2888e31cfd1SJeremy Kerr 		return -1;
2898e31cfd1SJeremy Kerr 
2908e31cfd1SJeremy Kerr 	ctx->n_clients++;
2918e31cfd1SJeremy Kerr 	ctx->clients = realloc(ctx->clients,
2928e31cfd1SJeremy Kerr 			ctx->n_clients * sizeof(struct client));
2938e31cfd1SJeremy Kerr 
2948e31cfd1SJeremy Kerr 	client = &ctx->clients[ctx->n_clients-1];
2958676c934SAndrew Jeffery 	memset(client, 0, sizeof(*client));
2968e31cfd1SJeremy Kerr 	client->active = true;
2978e31cfd1SJeremy Kerr 	client->sock = fd;
2988e31cfd1SJeremy Kerr 
2998e31cfd1SJeremy Kerr 	return 0;
3008e31cfd1SJeremy Kerr }
3018e31cfd1SJeremy Kerr 
3028e31cfd1SJeremy Kerr static int client_process_recv(struct ctx *ctx, int idx)
3038e31cfd1SJeremy Kerr {
3048e31cfd1SJeremy Kerr 	struct client *client = &ctx->clients[idx];
305f49b2ac8SJeremy Kerr 	uint8_t eid;
306f49b2ac8SJeremy Kerr 	ssize_t len;
3078e31cfd1SJeremy Kerr 	int rc;
3088e31cfd1SJeremy Kerr 
3098e31cfd1SJeremy Kerr 	/* are we waiting for a type message? */
3108e31cfd1SJeremy Kerr 	if (!client->type) {
3118e31cfd1SJeremy Kerr 		uint8_t type;
3128e31cfd1SJeremy Kerr 		rc = read(client->sock, &type, 1);
3138e31cfd1SJeremy Kerr 		if (rc <= 0)
3148e31cfd1SJeremy Kerr 			goto out_close;
3158e31cfd1SJeremy Kerr 
3168e31cfd1SJeremy Kerr 		if (type == 0) {
3178e31cfd1SJeremy Kerr 			rc = -1;
3188e31cfd1SJeremy Kerr 			goto out_close;
3198e31cfd1SJeremy Kerr 		}
3208e31cfd1SJeremy Kerr 		if (ctx->verbose)
3218e31cfd1SJeremy Kerr 			fprintf(stderr, "client[%d] registered for type %u\n",
3228e31cfd1SJeremy Kerr 					idx, type);
3238e31cfd1SJeremy Kerr 		client->type = type;
3248e31cfd1SJeremy Kerr 		return 0;
3258e31cfd1SJeremy Kerr 	}
3268e31cfd1SJeremy Kerr 
327f49b2ac8SJeremy Kerr 	len = recv(client->sock, NULL, 0, MSG_PEEK | MSG_TRUNC);
328f49b2ac8SJeremy Kerr 	if (len < 0) {
329f49b2ac8SJeremy Kerr 		warn("can't receive(peek) from client");
330*13a4041fSAndrew Jeffery 		rc = -1;
331f49b2ac8SJeremy Kerr 		goto out_close;
332f49b2ac8SJeremy Kerr 	}
333f49b2ac8SJeremy Kerr 
334f49b2ac8SJeremy Kerr 	if (len > ctx->buf_size) {
335f49b2ac8SJeremy Kerr 		void *tmp;
336f49b2ac8SJeremy Kerr 
337f49b2ac8SJeremy Kerr 		tmp = realloc(ctx->buf, len);
338f49b2ac8SJeremy Kerr 		if (!tmp) {
339f49b2ac8SJeremy Kerr 			warn("can't allocate for incoming message");
340*13a4041fSAndrew Jeffery 			rc = -1;
341f49b2ac8SJeremy Kerr 			goto out_close;
342f49b2ac8SJeremy Kerr 		}
343f49b2ac8SJeremy Kerr 		ctx->buf = tmp;
344f49b2ac8SJeremy Kerr 		ctx->buf_size = len;
345f49b2ac8SJeremy Kerr 	}
346f49b2ac8SJeremy Kerr 
347f49b2ac8SJeremy Kerr 	rc = recv(client->sock, ctx->buf, ctx->buf_size, 0);
3488e31cfd1SJeremy Kerr 	if (rc < 0) {
3498e31cfd1SJeremy Kerr 		warn("can't receive from client");
350*13a4041fSAndrew Jeffery 		rc = -1;
3518e31cfd1SJeremy Kerr 		goto out_close;
3528e31cfd1SJeremy Kerr 	}
3538e31cfd1SJeremy Kerr 
354195a7c5eSJeremy Kerr 	if (rc <= 0) {
3558e31cfd1SJeremy Kerr 		rc = -1;
3568e31cfd1SJeremy Kerr 		goto out_close;
3578e31cfd1SJeremy Kerr 	}
3588e31cfd1SJeremy Kerr 
359f49b2ac8SJeremy Kerr 	eid = *(uint8_t *)ctx->buf;
360d690d8eaSJeremy Kerr 
3618e31cfd1SJeremy Kerr 	if (ctx->verbose)
3628e31cfd1SJeremy Kerr 		fprintf(stderr,
3638e31cfd1SJeremy Kerr 			"client[%d] sent message: dest 0x%02x len %d\n",
3648e31cfd1SJeremy Kerr 			idx, eid, rc - 1);
3658e31cfd1SJeremy Kerr 
366195a7c5eSJeremy Kerr 
367195a7c5eSJeremy Kerr 	if (eid == ctx->local_eid)
368f49b2ac8SJeremy Kerr 		rx_message(eid, ctx, ctx->buf + 1, rc - 1);
369195a7c5eSJeremy Kerr 	else
370f49b2ac8SJeremy Kerr 		tx_message(ctx, eid, ctx->buf + 1, rc - 1);
3718e31cfd1SJeremy Kerr 
3728e31cfd1SJeremy Kerr 	return 0;
3738e31cfd1SJeremy Kerr 
3748e31cfd1SJeremy Kerr out_close:
3758e31cfd1SJeremy Kerr 	client->active = false;
3768e31cfd1SJeremy Kerr 	return rc;
3778e31cfd1SJeremy Kerr }
3788e31cfd1SJeremy Kerr 
3798e31cfd1SJeremy Kerr static int binding_init(struct ctx *ctx, const char *name,
3808e31cfd1SJeremy Kerr 		int argc, char * const *argv)
3818e31cfd1SJeremy Kerr {
3828e31cfd1SJeremy Kerr 	int rc;
3838e31cfd1SJeremy Kerr 
3848e31cfd1SJeremy Kerr 	ctx->binding = binding_lookup(name);
3858e31cfd1SJeremy Kerr 	if (!ctx->binding) {
3868e31cfd1SJeremy Kerr 		warnx("no such binding '%s'", name);
3878e31cfd1SJeremy Kerr 		return -1;
3888e31cfd1SJeremy Kerr 	}
3898e31cfd1SJeremy Kerr 
3908e31cfd1SJeremy Kerr 	rc = ctx->binding->init(ctx->mctp, ctx->binding, ctx->local_eid,
3918e31cfd1SJeremy Kerr 			argc, argv);
3928e31cfd1SJeremy Kerr 	return rc;
3938e31cfd1SJeremy Kerr }
3948e31cfd1SJeremy Kerr 
3958e31cfd1SJeremy Kerr enum {
3968e31cfd1SJeremy Kerr 	FD_BINDING = 0,
3978e31cfd1SJeremy Kerr 	FD_SOCKET,
3988e31cfd1SJeremy Kerr 	FD_NR,
3998e31cfd1SJeremy Kerr };
4008e31cfd1SJeremy Kerr 
4018e31cfd1SJeremy Kerr static int run_daemon(struct ctx *ctx)
4028e31cfd1SJeremy Kerr {
4038e31cfd1SJeremy Kerr 	bool clients_changed = false;
4048e31cfd1SJeremy Kerr 	int rc, i;
4058e31cfd1SJeremy Kerr 
4068e31cfd1SJeremy Kerr 	ctx->pollfds = malloc(FD_NR * sizeof(struct pollfd));
4078e31cfd1SJeremy Kerr 
40834b9b3d8SJeremy Kerr 	if (ctx->binding->get_fd) {
4098e31cfd1SJeremy Kerr 		ctx->pollfds[FD_BINDING].fd =
4108e31cfd1SJeremy Kerr 			ctx->binding->get_fd(ctx->binding);
4118e31cfd1SJeremy Kerr 		ctx->pollfds[FD_BINDING].events = POLLIN;
41234b9b3d8SJeremy Kerr 	} else {
41334b9b3d8SJeremy Kerr 		ctx->pollfds[FD_BINDING].fd = -1;
41434b9b3d8SJeremy Kerr 		ctx->pollfds[FD_BINDING].events = 0;
41534b9b3d8SJeremy Kerr 	}
4168e31cfd1SJeremy Kerr 
4178e31cfd1SJeremy Kerr 	ctx->pollfds[FD_SOCKET].fd = ctx->sock;
4188e31cfd1SJeremy Kerr 	ctx->pollfds[FD_SOCKET].events = POLLIN;
4198e31cfd1SJeremy Kerr 
4208e31cfd1SJeremy Kerr 	mctp_set_rx_all(ctx->mctp, rx_message, ctx);
4218e31cfd1SJeremy Kerr 
4228e31cfd1SJeremy Kerr 	for (;;) {
4238e31cfd1SJeremy Kerr 		if (clients_changed) {
4248e31cfd1SJeremy Kerr 			int i;
4258e31cfd1SJeremy Kerr 
4268e31cfd1SJeremy Kerr 			ctx->pollfds = realloc(ctx->pollfds,
4278e31cfd1SJeremy Kerr 					(ctx->n_clients + FD_NR) *
4288e31cfd1SJeremy Kerr 						sizeof(struct pollfd));
4298e31cfd1SJeremy Kerr 
4308e31cfd1SJeremy Kerr 			for (i = 0; i < ctx->n_clients; i++) {
4318e31cfd1SJeremy Kerr 				ctx->pollfds[FD_NR+i].fd =
4328e31cfd1SJeremy Kerr 					ctx->clients[i].sock;
4338e31cfd1SJeremy Kerr 				ctx->pollfds[FD_NR+i].events = POLLIN;
4348e31cfd1SJeremy Kerr 			}
4358e31cfd1SJeremy Kerr 			clients_changed = false;
4368e31cfd1SJeremy Kerr 		}
4378e31cfd1SJeremy Kerr 
4388e31cfd1SJeremy Kerr 		rc = poll(ctx->pollfds, ctx->n_clients + FD_NR, -1);
4398e31cfd1SJeremy Kerr 		if (rc < 0) {
4408e31cfd1SJeremy Kerr 			warn("poll failed");
4418e31cfd1SJeremy Kerr 			break;
4428e31cfd1SJeremy Kerr 		}
4438e31cfd1SJeremy Kerr 
4448e31cfd1SJeremy Kerr 		if (!rc)
4458e31cfd1SJeremy Kerr 			continue;
4468e31cfd1SJeremy Kerr 
4478e31cfd1SJeremy Kerr 		if (ctx->pollfds[FD_BINDING].revents) {
44834b9b3d8SJeremy Kerr 			rc = 0;
44934b9b3d8SJeremy Kerr 			if (ctx->binding->process)
4508e31cfd1SJeremy Kerr 				rc = ctx->binding->process(ctx->binding);
4518e31cfd1SJeremy Kerr 			if (rc)
4528e31cfd1SJeremy Kerr 				break;
4538e31cfd1SJeremy Kerr 		}
4548e31cfd1SJeremy Kerr 
4558e31cfd1SJeremy Kerr 		for (i = 0; i < ctx->n_clients; i++) {
4568e31cfd1SJeremy Kerr 			if (!ctx->pollfds[FD_NR+i].revents)
4578e31cfd1SJeremy Kerr 				continue;
4588e31cfd1SJeremy Kerr 
4598e31cfd1SJeremy Kerr 			rc = client_process_recv(ctx, i);
4608e31cfd1SJeremy Kerr 			if (rc)
4618e31cfd1SJeremy Kerr 				clients_changed = true;
4628e31cfd1SJeremy Kerr 		}
4638e31cfd1SJeremy Kerr 
4648e31cfd1SJeremy Kerr 		if (ctx->pollfds[FD_SOCKET].revents) {
4658e31cfd1SJeremy Kerr 			rc = socket_process(ctx);
4668e31cfd1SJeremy Kerr 			if (rc)
4678e31cfd1SJeremy Kerr 				break;
4688e31cfd1SJeremy Kerr 			clients_changed = true;
4698e31cfd1SJeremy Kerr 		}
4708e31cfd1SJeremy Kerr 
4718e31cfd1SJeremy Kerr 		if (clients_changed)
4728e31cfd1SJeremy Kerr 			client_remove_inactive(ctx);
4738e31cfd1SJeremy Kerr 
4748e31cfd1SJeremy Kerr 	}
4758e31cfd1SJeremy Kerr 
4768e31cfd1SJeremy Kerr 
4778e31cfd1SJeremy Kerr 	free(ctx->pollfds);
4788e31cfd1SJeremy Kerr 
4798e31cfd1SJeremy Kerr 	return rc;
4808e31cfd1SJeremy Kerr }
4818e31cfd1SJeremy Kerr 
4828e31cfd1SJeremy Kerr static const struct option options[] = {
4838e31cfd1SJeremy Kerr 	{ "verbose", no_argument, 0, 'v' },
4848e31cfd1SJeremy Kerr 	{ "eid", required_argument, 0, 'e' },
4858e31cfd1SJeremy Kerr 	{ 0 },
4868e31cfd1SJeremy Kerr };
4878e31cfd1SJeremy Kerr 
4888e31cfd1SJeremy Kerr static void usage(const char *progname)
4898e31cfd1SJeremy Kerr {
4908e31cfd1SJeremy Kerr 	unsigned int i;
4918e31cfd1SJeremy Kerr 
4928e31cfd1SJeremy Kerr 	fprintf(stderr, "usage: %s <binding> [params]\n", progname);
4938e31cfd1SJeremy Kerr 	fprintf(stderr, "Available bindings:\n");
4948e31cfd1SJeremy Kerr 	for (i = 0; i < ARRAY_SIZE(bindings); i++)
4958e31cfd1SJeremy Kerr 		fprintf(stderr, "  %s\n", bindings[i].name);
4968e31cfd1SJeremy Kerr }
4978e31cfd1SJeremy Kerr 
4988e31cfd1SJeremy Kerr int main(int argc, char * const *argv)
4998e31cfd1SJeremy Kerr {
5008e31cfd1SJeremy Kerr 	struct ctx *ctx, _ctx;
5018e31cfd1SJeremy Kerr 	int rc;
5028e31cfd1SJeremy Kerr 
5038e31cfd1SJeremy Kerr 	ctx = &_ctx;
5048e31cfd1SJeremy Kerr 	ctx->clients = NULL;
5058e31cfd1SJeremy Kerr 	ctx->n_clients = 0;
5068e31cfd1SJeremy Kerr 	ctx->local_eid = local_eid_default;
50704b81fc7SAndrew Jeffery 	ctx->verbose = false;
5088e31cfd1SJeremy Kerr 
5098e31cfd1SJeremy Kerr 	for (;;) {
5108e31cfd1SJeremy Kerr 		rc = getopt_long(argc, argv, "e:v", options, NULL);
5118e31cfd1SJeremy Kerr 		if (rc == -1)
5128e31cfd1SJeremy Kerr 			break;
5138e31cfd1SJeremy Kerr 		switch (rc) {
5148e31cfd1SJeremy Kerr 		case 'v':
5158e31cfd1SJeremy Kerr 			ctx->verbose = true;
5168e31cfd1SJeremy Kerr 			break;
5178e31cfd1SJeremy Kerr 		case 'e':
5188e31cfd1SJeremy Kerr 			ctx->local_eid = atoi(optarg);
5198e31cfd1SJeremy Kerr 			break;
5208e31cfd1SJeremy Kerr 		default:
5218e31cfd1SJeremy Kerr 			fprintf(stderr, "Invalid argument\n");
5228e31cfd1SJeremy Kerr 			return EXIT_FAILURE;
5238e31cfd1SJeremy Kerr 		}
5248e31cfd1SJeremy Kerr 	}
5258e31cfd1SJeremy Kerr 
5268e31cfd1SJeremy Kerr 	if (optind >= argc) {
5278e31cfd1SJeremy Kerr 		fprintf(stderr, "missing binding argument\n");
5288e31cfd1SJeremy Kerr 		usage(argv[0]);
5298e31cfd1SJeremy Kerr 		return EXIT_FAILURE;
5308e31cfd1SJeremy Kerr 	}
5318e31cfd1SJeremy Kerr 
532f49b2ac8SJeremy Kerr 	/* setup initial buffer */
533f49b2ac8SJeremy Kerr 	ctx->buf_size = 4096;
534f49b2ac8SJeremy Kerr 	ctx->buf = malloc(ctx->buf_size);
535f49b2ac8SJeremy Kerr 
5360b278a63SJeremy Kerr 	mctp_set_log_stdio(ctx->verbose ? MCTP_LOG_DEBUG : MCTP_LOG_WARNING);
5370b278a63SJeremy Kerr 
5388e31cfd1SJeremy Kerr 	ctx->mctp = mctp_init();
5398e31cfd1SJeremy Kerr 	assert(ctx->mctp);
5408e31cfd1SJeremy Kerr 
5418e31cfd1SJeremy Kerr 	rc = binding_init(ctx, argv[optind], argc - optind - 1, argv + optind + 1);
5428e31cfd1SJeremy Kerr 	if (rc)
5438e31cfd1SJeremy Kerr 		return EXIT_FAILURE;
5448e31cfd1SJeremy Kerr 
5458e31cfd1SJeremy Kerr 	rc = socket_init(ctx);
5468e31cfd1SJeremy Kerr 	if (rc)
5478e31cfd1SJeremy Kerr 		return EXIT_FAILURE;
5488e31cfd1SJeremy Kerr 
5498e31cfd1SJeremy Kerr 	rc = run_daemon(ctx);
5508e31cfd1SJeremy Kerr 
5518e31cfd1SJeremy Kerr 	return rc ? EXIT_FAILURE : EXIT_SUCCESS;
5528e31cfd1SJeremy Kerr 
5538e31cfd1SJeremy Kerr }
554