pcap: Use SLL2 linktype for captures

This means we can use wireshark on our pcaps.

Signed-off-by: Rashmica Gupta <rashmica@linux.ibm.com>
Change-Id: I215af00e064d352e41d0a8eb87d5a30582998676
diff --git a/core.c b/core.c
index 5a5d247..51eda38 100644
--- a/core.c
+++ b/core.c
@@ -547,7 +547,8 @@
 		goto out;
 
 	if (mctp->capture)
-		mctp->capture(pkt, mctp->capture_data);
+		mctp->capture(pkt, MCTP_MESSAGE_CAPTURE_INCOMING,
+			      mctp->capture_data);
 
 	hdr = mctp_pktbuf_hdr(pkt);
 
@@ -681,7 +682,8 @@
 		return -1;
 
 	if (mctp->capture)
-		mctp->capture(pkt, mctp->capture_data);
+		mctp->capture(pkt, MCTP_MESSAGE_CAPTURE_OUTGOING,
+			      mctp->capture_data);
 
 	return bus->binding->tx(bus->binding, pkt);
 }
diff --git a/libmctp.h b/libmctp.h
index b34abfe..76f8ec9 100644
--- a/libmctp.h
+++ b/libmctp.h
@@ -37,8 +37,10 @@
 #define MCTP_HDR_TAG_SHIFT (0)
 #define MCTP_HDR_TAG_MASK  (0x7)
 
-#define MCTP_MESSAGE_TO_SRC true
-#define MCTP_MESSAGE_TO_DST false
+#define MCTP_MESSAGE_TO_SRC	      true
+#define MCTP_MESSAGE_TO_DST	      false
+#define MCTP_MESSAGE_CAPTURE_OUTGOING true
+#define MCTP_MESSAGE_CAPTURE_INCOMING false
 
 /* Baseline Transmission Unit and packet size */
 #define MCTP_BTU	       64
@@ -72,7 +74,8 @@
 
 struct mctp *mctp_init(void);
 void mctp_set_max_message_size(struct mctp *mctp, size_t message_size);
-typedef void (*mctp_capture_fn)(struct mctp_pktbuf *pkt, void *user);
+typedef void (*mctp_capture_fn)(struct mctp_pktbuf *pkt, bool outgoing,
+				void *user);
 void mctp_set_capture_handler(struct mctp *mctp, mctp_capture_fn fn,
 			      void *user);
 void mctp_destroy(struct mctp *mctp);
diff --git a/utils/mctp-capture.c b/utils/mctp-capture.c
index 05180ec..b38e92d 100644
--- a/utils/mctp-capture.c
+++ b/utils/mctp-capture.c
@@ -2,6 +2,18 @@
 
 #include <stdio.h>
 #include <sys/time.h>
