mctp-demux-daemon: Add packet capture option

Optionally enable libpcap support in mctp-demux-daemon to capture
packets both from the Unix domain socket and binding interfaces.
Providing the two capture points allows for tracking down issues with
packets being dropped during binding initialisation.

As there's no formal linktype defined for MCTP or higher-level DMTF
protocols command-line switches provide the ability to specify one of
the private linktype values in the range 147-162.

Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Change-Id: I593d9e4be80c0198e643758f216e774169668a8c
diff --git a/utils/mctp-demux-daemon.c b/utils/mctp-demux-daemon.c
index bbf7796..dd719de 100644
--- a/utils/mctp-demux-daemon.c
+++ b/utils/mctp-demux-daemon.c
@@ -3,6 +3,7 @@
 #define _GNU_SOURCE
 
 #include "config.h"
+#include "utils/mctp-capture.h"
 
 #include <assert.h>
 #include <err.h>
@@ -71,6 +72,11 @@
 
 	struct client	*clients;
 	int		n_clients;
+
+	struct {
+		struct capture binding;
+		struct capture socket;
+	} pcap;
 };
 
 static void tx_message(struct ctx *ctx, mctp_eid_t eid, void *msg, size_t len)
@@ -380,6 +386,9 @@
 		goto out_close;
 	}
 
+	if (ctx->pcap.socket.path)
+		capture_socket(ctx->pcap.socket.dumper, ctx->buf, rc);
+
 	eid = *(uint8_t *)ctx->buf;
 
 	if (ctx->verbose)
@@ -537,6 +546,10 @@
 }
 
 static const struct option options[] = {
+	{ "capture-binding", required_argument, 0, 'b' },
+	{ "capture-socket", required_argument, 0, 's' },
+	{ "binding-linktype", required_argument, 0, 'B' },
+	{ "socket-linktype", required_argument, 0, 'S' },
 	{ "verbose", no_argument, 0, 'v' },
 	{ "eid", required_argument, 0, 'e' },
 	{ 0 },
@@ -562,12 +575,26 @@
 	ctx->n_clients = 0;
 	ctx->local_eid = local_eid_default;
 	ctx->verbose = false;
+	ctx->pcap.binding.path = NULL;
+	ctx->pcap.socket.path = NULL;
 
 	for (;;) {
-		rc = getopt_long(argc, argv, "e:v", options, NULL);
+		rc = getopt_long(argc, argv, "b:es::v", options, NULL);
 		if (rc == -1)
 			break;
 		switch (rc) {
+		case 'b':
+			ctx->pcap.binding.path = optarg;
+			break;
+		case 's':
+			ctx->pcap.socket.path = optarg;
+			break;
+		case 'B':
+			ctx->pcap.binding.linktype = atoi(optarg);
+			break;
+		case 'S':
+			ctx->pcap.socket.linktype = atoi(optarg);
+			break;
 		case 'v':
 			ctx->verbose = true;
 			break;
@@ -595,21 +622,65 @@
 	ctx->mctp = mctp_init();
 	assert(ctx->mctp);
 
+	if (ctx->pcap.binding.path || ctx->pcap.socket.path) {
+		if (capture_init()) {
+			rc = EXIT_FAILURE;
+			goto cleanup_mctp;
+		}
+	}
+
+	if (ctx->pcap.binding.path) {
+		rc = capture_prepare(&ctx->pcap.binding);
+		if (rc == -1) {
+			fprintf(stderr, "Failed to initialise capture: %d\n", rc);
+			rc = EXIT_FAILURE;
+			goto cleanup_mctp;
+		}
+
+		mctp_set_capture_handler(ctx->mctp, capture_binding,
+					 ctx->pcap.binding.dumper);
+	}
+
+	if (ctx->pcap.socket.path) {
+		rc = capture_prepare(&ctx->pcap.socket);
+		if (rc == -1) {
+			fprintf(stderr, "Failed to initialise capture: %d\n", rc);
+			rc = EXIT_FAILURE;
+			goto cleanup_pcap_binding;
+		}
+	}
+
 	rc = binding_init(ctx, argv[optind], argc - optind - 1, argv + optind + 1);
-	if (rc)
-		return EXIT_FAILURE;
+	if (rc) {
+		fprintf(stderr, "Failed to initialise binding: %d\n", rc);
+		rc = EXIT_FAILURE;
+		goto cleanup_pcap_socket;
+	}
 
 	rc = sd_listen_fds(true);
 	if (rc <= 0) {
 		rc = socket_init(ctx);
-		if (rc)
+		if (rc) {
+			fprintf(stderr, "Failed to initialse socket: %d\n", rc);
 			return EXIT_FAILURE;
+		}
 	} else {
 		ctx->sock = SD_LISTEN_FDS_START;
 	}
 
 	rc = run_daemon(ctx);
 
-	return rc ? EXIT_FAILURE : EXIT_SUCCESS;
+cleanup_pcap_socket:
+	if (ctx->pcap.socket.path)
+		capture_close(&ctx->pcap.socket);
+
+cleanup_pcap_binding:
+	if (ctx->pcap.binding.path)
+		capture_close(&ctx->pcap.binding);
+
+	rc = rc ? EXIT_FAILURE : EXIT_SUCCESS;
+cleanup_mctp:
+
+	return rc;
 
 }