xref: /openbmc/libmctp/utils/mctp-demux-daemon.c (revision 400766f9)
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"
65ab78259SAndrew Jeffery 
75ab78259SAndrew Jeffery #define SD_LISTEN_FDS_START 3
85ab78259SAndrew Jeffery 
95ab78259SAndrew Jeffery #include "compiler.h"
105ab78259SAndrew Jeffery #include "libmctp.h"
115ab78259SAndrew Jeffery #include "libmctp-serial.h"
125ab78259SAndrew Jeffery #include "libmctp-astlpc.h"
13cad47301SAndrew Jeffery #include "utils/mctp-capture.h"
14d4103f8fSAndrew Jeffery 
158e31cfd1SJeremy Kerr #include <assert.h>
168e31cfd1SJeremy Kerr #include <err.h>
176896d41eSAndrew Jeffery #include <errno.h>
188e31cfd1SJeremy Kerr #include <getopt.h>
19b93b6112SAndrew Jeffery #include <limits.h>
208e31cfd1SJeremy Kerr #include <poll.h>
21490e3873SAndrew Jeffery #include <signal.h>
2204b81fc7SAndrew Jeffery #include <stdbool.h>
238e31cfd1SJeremy Kerr #include <stdio.h>
248e31cfd1SJeremy Kerr #include <stdlib.h>
258e31cfd1SJeremy Kerr #include <string.h>
268e31cfd1SJeremy Kerr #include <unistd.h>
278e31cfd1SJeremy Kerr 
28490e3873SAndrew Jeffery #include <sys/signalfd.h>
298e31cfd1SJeremy Kerr #include <sys/socket.h>
308e31cfd1SJeremy Kerr #include <sys/un.h>
318e31cfd1SJeremy Kerr 
328e31cfd1SJeremy Kerr #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
338e31cfd1SJeremy Kerr 
34d4103f8fSAndrew Jeffery #if HAVE_SYSTEMD_SD_DAEMON_H
35d4103f8fSAndrew Jeffery #include <systemd/sd-daemon.h>
36d4103f8fSAndrew Jeffery #else
sd_listen_fds(int i __unused)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;
488f53d631SAndrew Jeffery 	int (*init)(struct mctp *mctp, struct binding *binding, mctp_eid_t eid,
498f53d631SAndrew Jeffery 		    int n_params, char *const *params);
50edebe169SAndrew Jeffery 	void (*destroy)(struct mctp *mctp, struct binding *binding);
518f53d631SAndrew Jeffery 	int (*init_pollfd)(struct binding *binding, struct pollfd *pollfd);
528e31cfd1SJeremy Kerr 	int (*process)(struct binding *binding);
538e31cfd1SJeremy Kerr 	void *data;
548e31cfd1SJeremy Kerr };
558e31cfd1SJeremy Kerr 
568e31cfd1SJeremy Kerr struct client {
578e31cfd1SJeremy Kerr 	bool active;
588e31cfd1SJeremy Kerr 	int sock;
598e31cfd1SJeremy Kerr 	uint8_t type;
608e31cfd1SJeremy Kerr };
618e31cfd1SJeremy Kerr 
628e31cfd1SJeremy Kerr struct ctx {
638e31cfd1SJeremy Kerr 	struct mctp *mctp;
648e31cfd1SJeremy Kerr 	struct binding *binding;
658e31cfd1SJeremy Kerr 	bool verbose;
668e31cfd1SJeremy Kerr 	int local_eid;
67f49b2ac8SJeremy Kerr 	void *buf;
68f49b2ac8SJeremy Kerr 	size_t buf_size;
698e31cfd1SJeremy Kerr 
708e31cfd1SJeremy Kerr 	int sock;
718e31cfd1SJeremy Kerr 	struct pollfd *pollfds;
728e31cfd1SJeremy Kerr 
738e31cfd1SJeremy Kerr 	struct client *clients;
748e31cfd1SJeremy Kerr 	int n_clients;
75cad47301SAndrew Jeffery 
76cad47301SAndrew Jeffery 	struct {
77cad47301SAndrew Jeffery 		struct capture binding;
78cad47301SAndrew Jeffery 		struct capture socket;
79cad47301SAndrew Jeffery 	} pcap;
808e31cfd1SJeremy Kerr };
818e31cfd1SJeremy Kerr 
tx_message(struct ctx * ctx,mctp_eid_t eid,void * msg,size_t len)828e31cfd1SJeremy Kerr static void tx_message(struct ctx *ctx, mctp_eid_t eid, void *msg, size_t len)
838e31cfd1SJeremy Kerr {
8406735055SAndrew Jeffery 	int rc;
8506735055SAndrew Jeffery 
86f39c3857SSumanth Bhat 	rc = mctp_message_tx(ctx->mctp, eid, MCTP_MESSAGE_TO_SRC, 0, msg, len);
8706735055SAndrew Jeffery 	if (rc)
8806735055SAndrew Jeffery 		warnx("Failed to send message: %d", rc);
898e31cfd1SJeremy Kerr }
908e31cfd1SJeremy Kerr 
client_remove_inactive(struct ctx * ctx)918e31cfd1SJeremy Kerr static void client_remove_inactive(struct ctx *ctx)
928e31cfd1SJeremy Kerr {
938e31cfd1SJeremy Kerr 	int i;
948e31cfd1SJeremy Kerr 
958e31cfd1SJeremy Kerr 	for (i = 0; i < ctx->n_clients; i++) {
968e31cfd1SJeremy Kerr 		struct client *client = &ctx->clients[i];
978e31cfd1SJeremy Kerr 		if (client->active)
988e31cfd1SJeremy Kerr 			continue;
998e31cfd1SJeremy Kerr 		close(client->sock);
1008e31cfd1SJeremy Kerr 
1018e31cfd1SJeremy Kerr 		ctx->n_clients--;
1028e31cfd1SJeremy Kerr 		memmove(&ctx->clients[i], &ctx->clients[i + 1],
1038e31cfd1SJeremy Kerr 			(ctx->n_clients - i) * sizeof(*ctx->clients));
1048e31cfd1SJeremy Kerr 		ctx->clients = realloc(ctx->clients,
1058e31cfd1SJeremy Kerr 				       ctx->n_clients * sizeof(*ctx->clients));
1068e31cfd1SJeremy Kerr 	}
1078e31cfd1SJeremy Kerr }
1088e31cfd1SJeremy Kerr 
rx_message(uint8_t eid,bool tag_owner __unused,uint8_t msg_tag __unused,void * data,void * msg,size_t len)109a721c2d8SPatrick Williams static void rx_message(uint8_t eid, bool tag_owner __unused,
110a721c2d8SPatrick Williams 		       uint8_t msg_tag __unused, void *data, void *msg,
111a721c2d8SPatrick Williams 		       size_t len)
1128e31cfd1SJeremy Kerr {
1138e31cfd1SJeremy Kerr 	struct ctx *ctx = data;
1148e31cfd1SJeremy Kerr 	struct iovec iov[2];
1158e31cfd1SJeremy Kerr 	struct msghdr msghdr;
1168e31cfd1SJeremy Kerr 	bool removed;
1178e31cfd1SJeremy Kerr 	uint8_t type;
1188e31cfd1SJeremy Kerr 	int i, rc;
1198e31cfd1SJeremy Kerr 
1208e31cfd1SJeremy Kerr 	if (len < 2)
1218e31cfd1SJeremy Kerr 		return;
1228e31cfd1SJeremy Kerr 
1238e31cfd1SJeremy Kerr 	type = *(uint8_t *)msg;
1248e31cfd1SJeremy Kerr 
1258e31cfd1SJeremy Kerr 	if (ctx->verbose)
1268e31cfd1SJeremy Kerr 		fprintf(stderr, "MCTP message received: len %zd, type %d\n",
1278e31cfd1SJeremy Kerr 			len, type);
1288e31cfd1SJeremy Kerr 
1298e31cfd1SJeremy Kerr 	memset(&msghdr, 0, sizeof(msghdr));
1308e31cfd1SJeremy Kerr 	msghdr.msg_iov = iov;
1318e31cfd1SJeremy Kerr 	msghdr.msg_iovlen = 2;
1328e31cfd1SJeremy Kerr 	iov[0].iov_base = &eid;
1338e31cfd1SJeremy Kerr 	iov[0].iov_len = 1;
1348e31cfd1SJeremy Kerr 	iov[1].iov_base = msg;
1358e31cfd1SJeremy Kerr 	iov[1].iov_len = len;
1368e31cfd1SJeremy Kerr 
1378e31cfd1SJeremy Kerr 	for (i = 0; i < ctx->n_clients; i++) {
1388e31cfd1SJeremy Kerr 		struct client *client = &ctx->clients[i];
1398e31cfd1SJeremy Kerr 
1408e31cfd1SJeremy Kerr 		if (client->type != type)
1418e31cfd1SJeremy Kerr 			continue;
1428e31cfd1SJeremy Kerr 
1438e31cfd1SJeremy Kerr 		if (ctx->verbose)
1448e31cfd1SJeremy Kerr 			fprintf(stderr, "  forwarding to client %d\n", i);
1458e31cfd1SJeremy Kerr 
1468e31cfd1SJeremy Kerr 		rc = sendmsg(client->sock, &msghdr, 0);
1478e31cfd1SJeremy Kerr 		if (rc != (ssize_t)(len + 1)) {
1488e31cfd1SJeremy Kerr 			client->active = false;
1498e31cfd1SJeremy Kerr 			removed = true;
1508e31cfd1SJeremy Kerr 		}
1518e31cfd1SJeremy Kerr 	}
1528e31cfd1SJeremy Kerr 
1538e31cfd1SJeremy Kerr 	if (removed)
1548e31cfd1SJeremy Kerr 		client_remove_inactive(ctx);
1558e31cfd1SJeremy Kerr }
1568e31cfd1SJeremy Kerr 
binding_null_init(struct mctp * mctp __unused,struct binding * binding __unused,mctp_eid_t eid __unused,int n_params,char * const * params __unused)15734b9b3d8SJeremy Kerr static int binding_null_init(struct mctp *mctp __unused,
15834b9b3d8SJeremy Kerr 			     struct binding *binding __unused,
159a721c2d8SPatrick Williams 			     mctp_eid_t eid __unused, int n_params,
160a721c2d8SPatrick Williams 			     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 
binding_serial_init(struct mctp * mctp,struct binding * binding,mctp_eid_t eid,int n_params,char * const * params)1698e31cfd1SJeremy Kerr static int binding_serial_init(struct mctp *mctp, struct binding *binding,
170a721c2d8SPatrick Williams 			       mctp_eid_t eid, int n_params,
171a721c2d8SPatrick Williams 			       char *const *params)
1728e31cfd1SJeremy Kerr {
1738e31cfd1SJeremy Kerr 	struct mctp_binding_serial *serial;
1748e31cfd1SJeremy Kerr 	const char *path;
1758e31cfd1SJeremy Kerr 	int rc;
1768e31cfd1SJeremy Kerr 
1778e31cfd1SJeremy Kerr 	if (n_params != 1) {
1788e31cfd1SJeremy Kerr 		warnx("serial binding requires device param");
1798e31cfd1SJeremy Kerr 		return -1;
1808e31cfd1SJeremy Kerr 	}
1818e31cfd1SJeremy Kerr 
1828e31cfd1SJeremy Kerr 	path = params[0];
1838e31cfd1SJeremy Kerr 
1848e31cfd1SJeremy Kerr 	serial = mctp_serial_init();
1858e31cfd1SJeremy Kerr 	assert(serial);
1868e31cfd1SJeremy Kerr 
1878e31cfd1SJeremy Kerr 	rc = mctp_serial_open_path(serial, path);
1888e31cfd1SJeremy Kerr 	if (rc)
1898e31cfd1SJeremy Kerr 		return -1;
1908e31cfd1SJeremy Kerr 
1913b36d17cSJeremy Kerr 	mctp_register_bus(mctp, mctp_binding_serial_core(serial), eid);
1928e31cfd1SJeremy Kerr 
1938e31cfd1SJeremy Kerr 	binding->data = serial;
1948e31cfd1SJeremy Kerr 
1958e31cfd1SJeremy Kerr 	return 0;
1968e31cfd1SJeremy Kerr }
1978e31cfd1SJeremy Kerr 
binding_serial_init_pollfd(struct binding * binding,struct pollfd * pollfd)1988f53d631SAndrew Jeffery static int binding_serial_init_pollfd(struct binding *binding,
1998f53d631SAndrew Jeffery 				      struct pollfd *pollfd)
2008e31cfd1SJeremy Kerr {
2018f53d631SAndrew Jeffery 	return mctp_serial_init_pollfd(binding->data, pollfd);
2028e31cfd1SJeremy Kerr }
2038e31cfd1SJeremy Kerr 
binding_serial_process(struct binding * binding)2048e31cfd1SJeremy Kerr static int binding_serial_process(struct binding *binding)
2058e31cfd1SJeremy Kerr {
2068e31cfd1SJeremy Kerr 	return mctp_serial_read(binding->data);
2078e31cfd1SJeremy Kerr }
2088e31cfd1SJeremy Kerr 
binding_astlpc_init(struct mctp * mctp,struct binding * binding,mctp_eid_t eid,int n_params,char * const * params)2098e31cfd1SJeremy Kerr static int binding_astlpc_init(struct mctp *mctp, struct binding *binding,
2108e31cfd1SJeremy Kerr 			       mctp_eid_t eid, int n_params,
2118e31cfd1SJeremy Kerr 			       char *const *params __attribute__((unused)))
2128e31cfd1SJeremy Kerr {
2138e31cfd1SJeremy Kerr 	struct mctp_binding_astlpc *astlpc;
214*400766f9SKonstantin Aladyshev 	const char *path;
2158e31cfd1SJeremy Kerr 
216*400766f9SKonstantin Aladyshev 	if (n_params != 1) {
217*400766f9SKonstantin Aladyshev 		warnx("astlpc binding requires kcs device param");
2188e31cfd1SJeremy Kerr 		return -1;
2198e31cfd1SJeremy Kerr 	}
2208e31cfd1SJeremy Kerr 
221*400766f9SKonstantin Aladyshev 	path = params[0];
222*400766f9SKonstantin Aladyshev 
223*400766f9SKonstantin Aladyshev 	astlpc = mctp_astlpc_init_fileio(path);
2248e31cfd1SJeremy Kerr 	if (!astlpc) {
2258e31cfd1SJeremy Kerr 		warnx("could not initialise astlpc binding");
2268e31cfd1SJeremy Kerr 		return -1;
2278e31cfd1SJeremy Kerr 	}
2288e31cfd1SJeremy Kerr 
2293b36d17cSJeremy Kerr 	mctp_register_bus(mctp, mctp_binding_astlpc_core(astlpc), eid);
2303b36d17cSJeremy Kerr 
2318e31cfd1SJeremy Kerr 	binding->data = astlpc;
2328e31cfd1SJeremy Kerr 	return 0;
2338e31cfd1SJeremy Kerr }
2348e31cfd1SJeremy Kerr 
binding_astlpc_destroy(struct mctp * mctp,struct binding * binding)235edebe169SAndrew Jeffery static void binding_astlpc_destroy(struct mctp *mctp, struct binding *binding)
236edebe169SAndrew Jeffery {
237edebe169SAndrew Jeffery 	struct mctp_binding_astlpc *astlpc = binding->data;
238edebe169SAndrew Jeffery 
239edebe169SAndrew Jeffery 	mctp_unregister_bus(mctp, mctp_binding_astlpc_core(astlpc));
240edebe169SAndrew Jeffery 
241edebe169SAndrew Jeffery 	mctp_astlpc_destroy(astlpc);
242edebe169SAndrew Jeffery }
243edebe169SAndrew Jeffery 
binding_astlpc_init_pollfd(struct binding * binding,struct pollfd * pollfd)2448f53d631SAndrew Jeffery static int binding_astlpc_init_pollfd(struct binding *binding,
2458f53d631SAndrew Jeffery 				      struct pollfd *pollfd)
2468e31cfd1SJeremy Kerr {
2478f53d631SAndrew Jeffery 	return mctp_astlpc_init_pollfd(binding->data, pollfd);
2488e31cfd1SJeremy Kerr }
2498e31cfd1SJeremy Kerr 
binding_astlpc_process(struct binding * binding)2508e31cfd1SJeremy Kerr static int binding_astlpc_process(struct binding *binding)
2518e31cfd1SJeremy Kerr {
2528e31cfd1SJeremy Kerr 	return mctp_astlpc_poll(binding->data);
2538e31cfd1SJeremy Kerr }
2548e31cfd1SJeremy Kerr 
255a721c2d8SPatrick Williams struct binding bindings[] = { {
25634b9b3d8SJeremy Kerr 				      .name = "null",
25734b9b3d8SJeremy Kerr 				      .init = binding_null_init,
25834b9b3d8SJeremy Kerr 			      },
25934b9b3d8SJeremy Kerr 			      {
2608e31cfd1SJeremy Kerr 				      .name = "serial",
2618e31cfd1SJeremy Kerr 				      .init = binding_serial_init,
262edebe169SAndrew Jeffery 				      .destroy = NULL,
2638f53d631SAndrew Jeffery 				      .init_pollfd = binding_serial_init_pollfd,
2648e31cfd1SJeremy Kerr 				      .process = binding_serial_process,
2658e31cfd1SJeremy Kerr 			      },
2668e31cfd1SJeremy Kerr 			      {
2678e31cfd1SJeremy Kerr 				      .name = "astlpc",
2688e31cfd1SJeremy Kerr 				      .init = binding_astlpc_init,
269edebe169SAndrew Jeffery 				      .destroy = binding_astlpc_destroy,
2708f53d631SAndrew Jeffery 				      .init_pollfd = binding_astlpc_init_pollfd,
2718e31cfd1SJeremy Kerr 				      .process = binding_astlpc_process,
272a721c2d8SPatrick Williams 			      } };
2738e31cfd1SJeremy Kerr 
binding_lookup(const char * name)2748e31cfd1SJeremy Kerr struct binding *binding_lookup(const char *name)
2758e31cfd1SJeremy Kerr {
2768e31cfd1SJeremy Kerr 	struct binding *binding;
2778e31cfd1SJeremy Kerr 	unsigned int i;
2788e31cfd1SJeremy Kerr 
2798e31cfd1SJeremy Kerr 	for (i = 0; i < ARRAY_SIZE(bindings); i++) {
2808e31cfd1SJeremy Kerr 		binding = &bindings[i];
2818e31cfd1SJeremy Kerr 
2828e31cfd1SJeremy Kerr 		if (!strcmp(binding->name, name))
2838e31cfd1SJeremy Kerr 			return binding;
2848e31cfd1SJeremy Kerr 	}
2858e31cfd1SJeremy Kerr 
2868e31cfd1SJeremy Kerr 	return NULL;
2878e31cfd1SJeremy Kerr }
2888e31cfd1SJeremy Kerr 
socket_init(struct ctx * ctx)2898e31cfd1SJeremy Kerr static int socket_init(struct ctx *ctx)
2908e31cfd1SJeremy Kerr {
2918e31cfd1SJeremy Kerr 	struct sockaddr_un addr;
2928e31cfd1SJeremy Kerr 	int namelen, rc;
2938e31cfd1SJeremy Kerr 
2948e31cfd1SJeremy Kerr 	namelen = sizeof(sockname) - 1;
2958e31cfd1SJeremy Kerr 	addr.sun_family = AF_UNIX;
2968e31cfd1SJeremy Kerr 	memcpy(addr.sun_path, sockname, namelen);
2978e31cfd1SJeremy Kerr 
2988e31cfd1SJeremy Kerr 	ctx->sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
2998e31cfd1SJeremy Kerr 	if (ctx->sock < 0) {
3008e31cfd1SJeremy Kerr 		warn("can't create socket");
3018e31cfd1SJeremy Kerr 		return -1;
3028e31cfd1SJeremy Kerr 	}
3038e31cfd1SJeremy Kerr 
3048e31cfd1SJeremy Kerr 	rc = bind(ctx->sock, (struct sockaddr *)&addr,
3058e31cfd1SJeremy Kerr 		  sizeof(addr.sun_family) + namelen);
3068e31cfd1SJeremy Kerr 	if (rc) {
3078e31cfd1SJeremy Kerr 		warn("can't bind socket");
3088e31cfd1SJeremy Kerr 		goto err_close;
3098e31cfd1SJeremy Kerr 	}
3108e31cfd1SJeremy Kerr 
3118e31cfd1SJeremy Kerr 	rc = listen(ctx->sock, 1);
3128e31cfd1SJeremy Kerr 	if (rc) {
3138e31cfd1SJeremy Kerr 		warn("can't listen on socket");
3148e31cfd1SJeremy Kerr 		goto err_close;
3158e31cfd1SJeremy Kerr 	}
3168e31cfd1SJeremy Kerr 
3178e31cfd1SJeremy Kerr 	return 0;
3188e31cfd1SJeremy Kerr 
3198e31cfd1SJeremy Kerr err_close:
3208e31cfd1SJeremy Kerr 	close(ctx->sock);
3218e31cfd1SJeremy Kerr 	return -1;
3228e31cfd1SJeremy Kerr }
3238e31cfd1SJeremy Kerr 
socket_process(struct ctx * ctx)3248e31cfd1SJeremy Kerr static int socket_process(struct ctx *ctx)
3258e31cfd1SJeremy Kerr {
3268e31cfd1SJeremy Kerr 	struct client *client;
3278e31cfd1SJeremy Kerr 	int fd;
3288e31cfd1SJeremy Kerr 
3298e31cfd1SJeremy Kerr 	fd = accept4(ctx->sock, NULL, 0, SOCK_NONBLOCK);
3308e31cfd1SJeremy Kerr 	if (fd < 0)
3318e31cfd1SJeremy Kerr 		return -1;
3328e31cfd1SJeremy Kerr 
3338e31cfd1SJeremy Kerr 	ctx->n_clients++;
334a721c2d8SPatrick Williams 	ctx->clients =
335a721c2d8SPatrick Williams 		realloc(ctx->clients, ctx->n_clients * sizeof(struct client));
3368e31cfd1SJeremy Kerr 
3378e31cfd1SJeremy Kerr 	client = &ctx->clients[ctx->n_clients - 1];
3388676c934SAndrew Jeffery 	memset(client, 0, sizeof(*client));
3398e31cfd1SJeremy Kerr 	client->active = true;
3408e31cfd1SJeremy Kerr 	client->sock = fd;
3418e31cfd1SJeremy Kerr 
3428e31cfd1SJeremy Kerr 	return 0;
3438e31cfd1SJeremy Kerr }
3448e31cfd1SJeremy Kerr 
client_process_recv(struct ctx * ctx,int idx)3458e31cfd1SJeremy Kerr static int client_process_recv(struct ctx *ctx, int idx)
3468e31cfd1SJeremy Kerr {
3478e31cfd1SJeremy Kerr 	struct client *client = &ctx->clients[idx];
348f49b2ac8SJeremy Kerr 	uint8_t eid;
349f49b2ac8SJeremy Kerr 	ssize_t len;
3508e31cfd1SJeremy Kerr 	int rc;
3518e31cfd1SJeremy Kerr 
3528e31cfd1SJeremy Kerr 	/* are we waiting for a type message? */
3538e31cfd1SJeremy Kerr 	if (!client->type) {
3548e31cfd1SJeremy Kerr 		uint8_t type;
3558e31cfd1SJeremy Kerr 		rc = read(client->sock, &type, 1);
3568e31cfd1SJeremy Kerr 		if (rc <= 0)
3578e31cfd1SJeremy Kerr 			goto out_close;
3588e31cfd1SJeremy Kerr 
3598e31cfd1SJeremy Kerr 		if (type == 0) {
3608e31cfd1SJeremy Kerr 			rc = -1;
3618e31cfd1SJeremy Kerr 			goto out_close;
3628e31cfd1SJeremy Kerr 		}
3638e31cfd1SJeremy Kerr 		if (ctx->verbose)
3648e31cfd1SJeremy Kerr 			fprintf(stderr, "client[%d] registered for type %u\n",
3658e31cfd1SJeremy Kerr 				idx, type);
3668e31cfd1SJeremy Kerr 		client->type = type;
3678e31cfd1SJeremy Kerr 		return 0;
3688e31cfd1SJeremy Kerr 	}
3698e31cfd1SJeremy Kerr 
370f49b2ac8SJeremy Kerr 	len = recv(client->sock, NULL, 0, MSG_PEEK | MSG_TRUNC);
371f49b2ac8SJeremy Kerr 	if (len < 0) {
3726896d41eSAndrew Jeffery 		if (errno != ECONNRESET)
373f49b2ac8SJeremy Kerr 			warn("can't receive (peek) from client");
3746896d41eSAndrew Jeffery 
37513a4041fSAndrew Jeffery 		rc = -1;
376f49b2ac8SJeremy Kerr 		goto out_close;
377f49b2ac8SJeremy Kerr 	}
378f49b2ac8SJeremy Kerr 
379b93b6112SAndrew Jeffery 	if ((size_t)len > ctx->buf_size) {
380f49b2ac8SJeremy Kerr 		void *tmp;
381f49b2ac8SJeremy Kerr 
382f49b2ac8SJeremy Kerr 		tmp = realloc(ctx->buf, len);
383f49b2ac8SJeremy Kerr 		if (!tmp) {
384f49b2ac8SJeremy Kerr 			warn("can't allocate for incoming message");
38513a4041fSAndrew Jeffery 			rc = -1;
386f49b2ac8SJeremy Kerr 			goto out_close;
387f49b2ac8SJeremy Kerr 		}
388f49b2ac8SJeremy Kerr 		ctx->buf = tmp;
389f49b2ac8SJeremy Kerr 		ctx->buf_size = len;
390f49b2ac8SJeremy Kerr 	}
391f49b2ac8SJeremy Kerr 
392f49b2ac8SJeremy Kerr 	rc = recv(client->sock, ctx->buf, ctx->buf_size, 0);
3938e31cfd1SJeremy Kerr 	if (rc < 0) {
3946896d41eSAndrew Jeffery 		if (errno != ECONNRESET)
3958e31cfd1SJeremy Kerr 			warn("can't receive from client");
39613a4041fSAndrew Jeffery 		rc = -1;
3978e31cfd1SJeremy Kerr 		goto out_close;
3988e31cfd1SJeremy Kerr 	}
3998e31cfd1SJeremy Kerr 
400195a7c5eSJeremy Kerr 	if (rc <= 0) {
4018e31cfd1SJeremy Kerr 		rc = -1;
4028e31cfd1SJeremy Kerr 		goto out_close;
4038e31cfd1SJeremy Kerr 	}
4048e31cfd1SJeremy Kerr 
405f49b2ac8SJeremy Kerr 	eid = *(uint8_t *)ctx->buf;
406d690d8eaSJeremy Kerr 
407f2988977SRashmica Gupta 	if (ctx->pcap.socket.path)
408f2988977SRashmica Gupta 		capture_socket(ctx->pcap.socket.dumper, ctx->buf, rc,
409f2988977SRashmica Gupta 			       MCTP_MESSAGE_CAPTURE_OUTGOING, eid);
410f2988977SRashmica Gupta 
4118e31cfd1SJeremy Kerr 	if (ctx->verbose)
412a721c2d8SPatrick Williams 		fprintf(stderr, "client[%d] sent message: dest 0x%02x len %d\n",
4138e31cfd1SJeremy Kerr 			idx, eid, rc - 1);
4148e31cfd1SJeremy Kerr 
415195a7c5eSJeremy Kerr 	if (eid == ctx->local_eid)
416f39c3857SSumanth Bhat 		rx_message(eid, MCTP_MESSAGE_TO_DST, 0, ctx, ctx->buf + 1,
417f39c3857SSumanth Bhat 			   rc - 1);
418195a7c5eSJeremy Kerr 	else
419f49b2ac8SJeremy Kerr 		tx_message(ctx, eid, ctx->buf + 1, rc - 1);
4208e31cfd1SJeremy Kerr 
4218e31cfd1SJeremy Kerr 	return 0;
4228e31cfd1SJeremy Kerr 
4238e31cfd1SJeremy Kerr out_close:
4248e31cfd1SJeremy Kerr 	client->active = false;
4258e31cfd1SJeremy Kerr 	return rc;
4268e31cfd1SJeremy Kerr }
4278e31cfd1SJeremy Kerr 
binding_init(struct ctx * ctx,const char * name,int argc,char * const * argv)428a721c2d8SPatrick Williams static int binding_init(struct ctx *ctx, const char *name, int argc,
429a721c2d8SPatrick Williams 			char *const *argv)
4308e31cfd1SJeremy Kerr {
4318e31cfd1SJeremy Kerr 	int rc;
4328e31cfd1SJeremy Kerr 
4338e31cfd1SJeremy Kerr 	ctx->binding = binding_lookup(name);
4348e31cfd1SJeremy Kerr 	if (!ctx->binding) {
4358e31cfd1SJeremy Kerr 		warnx("no such binding '%s'", name);
4368e31cfd1SJeremy Kerr 		return -1;
4378e31cfd1SJeremy Kerr 	}
4388e31cfd1SJeremy Kerr 
439a721c2d8SPatrick Williams 	rc = ctx->binding->init(ctx->mctp, ctx->binding, ctx->local_eid, argc,
440a721c2d8SPatrick Williams 				argv);
4418e31cfd1SJeremy Kerr 	return rc;
4428e31cfd1SJeremy Kerr }
4438e31cfd1SJeremy Kerr 
binding_destroy(struct ctx * ctx)444edebe169SAndrew Jeffery static void binding_destroy(struct ctx *ctx)
445edebe169SAndrew Jeffery {
446edebe169SAndrew Jeffery 	if (ctx->binding->destroy)
447edebe169SAndrew Jeffery 		ctx->binding->destroy(ctx->mctp, ctx->binding);
448edebe169SAndrew Jeffery }
449edebe169SAndrew Jeffery 
4508e31cfd1SJeremy Kerr enum {
4518e31cfd1SJeremy Kerr 	FD_BINDING = 0,
4528e31cfd1SJeremy Kerr 	FD_SOCKET,
453490e3873SAndrew Jeffery 	FD_SIGNAL,
4548e31cfd1SJeremy Kerr 	FD_NR,
4558e31cfd1SJeremy Kerr };
4568e31cfd1SJeremy Kerr 
run_daemon(struct ctx * ctx)4578e31cfd1SJeremy Kerr static int run_daemon(struct ctx *ctx)
4588e31cfd1SJeremy Kerr {
4598e31cfd1SJeremy Kerr 	bool clients_changed = false;
460490e3873SAndrew Jeffery 	sigset_t mask;
4618e31cfd1SJeremy Kerr 	int rc, i;
4628e31cfd1SJeremy Kerr 
4638e31cfd1SJeremy Kerr 	ctx->pollfds = malloc(FD_NR * sizeof(struct pollfd));
4648e31cfd1SJeremy Kerr 
4658f53d631SAndrew Jeffery 	if (!ctx->binding->init_pollfd) {
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 
5048f53d631SAndrew Jeffery 		if (ctx->binding->init_pollfd)
5058f53d631SAndrew Jeffery 			ctx->binding->init_pollfd(ctx->binding,
5068f53d631SAndrew Jeffery 						  &ctx->pollfds[FD_BINDING]);
5078e31cfd1SJeremy Kerr 		rc = poll(ctx->pollfds, ctx->n_clients + FD_NR, -1);
5088e31cfd1SJeremy Kerr 		if (rc < 0) {
5098e31cfd1SJeremy Kerr 			warn("poll failed");
5108e31cfd1SJeremy Kerr 			break;
5118e31cfd1SJeremy Kerr 		}
5128e31cfd1SJeremy Kerr 
5138e31cfd1SJeremy Kerr 		if (!rc)
5148e31cfd1SJeremy Kerr 			continue;
5158e31cfd1SJeremy Kerr 
516490e3873SAndrew Jeffery 		if (ctx->pollfds[FD_SIGNAL].revents) {
517490e3873SAndrew Jeffery 			struct signalfd_siginfo si;
518490e3873SAndrew Jeffery 			ssize_t got;
519490e3873SAndrew Jeffery 
520490e3873SAndrew Jeffery 			got = read(ctx->pollfds[FD_SIGNAL].fd, &si, sizeof(si));
521490e3873SAndrew Jeffery 			if (got == sizeof(si)) {
522490e3873SAndrew Jeffery 				warnx("Received %s, quitting",
523490e3873SAndrew Jeffery 				      strsignal(si.ssi_signo));
524490e3873SAndrew Jeffery 				rc = 0;
525490e3873SAndrew Jeffery 				break;
526490e3873SAndrew Jeffery 			} else {
527490e3873SAndrew Jeffery 				warnx("Unexpected read result for signalfd: %d",
528490e3873SAndrew Jeffery 				      rc);
529490e3873SAndrew Jeffery 				warnx("Quitting on the basis that signalfd became ready");
530490e3873SAndrew Jeffery 				rc = -1;
531490e3873SAndrew Jeffery 				break;
532490e3873SAndrew Jeffery 			}
533490e3873SAndrew Jeffery 		}
534490e3873SAndrew Jeffery 
5358e31cfd1SJeremy Kerr 		if (ctx->pollfds[FD_BINDING].revents) {
53634b9b3d8SJeremy Kerr 			rc = 0;
53734b9b3d8SJeremy Kerr 			if (ctx->binding->process)
5388e31cfd1SJeremy Kerr 				rc = ctx->binding->process(ctx->binding);
5398e31cfd1SJeremy Kerr 			if (rc)
5408e31cfd1SJeremy Kerr 				break;
5418e31cfd1SJeremy Kerr 		}
5428e31cfd1SJeremy Kerr 
5438e31cfd1SJeremy Kerr 		for (i = 0; i < ctx->n_clients; i++) {
5448e31cfd1SJeremy Kerr 			if (!ctx->pollfds[FD_NR + i].revents)
5458e31cfd1SJeremy Kerr 				continue;
5468e31cfd1SJeremy Kerr 
5478e31cfd1SJeremy Kerr 			rc = client_process_recv(ctx, i);
5488e31cfd1SJeremy Kerr 			if (rc)
5498e31cfd1SJeremy Kerr 				clients_changed = true;
5508e31cfd1SJeremy Kerr 		}
5518e31cfd1SJeremy Kerr 
5528e31cfd1SJeremy Kerr 		if (ctx->pollfds[FD_SOCKET].revents) {
5538e31cfd1SJeremy Kerr 			rc = socket_process(ctx);
5548e31cfd1SJeremy Kerr 			if (rc)
5558e31cfd1SJeremy Kerr 				break;
5568e31cfd1SJeremy Kerr 			clients_changed = true;
5578e31cfd1SJeremy Kerr 		}
5588e31cfd1SJeremy Kerr 
5598e31cfd1SJeremy Kerr 		if (clients_changed)
5608e31cfd1SJeremy Kerr 			client_remove_inactive(ctx);
5618e31cfd1SJeremy Kerr 	}
5628e31cfd1SJeremy Kerr 
5638e31cfd1SJeremy Kerr 	free(ctx->pollfds);
5648e31cfd1SJeremy Kerr 
5658e31cfd1SJeremy Kerr 	return rc;
5668e31cfd1SJeremy Kerr }
5678e31cfd1SJeremy Kerr 
5688e31cfd1SJeremy Kerr static const struct option options[] = {
569cad47301SAndrew Jeffery 	{ "capture-binding", required_argument, 0, 'b' },
570cad47301SAndrew Jeffery 	{ "capture-socket", required_argument, 0, 's' },
571cad47301SAndrew Jeffery 	{ "binding-linktype", required_argument, 0, 'B' },
572cad47301SAndrew Jeffery 	{ "socket-linktype", required_argument, 0, 'S' },
5738e31cfd1SJeremy Kerr 	{ "verbose", no_argument, 0, 'v' },
5748e31cfd1SJeremy Kerr 	{ "eid", required_argument, 0, 'e' },
5758e31cfd1SJeremy Kerr 	{ 0 },
5768e31cfd1SJeremy Kerr };
5778e31cfd1SJeremy Kerr 
usage(const char * progname)5788e31cfd1SJeremy Kerr static void usage(const char *progname)
5798e31cfd1SJeremy Kerr {
5808e31cfd1SJeremy Kerr 	unsigned int i;
5818e31cfd1SJeremy Kerr 
5828e31cfd1SJeremy Kerr 	fprintf(stderr, "usage: %s <binding> [params]\n", progname);
5838e31cfd1SJeremy Kerr 	fprintf(stderr, "Available bindings:\n");
5848e31cfd1SJeremy Kerr 	for (i = 0; i < ARRAY_SIZE(bindings); i++)
5858e31cfd1SJeremy Kerr 		fprintf(stderr, "  %s\n", bindings[i].name);
5868e31cfd1SJeremy Kerr }
5878e31cfd1SJeremy Kerr 
main(int argc,char * const * argv)5888e31cfd1SJeremy Kerr int main(int argc, char *const *argv)
5898e31cfd1SJeremy Kerr {
5908e31cfd1SJeremy Kerr 	struct ctx *ctx, _ctx;
5918e31cfd1SJeremy Kerr 	int rc;
5928e31cfd1SJeremy Kerr 
5938e31cfd1SJeremy Kerr 	ctx = &_ctx;
5948e31cfd1SJeremy Kerr 	ctx->clients = NULL;
5958e31cfd1SJeremy Kerr 	ctx->n_clients = 0;
5968e31cfd1SJeremy Kerr 	ctx->local_eid = local_eid_default;
59704b81fc7SAndrew Jeffery 	ctx->verbose = false;
598cad47301SAndrew Jeffery 	ctx->pcap.binding.path = NULL;
599cad47301SAndrew Jeffery 	ctx->pcap.socket.path = NULL;
6008e31cfd1SJeremy Kerr 
6018e31cfd1SJeremy Kerr 	for (;;) {
602cad47301SAndrew Jeffery 		rc = getopt_long(argc, argv, "b:es::v", options, NULL);
6038e31cfd1SJeremy Kerr 		if (rc == -1)
6048e31cfd1SJeremy Kerr 			break;
6058e31cfd1SJeremy Kerr 		switch (rc) {
606cad47301SAndrew Jeffery 		case 'b':
607cad47301SAndrew Jeffery 			ctx->pcap.binding.path = optarg;
608cad47301SAndrew Jeffery 			break;
609cad47301SAndrew Jeffery 		case 's':
610cad47301SAndrew Jeffery 			ctx->pcap.socket.path = optarg;
611cad47301SAndrew Jeffery 			break;
612cad47301SAndrew Jeffery 		case 'B':
613f2988977SRashmica Gupta 			fprintf(stderr,
614f2988977SRashmica Gupta 				"binding-linktype argument is deprecated\n");
615cad47301SAndrew Jeffery 			break;
616cad47301SAndrew Jeffery 		case 'S':
617f2988977SRashmica Gupta 			fprintf(stderr,
618f2988977SRashmica Gupta 				"socket-linktype argument is deprecated\n");
619cad47301SAndrew Jeffery 			break;
6208e31cfd1SJeremy Kerr 		case 'v':
6218e31cfd1SJeremy Kerr 			ctx->verbose = true;
6228e31cfd1SJeremy Kerr 			break;
6238e31cfd1SJeremy Kerr 		case 'e':
6248e31cfd1SJeremy Kerr 			ctx->local_eid = atoi(optarg);
6258e31cfd1SJeremy Kerr 			break;
6268e31cfd1SJeremy Kerr 		default:
6278e31cfd1SJeremy Kerr 			fprintf(stderr, "Invalid argument\n");
6288e31cfd1SJeremy Kerr 			return EXIT_FAILURE;
6298e31cfd1SJeremy Kerr 		}
6308e31cfd1SJeremy Kerr 	}
6318e31cfd1SJeremy Kerr 
6328e31cfd1SJeremy Kerr 	if (optind >= argc) {
6338e31cfd1SJeremy Kerr 		fprintf(stderr, "missing binding argument\n");
6348e31cfd1SJeremy Kerr 		usage(argv[0]);
6358e31cfd1SJeremy Kerr 		return EXIT_FAILURE;
6368e31cfd1SJeremy Kerr 	}
6378e31cfd1SJeremy Kerr 
638f49b2ac8SJeremy Kerr 	/* setup initial buffer */
639f49b2ac8SJeremy Kerr 	ctx->buf_size = 4096;
640f49b2ac8SJeremy Kerr 	ctx->buf = malloc(ctx->buf_size);
641f49b2ac8SJeremy Kerr 
642dca82599SAndrew Jeffery 	mctp_set_log_stdio(ctx->verbose ? MCTP_LOG_DEBUG : MCTP_LOG_NOTICE);
6430b278a63SJeremy Kerr 
6448e31cfd1SJeremy Kerr 	ctx->mctp = mctp_init();
6458e31cfd1SJeremy Kerr 	assert(ctx->mctp);
6468e31cfd1SJeremy Kerr 
647cad47301SAndrew Jeffery 	if (ctx->pcap.binding.path || ctx->pcap.socket.path) {
648cad47301SAndrew Jeffery 		if (capture_init()) {
649cad47301SAndrew Jeffery 			rc = EXIT_FAILURE;
650cad47301SAndrew Jeffery 			goto cleanup_mctp;
651cad47301SAndrew Jeffery 		}
652cad47301SAndrew Jeffery 	}
653cad47301SAndrew Jeffery 
654cad47301SAndrew Jeffery 	if (ctx->pcap.binding.path) {
655cad47301SAndrew Jeffery 		rc = capture_prepare(&ctx->pcap.binding);
656cad47301SAndrew Jeffery 		if (rc == -1) {
657a721c2d8SPatrick Williams 			fprintf(stderr, "Failed to initialise capture: %d\n",
658a721c2d8SPatrick Williams 				rc);
659cad47301SAndrew Jeffery 			rc = EXIT_FAILURE;
660cad47301SAndrew Jeffery 			goto cleanup_mctp;
661cad47301SAndrew Jeffery 		}
662cad47301SAndrew Jeffery 
663cad47301SAndrew Jeffery 		mctp_set_capture_handler(ctx->mctp, capture_binding,
664cad47301SAndrew Jeffery 					 ctx->pcap.binding.dumper);
665cad47301SAndrew Jeffery 	}
666cad47301SAndrew Jeffery 
667cad47301SAndrew Jeffery 	if (ctx->pcap.socket.path) {
668cad47301SAndrew Jeffery 		rc = capture_prepare(&ctx->pcap.socket);
669cad47301SAndrew Jeffery 		if (rc == -1) {
670a721c2d8SPatrick Williams 			fprintf(stderr, "Failed to initialise capture: %d\n",
671a721c2d8SPatrick Williams 				rc);
672cad47301SAndrew Jeffery 			rc = EXIT_FAILURE;
673cad47301SAndrew Jeffery 			goto cleanup_pcap_binding;
674cad47301SAndrew Jeffery 		}
675cad47301SAndrew Jeffery 	}
676cad47301SAndrew Jeffery 
677a721c2d8SPatrick Williams 	rc = binding_init(ctx, argv[optind], argc - optind - 1,
678a721c2d8SPatrick Williams 			  argv + optind + 1);
679cad47301SAndrew Jeffery 	if (rc) {
680cad47301SAndrew Jeffery 		fprintf(stderr, "Failed to initialise binding: %d\n", rc);
681cad47301SAndrew Jeffery 		rc = EXIT_FAILURE;
682cad47301SAndrew Jeffery 		goto cleanup_pcap_socket;
683cad47301SAndrew Jeffery 	}
6848e31cfd1SJeremy Kerr 
685d4103f8fSAndrew Jeffery 	rc = sd_listen_fds(true);
686d4103f8fSAndrew Jeffery 	if (rc <= 0) {
6878e31cfd1SJeremy Kerr 		rc = socket_init(ctx);
688cad47301SAndrew Jeffery 		if (rc) {
689cad47301SAndrew Jeffery 			fprintf(stderr, "Failed to initialse socket: %d\n", rc);
690edebe169SAndrew Jeffery 			goto cleanup_binding;
691cad47301SAndrew Jeffery 		}
692d4103f8fSAndrew Jeffery 	} else {
693d4103f8fSAndrew Jeffery 		ctx->sock = SD_LISTEN_FDS_START;
694d4103f8fSAndrew Jeffery 	}
6958e31cfd1SJeremy Kerr 
6968e31cfd1SJeremy Kerr 	rc = run_daemon(ctx);
6978e31cfd1SJeremy Kerr 
698edebe169SAndrew Jeffery cleanup_binding:
699edebe169SAndrew Jeffery 	binding_destroy(ctx);
700edebe169SAndrew Jeffery 
701cad47301SAndrew Jeffery cleanup_pcap_socket:
702cad47301SAndrew Jeffery 	if (ctx->pcap.socket.path)
703cad47301SAndrew Jeffery 		capture_close(&ctx->pcap.socket);
704cad47301SAndrew Jeffery 
705cad47301SAndrew Jeffery cleanup_pcap_binding:
706cad47301SAndrew Jeffery 	if (ctx->pcap.binding.path)
707cad47301SAndrew Jeffery 		capture_close(&ctx->pcap.binding);
708cad47301SAndrew Jeffery 
709cad47301SAndrew Jeffery 	rc = rc ? EXIT_FAILURE : EXIT_SUCCESS;
710cad47301SAndrew Jeffery cleanup_mctp:
711cad47301SAndrew Jeffery 
712cad47301SAndrew Jeffery 	return rc;
7138e31cfd1SJeremy Kerr }
714