+#include <string.h>
+
+#if HAVE_PCAP
+#include <pcap/sll.h>
+#include <linux/if_ether.h>
+#include "libmctp-alloc.h"
+
+#ifndef ETH_P_MCTP
+#define ETH_P_MCTP 0xfa
+#endif
+
+#endif
 
 int capture_init(void)
 {
@@ -20,19 +32,11 @@
 {
 	int rc;
 
-	if (cap->linktype < CAPTURE_LINKTYPE_FIRST ||
-	    cap->linktype > CAPTURE_LINKTYPE_LAST) {
-		fprintf(stderr,
-			"Invalid private linktype value %d: see https://www.tcpdump.org/linktypes.html\n",
-			cap->linktype);
-		return -1;
-	}
-
-	if (!(cap->pcap = pcap_open_dead(cap->linktype, UINT16_MAX))) {
+	if (!(cap->pcap = pcap_open_dead(CAPTURE_LINKTYPE_LINUX_SLL2,
+					 UINT16_MAX))) {
 		fprintf(stderr, "pcap_open_dead: failed\n");
 		return -1;
 	}
-
 	if (!(cap->dumper = pcap_dump_open(cap->pcap, cap->path))) {
 		fprintf(stderr, "pcap_dump_open: failed\n");
 		return -1;
@@ -48,31 +52,94 @@
 	pcap_close(cap->pcap);
 }
 
-void capture_binding(struct mctp_pktbuf *pkt, void *user)
+void capture_binding(struct mctp_pktbuf *pkt, bool outgoing, void *user)
 {
 	pcap_dumper_t *dumper = user;
 	struct pcap_pkthdr hdr;
 	int rc;
+	uint8_t *pktbuf = NULL;
+	size_t size;
 
 	if ((rc = gettimeofday(&hdr.ts, NULL)) == -1)
 		return;
 
-	hdr.caplen = mctp_pktbuf_size(pkt);
-	hdr.len = mctp_pktbuf_size(pkt);
+	/* Write sll2 header */
+	size = sizeof(struct sll2_header) + mctp_pktbuf_size(pkt);
+	pktbuf = __mctp_alloc(size);
+	if (!pktbuf)
+		return;
 
-	pcap_dump((u_char *)dumper, &hdr, (const u_char *)mctp_pktbuf_hdr(pkt));
+	struct sll2_header *sll2 = (struct sll2_header *)pktbuf;
+	sll2->sll2_protocol = htons(ETH_P_MCTP);
+	if (outgoing)
+		sll2->sll2_pkttype = LINUX_SLL_OUTGOING;
+	else
+		sll2->sll2_pkttype = LINUX_SLL_HOST;
+	sll2->sll2_reserved_mbz = 0x0;
+	sll2->sll2_if_index = 0x0;
+	sll2->sll2_hatype = 0x0;
+	sll2->sll2_halen = 0x0;
+	memset(sll2->sll2_addr, 0, SLL_ADDRLEN);
+
+	memcpy(pktbuf + sizeof(struct sll2_header), mctp_pktbuf_hdr(pkt),
+	       mctp_pktbuf_size(pkt));
+
+	hdr.caplen = size;
+	hdr.len = size;
+
+	pcap_dump((u_char *)dumper, &hdr, (const u_char *)pktbuf);
+	__mctp_free(pktbuf);
 }
 
-void capture_socket(pcap_dumper_t *dumper, const void *buf, size_t len)
+void capture_socket(pcap_dumper_t *dumper, const void *buf, size_t len,
+		    bool outgoing, int eid)
 {
 	struct pcap_pkthdr hdr;
 	int rc;
+	uint8_t *pktbuf = NULL;
+	size_t size;
 
 	if ((rc = gettimeofday(&hdr.ts, NULL)) == -1)
 		return;
 
-	hdr.caplen = len;
-	hdr.len = len;
+	/* Write sll2 header */
+	size = sizeof(struct sll2_header) + sizeof(struct mctp_hdr) + len;
+	pktbuf = __mctp_alloc(size);
+	if (!pktbuf)
+		return;
 
-	pcap_dump((u_char *)dumper, &hdr, buf);
+	struct sll2_header *sll2 = (struct sll2_header *)pktbuf;
+	sll2->sll2_protocol = htons(ETH_P_MCTP);
+	if (outgoing)
+		sll2->sll2_pkttype = LINUX_SLL_OUTGOING;
+	else
+		sll2->sll2_pkttype = LINUX_SLL_HOST;
+	sll2->sll2_reserved_mbz = 0x0;
+	sll2->sll2_if_index = 0x0;
+	sll2->sll2_hatype = 0x0;
+	sll2->sll2_halen = 0x0;
+	memset(sll2->sll2_addr, 0, SLL_ADDRLEN);
+
+	/* Write fake mctp header */
+	struct mctp_hdr *mctp =
+		(struct mctp_hdr *)(pktbuf + sizeof(struct sll2_header));
+	mctp->ver = 1;
+	mctp->flags_seq_tag = 0xc0; //set SOM and EOM
+	if (outgoing) {
+		mctp->dest = eid;
+		mctp->src = 0;
+	} else {
+		mctp->dest = 0;
+		mctp->src = eid;
+	}
+
+	/* Ignore the eid at start of buf */
+	memcpy(pktbuf + sizeof(struct sll2_header) + sizeof(struct mctp_hdr),
+	       buf + 1, len - 1);
+
+	hdr.caplen = size;
+	hdr.len = size;
+
+	pcap_dump((u_char *)dumper, &hdr, (const u_char *)pktbuf);
+	__mctp_free(pktbuf);
 }
diff --git a/utils/mctp-capture.h b/utils/mctp-capture.h
index 8babf2e..e432df9 100644
--- a/utils/mctp-capture.h
+++ b/utils/mctp-capture.h
@@ -12,17 +12,16 @@
 
 #if HAVE_PCAP
 #include <pcap/pcap.h>
+
 #else
 typedef void pcap_t;
 typedef void pcap_dumper_t;
 #endif
 
-#define CAPTURE_LINKTYPE_FIRST 147
-#define CAPTURE_LINKTYPE_LAST  162
+#define CAPTURE_LINKTYPE_LINUX_SLL2 276
 
 struct capture {
 	const char *path;
-	int linktype;
 	pcap_t *pcap;
 	pcap_dumper_t *dumper;
 };
@@ -31,8 +30,9 @@
 int capture_init(void);
 int capture_prepare(struct capture *cap);
 void capture_close(struct capture *cap);
-void capture_binding(struct mctp_pktbuf *pkt, void *user);
-void capture_socket(pcap_dumper_t *dumper, const void *buf, size_t len);
+void capture_binding(struct mctp_pktbuf *pkt, bool outgoing, void *user);
+void capture_socket(pcap_dumper_t *dumper, const void *buf, size_t len,
+		    bool outgoing, int eid);
 #else
 #include <stdio.h>
 static inline int capture_init(void)
@@ -54,12 +54,13 @@
 }
 
 static inline void capture_binding(struct mctp_pktbuf *pkt __unused,
-				   void *user __unused)
+				   bool outgoing __unused, void *user __unused)
 {
 }
 
 static inline void capture_socket(pcap_dumper_t *dumper __unused,
-				  const void *buf __unused, size_t len __unused)
+				  const void *buf __unused, size_t len __unused,
+				  bool outgoing __unused, int eid __unused)
 {
 }
 #endif
