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/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);
 }