xref: /openbmc/libmctp/utils/mctp-demux-daemon.c (revision 3ef47785801cd0091b4118eabdea6dd2fde15e73)
13d36ee2eSJeremy Kerr /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
23d36ee2eSJeremy Kerr 
38e31cfd1SJeremy Kerr #define _GNU_SOURCE
48e31cfd1SJeremy Kerr 
5*3ef47785SMatt Johnston #ifdef HAVE_CONFIG_H
6d4103f8fSAndrew Jeffery #include "config.h"
7*3ef47785SMatt Johnston #endif
85ab78259SAndrew Jeffery 
95ab78259SAndrew Jeffery #define SD_LISTEN_FDS_START 3
105ab78259SAndrew Jeffery 
115ab78259SAndrew Jeffery #include "compiler.h"
125ab78259SAndrew Jeffery #include "libmctp.h"
135ab78259SAndrew Jeffery #include "libmctp-serial.h"
145ab78259SAndrew Jeffery #include "libmctp-astlpc.h"
15cad47301SAndrew Jeffery #include "utils/mctp-capture.h"
16d4103f8fSAndrew Jeffery 
178e31cfd1SJeremy Kerr #include <assert.h>
188e31cfd1SJeremy Kerr #include <err.h>
196896d41eSAndrew Jeffery #include <errno.h>
208e31cfd1SJeremy Kerr #include <getopt.h>
21b93b6112SAndrew Jeffery #include <limits.h>
228e31cfd1SJeremy Kerr #include <poll.h>
23490e3873SAndrew Jeffery #include <signal.h>
2404b81fc7SAndrew Jeffery #include <stdbool.h>
258e31cfd1SJeremy Kerr #include <stdio.h>
268e31cfd1SJeremy Kerr #include <stdlib.h>
278e31cfd1SJeremy Kerr #include <string.h>
288e31cfd1SJeremy Kerr #include <unistd.h>
298e31cfd1SJeremy Kerr 
30490e3873SAndrew Jeffery #include <sys/signalfd.h>
318e31cfd1SJeremy Kerr #include <sys/socket.h>
328e31cfd1SJeremy Kerr #include <sys/un.h>
338e31cfd1SJeremy Kerr 
348e31cfd1SJeremy Kerr #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
358e31cfd1SJeremy Kerr 
36d4103f8fSAndrew Jeffery #if HAVE_SYSTEMD_SD_DAEMON_H
37d4103f8fSAndrew Jeffery #include <systemd/sd-daemon.h>
38d4103f8fSAndrew Jeffery #else
sd_listen_fds(int i __unused)39d4103f8fSAndrew Jeffery static inline int sd_listen_fds(int i __unused)
40d4103f8fSAndrew Jeffery {
41d4103f8fSAndrew Jeffery 	return -1;
42d4103f8fSAndrew Jeffery }
43d4103f8fSAndrew Jeffery #endif
44d4103f8fSAndrew Jeffery 
458e31cfd1SJeremy Kerr static const mctp_eid_t local_eid_default = 8;
468e31cfd1SJeremy Kerr static char sockname[] = "\0mctp-mux";
478e31cfd1SJeremy Kerr 
488e31cfd1SJeremy Kerr struct binding {
498e31cfd1SJeremy Kerr 	const char *name;
508f53d631SAndrew Jeffery 	int (*init)(struct mctp *mctp, struct binding *binding, mctp_eid_t eid,
518f53d631SAndrew Jeffery 		    int n_params, char *const *params);
52edebe169SAndrew Jeffery 	void (*destroy)(struct mctp *mctp, struct binding *binding);
538f53d631SAndrew Jeffery 	int (*init_pollfd)(struct binding *binding, struct pollfd *pollfd);
548e31cfd1SJeremy Kerr 	int (*process)(struct binding *binding);
558e31cfd1SJeremy Kerr 	void *data;
568e31cfd1SJeremy Kerr };
578e31cfd1SJeremy Kerr 
588e31cfd1SJeremy Kerr struct client {
598e31cfd1SJeremy Kerr 	bool active;
608e31cfd1SJeremy Kerr 	int sock;
618e31cfd1SJeremy Kerr 	uint8_t type;
628e31cfd1SJeremy Kerr };
638e31cfd1SJeremy Kerr 
648e31cfd1SJeremy Kerr struct ctx {
658e31cfd1SJeremy Kerr 	struct mctp *mctp;
668e31cfd1SJeremy Kerr 	struct binding *binding;
678e31cfd1SJeremy Kerr 	bool verbose;
688e31cfd1SJeremy Kerr 	int local_eid;
69*3ef47785SMatt Johnston 	uint8_t *buf;
70f49b2ac8SJeremy Kerr 	size_t buf_size;
718e31cfd1SJeremy Kerr 
728e31cfd1SJeremy Kerr 	int sock;
738e31cfd1SJeremy Kerr 	struct pollfd *pollfds;
748e31cfd1SJeremy Kerr 
758e31cfd1SJeremy Kerr 	struct client *clients;
768e31cfd1SJeremy Kerr 	int n_clients;
77cad47301SAndrew Jeffery 
78cad47301SAndrew Jeffery 	struct {
79cad47301SAndrew Jeffery 		struct capture binding;
80cad47301SAndrew Jeffery 		struct capture socket;
81cad47301SAndrew Jeffery 	} pcap;
828e31cfd1SJeremy Kerr };
838e31cfd1SJeremy Kerr 
tx_message(struct ctx * ctx,mctp_eid_t eid,void * msg,size_t len)848e31cfd1SJeremy Kerr static void tx_message(struct ctx *ctx, mctp_eid_t eid, void *msg, size_t len)
858e31cfd1SJeremy Kerr {
8606735055SAndrew Jeffery 	int rc;
8706735055SAndrew Jeffery 
88f39c3857SSumanth Bhat 	rc = mctp_message_tx(ctx->mctp, eid, MCTP_MESSAGE_TO_SRC, 0, msg, len);
8906735055SAndrew Jeffery 	if (rc)
9006735055SAndrew Jeffery 		warnx("Failed to send message: %d", rc);
918e31cfd1SJeremy Kerr }
928e31cfd1SJeremy Kerr 
client_remove_inactive(struct ctx * ctx)938e31cfd1SJeremy Kerr static void client_remove_inactive(struct ctx *ctx)
948e31cfd1SJeremy Kerr {
958e31cfd1SJeremy Kerr 	int i;
968e31cfd1SJeremy Kerr 
978e31cfd1SJeremy Kerr 	for (i = 0; i < ctx->n_clients; i++) {
988e31cfd1SJeremy Kerr 		struct client *client = &ctx->clients[i];
998e31cfd1SJeremy Kerr 		if (client->active)
1008e31cfd1SJeremy Kerr 			continue;
1018e31cfd1SJeremy Kerr 		close(client->sock);
1028e31cfd1SJeremy Kerr 
1038e31cfd1SJeremy Kerr 		ctx->n_clients--;
1048e31cfd1SJeremy Kerr 		memmove(&ctx->clients[i], &ctx->clients[i + 1],
1058e31cfd1SJeremy Kerr 			(ctx->n_clients - i) * sizeof(*ctx->clients));
1068e31cfd1SJeremy Kerr 		ctx->clients = realloc(ctx->clients,
1078e31cfd1SJeremy Kerr 				       ctx->n_clients * sizeof(*ctx->clients));
1088e31cfd1SJeremy Kerr 	}
1098e31cfd1SJeremy Kerr }
1108e31cfd1SJeremy Kerr 
rx_message(uint8_t eid,bool tag_owner __unused,uint8_t msg_tag __unused,void * data,void * msg,size_t len)111a721c2d8SPatrick Williams static void rx_message(uint8_t eid, bool tag_owner __unused,
112a721c2d8SPatrick Williams 		       uint8_t msg_tag __unused, void *data, void *msg,
113a721c2d8SPatrick Williams 		       size_t len)
1148e31cfd1SJeremy Kerr {
1158e31cfd1SJeremy Kerr 	struct ctx *ctx = data;
1168e31cfd1SJeremy Kerr 	struct iovec iov[2];
1178e31cfd1SJeremy Kerr 	struct msghdr msghdr;
1188e31cfd1SJeremy Kerr 	bool removed;
1198e31cfd1SJeremy Kerr 	uint8_t type;
1208e31cfd1SJeremy Kerr 	int i, rc;
1218e31cfd1SJeremy Kerr 
1228e31cfd1SJeremy Kerr 	if (len < 2)
1238e31cfd1SJeremy Kerr 		return;
1248e31cfd1SJeremy Kerr 
1258e31cfd1SJeremy Kerr 	type = *(uint8_t *)msg;
1268e31cfd1SJeremy Kerr 
1278e31cfd1SJeremy Kerr 	if (ctx->verbose)
1288e31cfd1SJeremy Kerr 		fprintf(stderr, "MCTP message received: len %zd, type %d\n",
1298e31cfd1SJeremy Kerr 			len, type);
1308e31cfd1SJeremy Kerr 
1318e31cfd1SJeremy Kerr 	memset(&msghdr, 0, sizeof(msghdr));
1328e31cfd1SJeremy Kerr 	msghdr.msg_iov = iov;
1338e31cfd1SJeremy Kerr 	msghdr.msg_iovlen = 2;
1348e31cfd1SJeremy Kerr 	iov[0].iov_base = &eid;
1358e31cfd1SJeremy Kerr 	iov[0].iov_len = 1;
1368e31cfd1SJeremy Kerr 	iov[1].iov_base = msg;
1378e31cfd1SJeremy Kerr 	iov[1].iov_len = len;
1388e31cfd1SJeremy Kerr 
1398e31cfd1SJeremy Kerr 	for (i = 0; i < ctx->n_clients; i++) {
1408e31cfd1SJeremy Kerr 		struct client *client = &ctx->clients[i];
1418e31cfd1SJeremy Kerr 
1428e31cfd1SJeremy Kerr 		if (client->type != type)
1438e31cfd1SJeremy Kerr 			continue;
1448e31cfd1SJeremy Kerr 
1458e31cfd1SJeremy Kerr 		if (ctx->verbose)
1468e31cfd1SJeremy Kerr 			fprintf(stderr, "  forwarding to client %d\n", i);
1478e31cfd1SJeremy Kerr 
1488e31cfd1SJeremy Kerr 		rc = sendmsg(client->sock, &msghdr, 0);
1498e31cfd1SJeremy Kerr 		if (rc != (ssize_t)(len + 1)) {
1508e31cfd1SJeremy Kerr 			client->active = false;
1518e31cfd1SJeremy Kerr 			removed = true;
1528e31cfd1SJeremy Kerr 		}
1538e31cfd1SJeremy Kerr 	}
1548e31cfd1SJeremy Kerr 
1558e31cfd1SJeremy Kerr 	if (removed)
1568e31cfd1SJeremy Kerr 		client_remove_inactive(ctx);
1578e31cfd1SJeremy Kerr }
1588e31cfd1SJeremy Kerr 
binding_null_init(struct mctp * mctp __unused,struct binding * binding __unused,mctp_eid_t eid __unused,int n_params,char * const * params __unused)15934b9b3d8SJeremy Kerr static int binding_null_init(struct mctp *mctp __unused,
16034b9b3d8SJeremy Kerr 			     struct binding *binding __unused,
161a721c2d8SPatrick Williams 			     mctp_eid_t eid __unused, int n_params,
162a721c2d8SPatrick Williams 			     char *const *params __unused)
16334b9b3d8SJeremy Kerr {
16434b9b3d8SJeremy Kerr 	if (n_params != 0) {
16534b9b3d8SJeremy Kerr 		warnx("null binding doesn't accept parameters");
16634b9b3d8SJeremy Kerr 		return -1;
16734b9b3d8SJeremy Kerr 	}
16834b9b3d8SJeremy Kerr 	return 0;
16934b9b3d8SJeremy Kerr }
17034b9b3d8SJeremy Kerr 
binding_serial_init(struct mctp * mctp,struct binding * binding,mctp_eid_t eid,int n_params,char * const * params)1718e31cfd1SJeremy Kerr static int binding_serial_init(struct mctp *mctp, struct binding *binding,
172a721c2d8SPatrick Williams 			       mctp_eid_t eid, int n_params,
173a721c2d8SPatrick Williams 			       char *const *params)
1748e31cfd1SJeremy Kerr {
1758e31cfd1SJeremy Kerr 	struct mctp_binding_serial *serial;
1768e31cfd1SJeremy Kerr 	const char *path;
1778e31cfd1SJeremy Kerr 	int rc;
1788e31cfd1SJeremy Kerr 
1798e31cfd1SJeremy Kerr 	if (n_params != 1) {
1808e31cfd1SJeremy Kerr 		warnx("serial binding requires device param");
1818e31cfd1SJeremy Kerr 		return -1;
1828e31cfd1SJeremy Kerr 	}
1838e31cfd1SJeremy Kerr 
1848e31cfd1SJeremy Kerr 	path = params[0];
1858e31cfd1SJeremy Kerr 
1868e31cfd1SJeremy Kerr 	serial = mctp_serial_init();
1878e31cfd1SJeremy Kerr 	assert(serial);
1888e31cfd1SJeremy Kerr 
1898e31cfd1SJeremy Kerr 	rc = mctp_serial_open_path(serial, path);
1908e31cfd1SJeremy Kerr 	if (rc)
1918e31cfd1SJeremy Kerr 		return -1;
1928e31cfd1SJeremy Kerr 
1933b36d17cSJeremy Kerr 	mctp_register_bus(mctp, mctp_binding_serial_core(serial), eid);
1948e31cfd1SJeremy Kerr 
1958e31cfd1SJeremy Kerr 	binding->data = serial;
1968e31cfd1SJeremy Kerr 
1978e31cfd1SJeremy Kerr 	return 0;
1988e31cfd1SJeremy Kerr }
1998e31cfd1SJeremy Kerr 
binding_serial_init_pollfd(struct binding * binding,struct pollfd * pollfd)2008f53d631SAndrew Jeffery static int binding_serial_init_pollfd(struct binding *binding,
2018f53d631SAndrew Jeffery 				      struct pollfd *pollfd)
2028e31cfd1SJeremy Kerr {
2038f53d631SAndrew Jeffery 	return mctp_serial_init_pollfd(binding->data, pollfd);
2048e31cfd1SJeremy Kerr }
2058e31cfd1SJeremy Kerr 
binding_serial_process(struct binding * binding)2068e31cfd1SJeremy Kerr static int binding_serial_process(struct binding *binding)
2078e31cfd1SJeremy Kerr {
2088e31cfd1SJeremy Kerr 	return mctp_serial_read(binding->data);
2098e31cfd1SJeremy Kerr }
2108e31cfd1SJeremy Kerr 
binding_astlpc_init(struct mctp * mctp,struct binding * binding,mctp_eid_t eid,int n_params,char * const * params)2118e31cfd1SJeremy Kerr static int binding_astlpc_init(struct mctp *mctp, struct binding *binding,
2128e31cfd1SJeremy Kerr 			       mctp_eid_t eid, int n_params,
2138e31cfd1SJeremy Kerr 			       char *const *params __attribute__((unused)))
2148e31cfd1SJeremy Kerr {
2158e31cfd1SJeremy Kerr 	struct mctp_binding_astlpc *astlpc;
216400766f9SKonstantin Aladyshev 	const char *path;
2178e31cfd1SJeremy Kerr 
218400766f9SKonstantin Aladyshev 	if (n_params != 1) {
219400766f9SKonstantin Aladyshev 		warnx("astlpc binding requires kcs device param");
2208e31cfd1SJeremy Kerr 		return -1;
2218e31cfd1SJeremy Kerr 	}
2228e31cfd1SJeremy Kerr 
223400766f9SKonstantin Aladyshev 	path = params[0];
224400766f9SKonstantin Aladyshev 
225400766f9SKonstantin Aladyshev 	astlpc = mctp_astlpc_init_fileio(path);
2268e31cfd1SJeremy Kerr 	if (!astlpc) {
2278e31cfd1SJeremy Kerr 		warnx("could not initialise astlpc binding");
2288e31cfd1SJeremy Kerr 		return -1;
2298e31cfd1SJeremy Kerr 	}
2308e31cfd1SJeremy Kerr 
2313b36d17cSJeremy Kerr 	mctp_register_bus(mctp, mctp_binding_astlpc_core(astlpc), eid);
2323b36d17cSJeremy Kerr 
2338e31cfd1SJeremy Kerr 	binding->data = astlpc;
2348e31cfd1SJeremy Kerr 	return 0;
2358e31cfd1SJeremy Kerr }
2368e31cfd1SJeremy Kerr 
binding_astlpc_destroy(struct mctp * mctp,struct binding * binding)237edebe169SAndrew Jeffery static void binding_astlpc_destroy(struct mctp *mctp, struct binding *binding)
238edebe169SAndrew Jeffery {
239edebe169SAndrew Jeffery 	struct mctp_binding_astlpc *astlpc = binding->data;
240edebe169SAndrew Jeffery 
241edebe169SAndrew Jeffery 	mctp_unregister_bus(mctp, mctp_binding_astlpc_core(astlpc));
242edebe169SAndrew Jeffery 
243edebe169SAndrew Jeffery 	mctp_astlpc_destroy(astlpc);
244edebe169SAndrew Jeffery }
245edebe169SAndrew Jeffery 
binding_astlpc_init_pollfd(struct binding * binding,struct pollfd * pollfd)2468f53d631SAndrew Jeffery static int binding_astlpc_init_pollfd(struct binding *binding,
2478f53d631SAndrew Jeffery 				      struct pollfd *pollfd)
2488e31cfd1SJeremy Kerr {
2498f53d631SAndrew Jeffery 	return mctp_astlpc_init_pollfd(binding->data, pollfd);
2508e31cfd1SJeremy Kerr }
2518e31cfd1SJeremy Kerr 
binding_astlpc_process(struct binding * binding)2528e31cfd1SJeremy Kerr static int binding_astlpc_process(struct binding *binding)
2538e31cfd1SJeremy Kerr {
2548e31cfd1SJeremy Kerr 	return mctp_astlpc_poll(binding->data);
2558e31cfd1SJeremy Kerr }
2568e31cfd1SJeremy Kerr 
257a721c2d8SPatrick Williams struct binding bindings[] = { {
25834b9b3d8SJeremy Kerr 				      .name = "null",
25934b9b3d8SJeremy Kerr 				      .init = binding_null_init,
26034b9b3d8SJeremy Kerr 			      },
26134b9b3d8SJeremy Kerr 			      {
2628e31cfd1SJeremy Kerr 				      .name = "serial",
2638e31cfd1SJeremy Kerr 				      .init = binding_serial_init,
264edebe169SAndrew Jeffery 				      .destroy = NULL,
2658f53d631SAndrew Jeffery 				      .init_pollfd = binding_serial_init_pollfd,
2668e31cfd1SJeremy Kerr 				      .process = binding_serial_process,
2678e31cfd1SJeremy Kerr 			      },
2688e31cfd1SJeremy Kerr 			      {
2698e31cfd1SJeremy Kerr 				      .name = "astlpc",
2708e31cfd1SJeremy Kerr 				      .init = binding_astlpc_init,
271edebe169SAndrew Jeffery 				      .destroy = binding_astlpc_destroy,
2728f53d631SAndrew Jeffery 				      .init_pollfd = binding_astlpc_init_pollfd,
2738e31cfd1SJeremy Kerr 				      .process = binding_astlpc_process,
274a721c2d8SPatrick Williams 			      } };
2758e31cfd1SJeremy Kerr 
binding_lookup(const char * name)2768e31cfd1SJeremy Kerr struct binding *binding_lookup(const char *name)
2778e31cfd1SJeremy Kerr {
2788e31cfd1SJeremy Kerr 	struct binding *binding;
2798e31cfd1SJeremy Kerr 	unsigned int i;
2808e31cfd1SJeremy Kerr 
2818e31cfd1SJeremy Kerr 	for (i = 0; i < ARRAY_SIZE(bindings); i++) {
2828e31cfd1SJeremy Kerr 		binding = &bindings[i];
2838e31cfd1SJeremy Kerr 
2848e31cfd1SJeremy Kerr 		if (!strcmp(binding->name, name))
2858e31cfd1SJeremy Kerr 			return binding;
2868e31cfd1SJeremy Kerr 	}
2878e31cfd1SJeremy Kerr 
2888e31cfd1SJeremy Kerr 	return NULL;
2898e31cfd1SJeremy Kerr }
2908e31cfd1SJeremy Kerr 
socket_init(struct ctx * ctx)2918e31cfd1SJeremy Kerr static int socket_init(struct ctx *ctx)
2928e31cfd1SJeremy Kerr {
2938e31cfd1SJeremy Kerr 	struct sockaddr_un addr;
2948e31cfd1SJeremy Kerr 	int namelen, rc;
2958e31cfd1SJeremy Kerr 
2968e31cfd1SJeremy Kerr 	namelen = sizeof(sockname) - 1;
2978e31cfd1SJeremy Kerr 	addr.sun_family = AF_UNIX;
2988e31cfd1SJeremy Kerr 	memcpy(addr.sun_path, sockname, namelen);
2998e31cfd1SJeremy Kerr 
3008e31cfd1SJeremy Kerr 	ctx->sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
3018e31cfd1SJeremy Kerr 	if (ctx->sock < 0) {
3028e31cfd1SJeremy Kerr 		warn("can't create socket");
3038e31cfd1SJeremy Kerr 		return -1;
3048e31cfd1SJeremy Kerr 	}
3058e31cfd1SJeremy Kerr 
3068e31cfd1SJeremy Kerr 	rc = bind(ctx->sock, (struct sockaddr *)&addr,
3078e31cfd1SJeremy Kerr 		  sizeof(addr.sun_family) + namelen);
3088e31cfd1SJeremy Kerr 	if (rc) {
3098e31cfd1SJeremy Kerr 		warn("can't bind socket");
3108e31cfd1SJeremy Kerr 		goto err_close;
3118e31cfd1SJeremy Kerr 	}
3128e31cfd1SJeremy Kerr 
3138e31cfd1SJeremy Kerr 	rc = listen(ctx->sock, 1);
3148e31cfd1SJeremy Kerr 	if (rc) {
3158e31cfd1SJeremy Kerr 		warn("can't listen on socket");
3168e31cfd1SJeremy Kerr 		goto err_close;
3178e31cfd1SJeremy Kerr 	}
3188e31cfd1SJeremy Kerr 
3198e31cfd1SJeremy Kerr 	return 0;
3208e31cfd1SJeremy Kerr 
3218e31cfd1SJeremy Kerr err_close:
3228e31cfd1SJeremy Kerr 	close(ctx->sock);
3238e31cfd1SJeremy Kerr 	return -1;
3248e31cfd1SJeremy Kerr }
3258e31cfd1SJeremy Kerr 
socket_process(struct ctx * ctx)3268e31cfd1SJeremy Kerr static int socket_process(struct ctx *ctx)
3278e31cfd1SJeremy Kerr {
3288e31cfd1SJeremy Kerr 	struct client *client;
3298e31cfd1SJeremy Kerr 	int fd;
3308e31cfd1SJeremy Kerr 
3318e31cfd1SJeremy Kerr 	fd = accept4(ctx->sock, NULL, 0, SOCK_NONBLOCK);
3328e31cfd1SJeremy Kerr 	if (fd < 0)
3338e31cfd1SJeremy Kerr 		return -1;
3348e31cfd1SJeremy Kerr 
3358e31cfd1SJeremy Kerr 	ctx->n_clients++;
336a721c2d8SPatrick Williams 	ctx->clients =
337a721c2d8SPatrick Williams 		realloc(ctx->clients, ctx->n_clients * sizeof(struct client));
3388e31cfd1SJeremy Kerr 
3398e31cfd1SJeremy Kerr 	client = &ctx->clients[ctx->n_clients - 1];
3408676c934SAndrew Jeffery 	memset(client, 0, sizeof(*client));
3418e31cfd1SJeremy Kerr 	client->active = true;
3428e31cfd1SJeremy Kerr 	client->sock = fd;
3438e31cfd1SJeremy Kerr 
3448e31cfd1SJeremy Kerr 	return 0;
3458e31cfd1SJeremy Kerr }
3468e31cfd1SJeremy Kerr 
client_process_recv(struct ctx * ctx,int idx)3478e31cfd1SJeremy Kerr static int client_process_recv(struct ctx *ctx, int idx)
3488e31cfd1SJeremy Kerr {
3498e31cfd1SJeremy Kerr 	struct client *client = &ctx->clients[idx];
350f49b2ac8SJeremy Kerr 	uint8_t eid;
351f49b2ac8SJeremy Kerr 	ssize_t len;
3528e31cfd1SJeremy Kerr 	int rc;
3538e31cfd1SJeremy Kerr 
3548e31cfd1SJeremy Kerr 	/* are we waiting for a type message? */
3558e31cfd1SJeremy Kerr 	if (!client->type) {
3568e31cfd1SJeremy Kerr 		uint8_t type;
3578e31cfd1SJeremy Kerr 		rc = read(client->sock, &type, 1);
3588e31cfd1SJeremy Kerr 		if (rc <= 0)
3598e31cfd1SJeremy Kerr 			goto out_close;
3608e31cfd1SJeremy Kerr 
3618e31cfd1SJeremy Kerr 		if (type == 0) {
3628e31cfd1SJeremy Kerr 			rc = -1;
3638e31cfd1SJeremy Kerr 			goto out_close;
3648e31cfd1SJeremy Kerr 		}
3658e31cfd1SJeremy Kerr 		if (ctx->verbose)
3668e31cfd1SJeremy Kerr 			fprintf(stderr, "client[%d] registered for type %u\n",
3678e31cfd1SJeremy Kerr 				idx, type);
3688e31cfd1SJeremy Kerr 		client->type = type;
3698e31cfd1SJeremy Kerr 		return 0;
3708e31cfd1SJeremy Kerr 	}
3718e31cfd1SJeremy Kerr 
372f49b2ac8SJeremy Kerr 	len = recv(client->sock, NULL, 0, MSG_PEEK | MSG_TRUNC);
373f49b2ac8SJeremy Kerr 	if (len < 0) {
3746896d41eSAndrew Jeffery 		if (errno != ECONNRESET)
375f49b2ac8SJeremy Kerr 			warn("can't receive (peek) from client");
3766896d41eSAndrew Jeffery 
37713a4041fSAndrew Jeffery 		rc = -1;
378f49b2ac8SJeremy Kerr 		goto out_close;
379f49b2ac8SJeremy Kerr 	}
380f49b2ac8SJeremy Kerr 
381b93b6112SAndrew Jeffery 	if ((size_t)len > ctx->buf_size) {
382f49b2ac8SJeremy Kerr 		void *tmp;
383f49b2ac8SJeremy Kerr 
384f49b2ac8SJeremy Kerr 		tmp = realloc(ctx->buf, len);
385f49b2ac8SJeremy Kerr 		if (!tmp) {
386f49b2ac8SJeremy Kerr 			warn("can't allocate for incoming message");
38713a4041fSAndrew Jeffery 			rc = -1;
388f49b2ac8SJeremy Kerr 			goto out_close;
389f49b2ac8SJeremy Kerr 		}
390f49b2ac8SJeremy Kerr 		ctx->buf = tmp;
391f49b2ac8SJeremy Kerr 		ctx->buf_size = len;
392f49b2ac8SJeremy Kerr 	}
393f49b2ac8SJeremy Kerr 
394f49b2ac8SJeremy Kerr 	rc = recv(client->sock, ctx->buf, ctx->buf_size, 0);
3958e31cfd1SJeremy Kerr 	if (rc < 0) {
3966896d41eSAndrew Jeffery 		if (errno != ECONNRESET)
3978e31cfd1SJeremy Kerr 			warn("can't receive from client");
39813a4041fSAndrew Jeffery 		rc = -1;
3998e31cfd1SJeremy Kerr 		goto out_close;
4008e31cfd1SJeremy Kerr 	}
4018e31cfd1SJeremy Kerr 
402195a7c5eSJeremy Kerr 	if (rc <= 0) {
4038e31cfd1SJeremy Kerr 		rc = -1;
4048e31cfd1SJeremy Kerr 		goto out_close;
4058e31cfd1SJeremy Kerr 	}
4068e31cfd1SJeremy Kerr 
407f49b2ac8SJeremy Kerr 	eid = *(uint8_t *)ctx->buf;
408d690d8eaSJeremy Kerr 
409f2988977SRashmica Gupta 	if (ctx->pcap.socket.path)
410f2988977SRashmica Gupta 		capture_socket(ctx->pcap.socket.dumper, ctx->buf, rc,
411f2988977SRashmica Gupta 			       MCTP_MESSAGE_CAPTURE_OUTGOING, eid);
412f2988977SRashmica Gupta 
4138e31cfd1SJeremy Kerr 	if (ctx->verbose)
414a721c2d8SPatrick Williams 		fprintf(stderr, "client[%d] sent message: dest 0x%02x len %d\n",
4158e31cfd1SJeremy Kerr 			idx, eid, rc - 1);
4168e31cfd1SJeremy Kerr 
417195a7c5eSJeremy Kerr 	if (eid == ctx->local_eid)
418f39c3857SSumanth Bhat 		rx_message(eid, MCTP_MESSAGE_TO_DST, 0, ctx, ctx->buf + 1,
419f39c3857SSumanth Bhat 			   rc - 1);
420195a7c5eSJeremy Kerr 	else
421f49b2ac8SJeremy Kerr 		tx_message(ctx, eid, ctx->buf + 1, rc - 1);
4228e31cfd1SJeremy Kerr 
4238e31cfd1SJeremy Kerr 	return 0;
4248e31cfd1SJeremy Kerr 
4258e31cfd1SJeremy Kerr out_close:
4268e31cfd1SJeremy Kerr 	client->active = false;
4278e31cfd1SJeremy Kerr 	return rc;
4288e31cfd1SJeremy Kerr }
4298e31cfd1SJeremy Kerr 
binding_init(struct ctx * ctx,const char * name,int argc,char * const * argv)430a721c2d8SPatrick Williams static int binding_init(struct ctx *ctx, const char *name, int argc,
431a721c2d8SPatrick Williams 			char *const *argv)
4328e31cfd1SJeremy Kerr {
4338e31cfd1SJeremy Kerr 	int rc;
4348e31cfd1SJeremy Kerr 
4358e31cfd1SJeremy Kerr 	ctx->binding = binding_lookup(name);
4368e31cfd1SJeremy Kerr 	if (!ctx->binding) {
4378e31cfd1SJeremy Kerr 		warnx("no such binding '%s'", name);
4388e31cfd1SJeremy Kerr 		return -1;
4398e31cfd1SJeremy Kerr 	}
4408e31cfd1SJeremy Kerr 
441a721c2d8SPatrick Williams 	rc = ctx->binding->init(ctx->mctp, ctx->binding, ctx->local_eid, argc,
442a721c2d8SPatrick Williams 				argv);
4438e31cfd1SJeremy Kerr 	return rc;
4448e31cfd1SJeremy Kerr }
4458e31cfd1SJeremy Kerr 
binding_destroy(struct ctx * ctx)446edebe169SAndrew Jeffery static void binding_destroy(struct ctx *ctx)
447edebe169SAndrew Jeffery {
448edebe169SAndrew Jeffery 	if (ctx->binding->destroy)
449edebe169SAndrew Jeffery 		ctx->binding->destroy(ctx->mctp, ctx->binding);
450edebe169SAndrew Jeffery }
451edebe169SAndrew Jeffery 
4528e31cfd1SJeremy Kerr enum {
4538e31cfd1SJeremy Kerr 	FD_BINDING = 0,
4548e31cfd1SJeremy Kerr 	FD_SOCKET,
455490e3873SAndrew Jeffery 	FD_SIGNAL,
4568e31cfd1SJeremy Kerr 	FD_NR,
4578e31cfd1SJeremy Kerr };
4588e31cfd1SJeremy Kerr 
run_daemon(struct ctx * ctx)4598e31cfd1SJeremy Kerr static int run_daemon(struct ctx *ctx)
4608e31cfd1SJeremy Kerr {
4618e31cfd1SJeremy Kerr 	bool clients_changed = false;
462490e3873SAndrew Jeffery 	sigset_t mask;
4638e31cfd1SJeremy Kerr 	int rc, i;
4648e31cfd1SJeremy Kerr 
4658e31cfd1SJeremy Kerr 	ctx->pollfds = malloc(FD_NR * sizeof(struct pollfd));
4668e31cfd1SJeremy Kerr 
4678f53d631SAndrew Jeffery 	if (!ctx->binding->init_pollfd) {
46834b9b3d8SJeremy Kerr 		ctx->pollfds[FD_BINDING].fd = -1;
46934b9b3d8SJeremy Kerr 		ctx->pollfds[FD_BINDING].events = 0;
47034b9b3d8SJeremy Kerr 	}
4718e31cfd1SJeremy Kerr 
472490e3873SAndrew Jeffery 	sigemptyset(&mask);
473490e3873SAndrew Jeffery 	sigaddset(&mask, SIGINT);
474490e3873SAndrew Jeffery 	sigaddset(&mask, SIGTERM);
475490e3873SAndrew Jeffery 	sigaddset(&mask, SIGQUIT);
476490e3873SAndrew Jeffery 
477490e3873SAndrew Jeffery 	if ((rc = sigprocmask(SIG_BLOCK, &mask, NULL)) == -1) {
478490e3873SAndrew Jeffery 		warn("sigprocmask");
479490e3873SAndrew Jeffery 		return rc;
480490e3873SAndrew Jeffery 	}
481490e3873SAndrew Jeffery 
482490e3873SAndrew Jeffery 	ctx->pollfds[FD_SIGNAL].fd = signalfd(-1, &mask, 0);
483490e3873SAndrew Jeffery 	ctx->pollfds[FD_SIGNAL].events = POLLIN;
484490e3873SAndrew Jeffery 
4858e31cfd1SJeremy Kerr 	ctx->pollfds[FD_SOCKET].fd = ctx->sock;
4868e31cfd1SJeremy Kerr 	ctx->pollfds[FD_SOCKET].events = POLLIN;
4878e31cfd1SJeremy Kerr 
4888e31cfd1SJeremy Kerr 	mctp_set_rx_all(ctx->mctp, rx_message, ctx);
4898e31cfd1SJeremy Kerr 
4908e31cfd1SJeremy Kerr 	for (;;) {
4918e31cfd1SJeremy Kerr 		if (clients_changed) {
4928e31cfd1SJeremy Kerr 			int i;
4938e31cfd1SJeremy Kerr 
4948e31cfd1SJeremy Kerr 			ctx->pollfds = realloc(ctx->pollfds,
4958e31cfd1SJeremy Kerr 					       (ctx->n_clients + FD_NR) *
4968e31cfd1SJeremy Kerr 						       sizeof(struct pollfd));
4978e31cfd1SJeremy Kerr 
4988e31cfd1SJeremy Kerr 			for (i = 0; i < ctx->n_clients; i++) {
4998e31cfd1SJeremy Kerr 				ctx->pollfds[FD_NR + i].fd =
5008e31cfd1SJeremy Kerr 					ctx->clients[i].sock;
5018e31cfd1SJeremy Kerr 				ctx->pollfds[FD_NR + i].events = POLLIN;
5028e31cfd1SJeremy Kerr 			}
5038e31cfd1SJeremy Kerr 			clients_changed = false;
5048e31cfd1SJeremy Kerr 		}
5058e31cfd1SJeremy Kerr 
5068f53d631SAndrew Jeffery 		if (ctx->binding->init_pollfd)
5078f53d631SAndrew Jeffery 			ctx->binding->init_pollfd(ctx->binding,
5088f53d631SAndrew Jeffery 						  &ctx->pollfds[FD_BINDING]);
5098e31cfd1SJeremy Kerr 		rc = poll(ctx->pollfds, ctx->n_clients + FD_NR, -1);
5108e31cfd1SJeremy Kerr 		if (rc < 0) {
5118e31cfd1SJeremy Kerr 			warn("poll failed");
5128e31cfd1SJeremy Kerr 			break;
5138e31cfd1SJeremy Kerr 		}
5148e31cfd1SJeremy Kerr 
5158e31cfd1SJeremy Kerr 		if (!rc)
5168e31cfd1SJeremy Kerr 			continue;
5178e31cfd1SJeremy Kerr 
518490e3873SAndrew Jeffery 		if (ctx->pollfds[FD_SIGNAL].revents) {
519490e3873SAndrew Jeffery 			struct signalfd_siginfo si;
520490e3873SAndrew Jeffery 			ssize_t got;
521490e3873SAndrew Jeffery 
522490e3873SAndrew Jeffery 			got = read(ctx->pollfds[FD_SIGNAL].fd, &si, sizeof(si));
523490e3873SAndrew Jeffery 			if (got == sizeof(si)) {
524490e3873SAndrew Jeffery 				warnx("Received %s, quitting",
525490e3873SAndrew Jeffery 				      strsignal(si.ssi_signo));
526490e3873SAndrew Jeffery 				rc = 0;
527490e3873SAndrew Jeffery 				break;
528490e3873SAndrew Jeffery 			} else {
529490e3873SAndrew Jeffery 				warnx("Unexpected read result for signalfd: %d",
530490e3873SAndrew Jeffery 				      rc);
531490e3873SAndrew Jeffery 				warnx("Quitting on the basis that signalfd became ready");
532490e3873SAndrew Jeffery 				rc = -1;
533490e3873SAndrew Jeffery 				break;
534490e3873SAndrew Jeffery 			}
535490e3873SAndrew Jeffery 		}
536490e3873SAndrew Jeffery 
5378e31cfd1SJeremy Kerr 		if (ctx->pollfds[FD_BINDING].revents) {
53834b9b3d8SJeremy Kerr 			rc = 0;
53934b9b3d8SJeremy Kerr 			if (ctx->binding->process)
5408e31cfd1SJeremy Kerr 				rc = ctx->binding->process(ctx->binding);
5418e31cfd1SJeremy Kerr 			if (rc)
5428e31cfd1SJeremy Kerr 				break;
5438e31cfd1SJeremy Kerr 		}
5448e31cfd1SJeremy Kerr 
5458e31cfd1SJeremy Kerr 		for (i = 0; i < ctx->n_clients; i++) {
5468e31cfd1SJeremy Kerr 			if (!ctx->pollfds[FD_NR + i].revents)
5478e31cfd1SJeremy Kerr 				continue;
5488e31cfd1SJeremy Kerr 
5498e31cfd1SJeremy Kerr 			rc = client_process_recv(ctx, i);
5508e31cfd1SJeremy Kerr 			if (rc)
5518e31cfd1SJeremy Kerr 				clients_changed = true;
5528e31cfd1SJeremy Kerr 		}
5538e31cfd1SJeremy Kerr 
5548e31cfd1SJeremy Kerr 		if (ctx->pollfds[FD_SOCKET].revents) {
5558e31cfd1SJeremy Kerr 			rc = socket_process(ctx);
5568e31cfd1SJeremy Kerr 			if (rc)
5578e31cfd1SJeremy Kerr 				break;
5588e31cfd1SJeremy Kerr 			clients_changed = true;
5598e31cfd1SJeremy Kerr 		}
5608e31cfd1SJeremy Kerr 
5618e31cfd1SJeremy Kerr 		if (clients_changed)
5628e31cfd1SJeremy Kerr 			client_remove_inactive(ctx);
5638e31cfd1SJeremy Kerr 	}
5648e31cfd1SJeremy Kerr 
5658e31cfd1SJeremy Kerr 	free(ctx->pollfds);
5668e31cfd1SJeremy Kerr 
5678e31cfd1SJeremy Kerr 	return rc;
5688e31cfd1SJeremy Kerr }
5698e31cfd1SJeremy Kerr 
5708e31cfd1SJeremy Kerr static const struct option options[] = {
571cad47301SAndrew Jeffery 	{ "capture-binding", required_argument, 0, 'b' },
572cad47301SAndrew Jeffery 	{ "capture-socket", required_argument, 0, 's' },
573cad47301SAndrew Jeffery 	{ "binding-linktype", required_argument, 0, 'B' },
574cad47301SAndrew Jeffery 	{ "socket-linktype", required_argument, 0, 'S' },
5758e31cfd1SJeremy Kerr 	{ "verbose", no_argument, 0, 'v' },
5768e31cfd1SJeremy Kerr 	{ "eid", required_argument, 0, 'e' },
5778e31cfd1SJeremy Kerr 	{ 0 },
5788e31cfd1SJeremy Kerr };
5798e31cfd1SJeremy Kerr 
usage(const char * progname)5808e31cfd1SJeremy Kerr static void usage(const char *progname)
5818e31cfd1SJeremy Kerr {
5828e31cfd1SJeremy Kerr 	unsigned int i;
5838e31cfd1SJeremy Kerr 
5848e31cfd1SJeremy Kerr 	fprintf(stderr, "usage: %s <binding> [params]\n", progname);
5858e31cfd1SJeremy Kerr 	fprintf(stderr, "Available bindings:\n");
5868e31cfd1SJeremy Kerr 	for (i = 0; i < ARRAY_SIZE(bindings); i++)
5878e31cfd1SJeremy Kerr 		fprintf(stderr, "  %s\n", bindings[i].name);
5888e31cfd1SJeremy Kerr }
5898e31cfd1SJeremy Kerr 
main(int argc,char * const * argv)5908e31cfd1SJeremy Kerr int main(int argc, char *const *argv)
5918e31cfd1SJeremy Kerr {
5928e31cfd1SJeremy Kerr 	struct ctx *ctx, _ctx;
5938e31cfd1SJeremy Kerr 	int rc;
5948e31cfd1SJeremy Kerr 
5958e31cfd1SJeremy Kerr 	ctx = &_ctx;
5968e31cfd1SJeremy Kerr 	ctx->clients = NULL;
5978e31cfd1SJeremy Kerr 	ctx->n_clients = 0;
5988e31cfd1SJeremy Kerr 	ctx->local_eid = local_eid_default;
59904b81fc7SAndrew Jeffery 	ctx->verbose = false;
600cad47301SAndrew Jeffery 	ctx->pcap.binding.path = NULL;
601cad47301SAndrew Jeffery 	ctx->pcap.socket.path = NULL;
6028e31cfd1SJeremy Kerr 
6038e31cfd1SJeremy Kerr 	for (;;) {
604cad47301SAndrew Jeffery 		rc = getopt_long(argc, argv, "b:es::v", options, NULL);
6058e31cfd1SJeremy Kerr 		if (rc == -1)
6068e31cfd1SJeremy Kerr 			break;
6078e31cfd1SJeremy Kerr 		switch (rc) {
608cad47301SAndrew Jeffery 		case 'b':
609cad47301SAndrew Jeffery 			ctx->pcap.binding.path = optarg;
610cad47301SAndrew Jeffery 			break;
611cad47301SAndrew Jeffery 		case 's':
612cad47301SAndrew Jeffery 			ctx->pcap.socket.path = optarg;
613cad47301SAndrew Jeffery 			break;
614cad47301SAndrew Jeffery 		case 'B':
615f2988977SRashmica Gupta 			fprintf(stderr,
616f2988977SRashmica Gupta 				"binding-linktype argument is deprecated\n");
617cad47301SAndrew Jeffery 			break;
618cad47301SAndrew Jeffery 		case 'S':
619f2988977SRashmica Gupta 			fprintf(stderr,
620f2988977SRashmica Gupta 				"socket-linktype argument is deprecated\n");
621cad47301SAndrew Jeffery 			break;
6228e31cfd1SJeremy Kerr 		case 'v':
6238e31cfd1SJeremy Kerr 			ctx->verbose = true;
6248e31cfd1SJeremy Kerr 			break;
6258e31cfd1SJeremy Kerr 		case 'e':
6268e31cfd1SJeremy Kerr 			ctx->local_eid = atoi(optarg);
6278e31cfd1SJeremy Kerr 			break;
6288e31cfd1SJeremy Kerr 		default:
6298e31cfd1SJeremy Kerr 			fprintf(stderr, "Invalid argument\n");
6308e31cfd1SJeremy Kerr 			return EXIT_FAILURE;
6318e31cfd1SJeremy Kerr 		}
6328e31cfd1SJeremy Kerr 	}
6338e31cfd1SJeremy Kerr 
6348e31cfd1SJeremy Kerr 	if (optind >= argc) {
6358e31cfd1SJeremy Kerr 		fprintf(stderr, "missing binding argument\n");
6368e31cfd1SJeremy Kerr 		usage(argv[0]);
6378e31cfd1SJeremy Kerr 		return EXIT_FAILURE;
6388e31cfd1SJeremy Kerr 	}
6398e31cfd1SJeremy Kerr 
640f49b2ac8SJeremy Kerr 	/* setup initial buffer */
641f49b2ac8SJeremy Kerr 	ctx->buf_size = 4096;
642f49b2ac8SJeremy Kerr 	ctx->buf = malloc(ctx->buf_size);
643f49b2ac8SJeremy Kerr 
644dca82599SAndrew Jeffery 	mctp_set_log_stdio(ctx->verbose ? MCTP_LOG_DEBUG : MCTP_LOG_NOTICE);
6450b278a63SJeremy Kerr 
6468e31cfd1SJeremy Kerr 	ctx->mctp = mctp_init();
6478e31cfd1SJeremy Kerr 	assert(ctx->mctp);
6488e31cfd1SJeremy Kerr 
649cad47301SAndrew Jeffery 	if (ctx->pcap.binding.path || ctx->pcap.socket.path) {
650cad47301SAndrew Jeffery 		if (capture_init()) {
651cad47301SAndrew Jeffery 			rc = EXIT_FAILURE;
652cad47301SAndrew Jeffery 			goto cleanup_mctp;
653cad47301SAndrew Jeffery 		}
654cad47301SAndrew Jeffery 	}
655cad47301SAndrew Jeffery 
656cad47301SAndrew Jeffery 	if (ctx->pcap.binding.path) {
657cad47301SAndrew Jeffery 		rc = capture_prepare(&ctx->pcap.binding);
658cad47301SAndrew Jeffery 		if (rc == -1) {
659a721c2d8SPatrick Williams 			fprintf(stderr, "Failed to initialise capture: %d\n",
660a721c2d8SPatrick Williams 				rc);
661cad47301SAndrew Jeffery 			rc = EXIT_FAILURE;
662cad47301SAndrew Jeffery 			goto cleanup_mctp;
663cad47301SAndrew Jeffery 		}
664cad47301SAndrew Jeffery 
665cad47301SAndrew Jeffery 		mctp_set_capture_handler(ctx->mctp, capture_binding,
666cad47301SAndrew Jeffery 					 ctx->pcap.binding.dumper);
667cad47301SAndrew Jeffery 	}
668cad47301SAndrew Jeffery 
669cad47301SAndrew Jeffery 	if (ctx->pcap.socket.path) {
670cad47301SAndrew Jeffery 		rc = capture_prepare(&ctx->pcap.socket);
671cad47301SAndrew Jeffery 		if (rc == -1) {
672a721c2d8SPatrick Williams 			fprintf(stderr, "Failed to initialise capture: %d\n",
673a721c2d8SPatrick Williams 				rc);
674cad47301SAndrew Jeffery 			rc = EXIT_FAILURE;
675cad47301SAndrew Jeffery 			goto cleanup_pcap_binding;
676cad47301SAndrew Jeffery 		}
677cad47301SAndrew Jeffery 	}
678cad47301SAndrew Jeffery 
679a721c2d8SPatrick Williams 	rc = binding_init(ctx, argv[optind], argc - optind - 1,
680a721c2d8SPatrick Williams 			  argv + optind + 1);
681cad47301SAndrew Jeffery 	if (rc) {
682cad47301SAndrew Jeffery 		fprintf(stderr, "Failed to initialise binding: %d\n", rc);
683cad47301SAndrew Jeffery 		rc = EXIT_FAILURE;
684cad47301SAndrew Jeffery 		goto cleanup_pcap_socket;
685cad47301SAndrew Jeffery 	}
6868e31cfd1SJeremy Kerr 
687d4103f8fSAndrew Jeffery 	rc = sd_listen_fds(true);
688d4103f8fSAndrew Jeffery 	if (rc <= 0) {
6898e31cfd1SJeremy Kerr 		rc = socket_init(ctx);
690cad47301SAndrew Jeffery 		if (rc) {
691cad47301SAndrew Jeffery 			fprintf(stderr, "Failed to initialse socket: %d\n", rc);
692edebe169SAndrew Jeffery 			goto cleanup_binding;
693cad47301SAndrew Jeffery 		}
694d4103f8fSAndrew Jeffery 	} else {
695d4103f8fSAndrew Jeffery 		ctx->sock = SD_LISTEN_FDS_START;
696d4103f8fSAndrew Jeffery 	}
6978e31cfd1SJeremy Kerr 
6988e31cfd1SJeremy Kerr 	rc = run_daemon(ctx);
6998e31cfd1SJeremy Kerr 
700edebe169SAndrew Jeffery cleanup_binding:
701edebe169SAndrew Jeffery 	binding_destroy(ctx);
702edebe169SAndrew Jeffery 
703cad47301SAndrew Jeffery cleanup_pcap_socket:
704cad47301SAndrew Jeffery 	if (ctx->pcap.socket.path)
705cad47301SAndrew Jeffery 		capture_close(&ctx->pcap.socket);
706cad47301SAndrew Jeffery 
707cad47301SAndrew Jeffery cleanup_pcap_binding:
708cad47301SAndrew Jeffery 	if (ctx->pcap.binding.path)
709cad47301SAndrew Jeffery 		capture_close(&ctx->pcap.binding);
710cad47301SAndrew Jeffery 
711cad47301SAndrew Jeffery 	rc = rc ? EXIT_FAILURE : EXIT_SUCCESS;
712cad47301SAndrew Jeffery cleanup_mctp:
713cad47301SAndrew Jeffery 
714cad47301SAndrew Jeffery 	return rc;
7158e31cfd1SJeremy Kerr }
716