diff --git a/utils/mctp-demux-daemon.c b/utils/mctp-demux-daemon.c
index f9893bb..d07e141 100644
--- a/utils/mctp-demux-daemon.c
+++ b/utils/mctp-demux-daemon.c
@@ -399,11 +399,12 @@
 		goto out_close;
 	}
 
-	if (ctx->pcap.socket.path)
-		capture_socket(ctx->pcap.socket.dumper, ctx->buf, rc);
-
 	eid = *(uint8_t *)ctx->buf;
 
+	if (ctx->pcap.socket.path)
+		capture_socket(ctx->pcap.socket.dumper, ctx->buf, rc,
+			       MCTP_MESSAGE_CAPTURE_OUTGOING, eid);
+
 	if (ctx->verbose)
 		fprintf(stderr, "client[%d] sent message: dest 0x%02x len %d\n",
 			idx, eid, rc - 1);
@@ -592,9 +593,7 @@
 	ctx->local_eid = local_eid_default;
 	ctx->verbose = false;
 	ctx->pcap.binding.path = NULL;
-	ctx->pcap.binding.linktype = -1;
 	ctx->pcap.socket.path = NULL;
-	ctx->pcap.socket.linktype = -1;
 
 	for (;;) {
 		rc = getopt_long(argc, argv, "b:es::v", options, NULL);
@@ -608,10 +607,12 @@
 			ctx->pcap.socket.path = optarg;
 			break;
 		case 'B':
-			ctx->pcap.binding.linktype = atoi(optarg);
+			fprintf(stderr,
+				"binding-linktype argument is deprecated\n");
 			break;
 		case 'S':
-			ctx->pcap.socket.linktype = atoi(optarg);
+			fprintf(stderr,
+				"socket-linktype argument is deprecated\n");
 			break;
 		case 'v':
 			ctx->verbose = true;
@@ -631,18 +632,6 @@
 		return EXIT_FAILURE;
 	}
 
-	if (ctx->pcap.binding.linktype < 0 && ctx->pcap.binding.path) {
-		fprintf(stderr, "missing binding-linktype argument\n");
-		usage(argv[0]);
-		return EXIT_FAILURE;
-	}
-
-	if (ctx->pcap.socket.linktype < 0 && ctx->pcap.socket.path) {
-		fprintf(stderr, "missing socket-linktype argument\n");
-		usage(argv[0]);
-		return EXIT_FAILURE;
-	}
-
 	/* setup initial buffer */
 	ctx->buf_size = 4096;
 	ctx->buf = malloc(ctx->buf_size);