1*d0146fffSchristos /*	$NetBSD: shmif_dumpbus.c,v 1.19 2020/04/01 21:04:34 christos Exp $	*/
295569715Spooka 
395569715Spooka /*-
495569715Spooka  * Copyright (c) 2010 Antti Kantee.  All Rights Reserved.
595569715Spooka  *
695569715Spooka  * Redistribution and use in source and binary forms, with or without
795569715Spooka  * modification, are permitted provided that the following conditions
895569715Spooka  * are met:
995569715Spooka  * 1. Redistributions of source code must retain the above copyright
1095569715Spooka  *    notice, this list of conditions and the following disclaimer.
1195569715Spooka  * 2. Redistributions in binary form must reproduce the above copyright
1295569715Spooka  *    notice, this list of conditions and the following disclaimer in the
1395569715Spooka  *    documentation and/or other materials provided with the distribution.
1495569715Spooka  *
1595569715Spooka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
1695569715Spooka  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1795569715Spooka  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1895569715Spooka  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1995569715Spooka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2095569715Spooka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2195569715Spooka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2295569715Spooka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2395569715Spooka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2495569715Spooka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2595569715Spooka  * SUCH DAMAGE.
2695569715Spooka  */
2795569715Spooka 
2895569715Spooka /*
2995569715Spooka  * Convert shmif bus traffic to a pcap file which can be then
3095569715Spooka  * examined with tcpdump -r, wireshark, etc.
3195569715Spooka  */
3295569715Spooka 
335a18f1d9Spooka #include <rump/rumpuser_port.h>
345a18f1d9Spooka 
35e9a83eefSpooka #ifndef lint
36*d0146fffSchristos __RCSID("$NetBSD: shmif_dumpbus.c,v 1.19 2020/04/01 21:04:34 christos Exp $");
37e9a83eefSpooka #endif /* !lint */
38e9a83eefSpooka 
3995569715Spooka #include <sys/types.h>
4095569715Spooka #include <sys/mman.h>
4195569715Spooka #include <sys/stat.h>
425a18f1d9Spooka #ifdef __NetBSD__
435a18f1d9Spooka #include <sys/bswap.h>
445a18f1d9Spooka #endif
45c3118cb3Spooka 
4695569715Spooka #include <assert.h>
4795569715Spooka #include <err.h>
4895569715Spooka #include <fcntl.h>
4995569715Spooka #include <inttypes.h>
5095569715Spooka #include <pcap.h>
5195569715Spooka #include <stdbool.h>
5295569715Spooka #include <stdio.h>
5395569715Spooka #include <stdlib.h>
5495569715Spooka #include <string.h>
5595569715Spooka #include <unistd.h>
5695569715Spooka 
5795569715Spooka #include "shmifvar.h"
5895569715Spooka 
594624cd84Sjoerg __dead static void
usage(void)6095569715Spooka usage(void)
6195569715Spooka {
6295569715Spooka 
639e2a065bSpooka #ifndef HAVE_GETPROGNAME
645a18f1d9Spooka #define getprogname() "shmif_dumpbus"
655a18f1d9Spooka #endif
665a18f1d9Spooka 
67*d0146fffSchristos 	fprintf(stderr, "Usage: %s [-h] [-p pcapfile] buspath\n",
68*d0146fffSchristos 	    getprogname());
69*d0146fffSchristos 	exit(EXIT_FAILURE);
7095569715Spooka }
7195569715Spooka 
7295569715Spooka #define BUFSIZE 64*1024
7317ca2640Spooka 
7417ca2640Spooka /*
7517ca2640Spooka  * byte swapdom
7617ca2640Spooka  */
7717ca2640Spooka static uint32_t
swp32(uint32_t x)7817ca2640Spooka swp32(uint32_t x)
7917ca2640Spooka {
8017ca2640Spooka 	uint32_t v;
8117ca2640Spooka 
8217ca2640Spooka 	v = (((x) & 0xff000000) >> 24) |
8317ca2640Spooka 	    (((x) & 0x00ff0000) >>  8) |
8417ca2640Spooka 	    (((x) & 0x0000ff00) <<  8) |
8517ca2640Spooka 	    (((x) & 0x000000ff) << 24);
8617ca2640Spooka 	return v;
8717ca2640Spooka }
8817ca2640Spooka 
8917ca2640Spooka static uint64_t
swp64(uint64_t x)9017ca2640Spooka swp64(uint64_t x)
9117ca2640Spooka {
9217ca2640Spooka 	uint64_t v;
9317ca2640Spooka 
9417ca2640Spooka 	v = (((x) & 0xff00000000000000ull) >> 56) |
9517ca2640Spooka 	    (((x) & 0x00ff000000000000ull) >> 40) |
9617ca2640Spooka 	    (((x) & 0x0000ff0000000000ull) >> 24) |
9717ca2640Spooka 	    (((x) & 0x000000ff00000000ull) >>  8) |
9817ca2640Spooka 	    (((x) & 0x00000000ff000000ull) <<  8) |
9917ca2640Spooka 	    (((x) & 0x0000000000ff0000ull) << 24) |
10017ca2640Spooka 	    (((x) & 0x000000000000ff00ull) << 40) |
10117ca2640Spooka 	    (((x) & 0x00000000000000ffull) << 56);
10217ca2640Spooka 	return v;
10317ca2640Spooka }
10417ca2640Spooka 
105*d0146fffSchristos #define FIXENDIAN32(x) (doswap ? swp32(x) : (uint32_t)(x))
106*d0146fffSchristos #define FIXENDIAN64(x) (doswap ? swp64(x) : (uint64_t)(x))
10717ca2640Spooka 
10826dc025cSpooka /* compat for bus version 2 */
10926dc025cSpooka struct shmif_pkthdr2 {
11026dc025cSpooka 	uint32_t sp_len;
11126dc025cSpooka 
11226dc025cSpooka 	uint32_t sp_sec;
11326dc025cSpooka 	uint32_t sp_usec;
11426dc025cSpooka };
11526dc025cSpooka 
11695569715Spooka int
main(int argc,char * argv[])11795569715Spooka main(int argc, char *argv[])
11895569715Spooka {
11995569715Spooka 	struct stat sb;
12095569715Spooka 	void *busmem;
12195569715Spooka 	const char *pcapfile = NULL;
12295569715Spooka 	uint32_t curbus, buslast;
12395569715Spooka 	struct shmif_mem *bmem;
124c3118cb3Spooka 	int fd, i, ch;
12595569715Spooka 	int bonus;
12695569715Spooka 	char *buf;
127b59e1825Spooka 	bool hflag = false, doswap = false;
128c3118cb3Spooka 	pcap_dumper_t *pdump;
129b59e1825Spooka 	FILE *dumploc = stdout;
130*d0146fffSchristos 	uint32_t useversion;
13195569715Spooka 
13295569715Spooka 	setprogname(argv[0]);
13395569715Spooka 	while ((ch = getopt(argc, argv, "hp:")) != -1) {
13495569715Spooka 		switch (ch) {
13595569715Spooka 		case 'h':
13695569715Spooka 			hflag = true;
13795569715Spooka 			break;
13895569715Spooka 		case 'p':
13995569715Spooka 			pcapfile = optarg;
14095569715Spooka 			break;
14195569715Spooka 		default:
14295569715Spooka 			usage();
14395569715Spooka 		}
14495569715Spooka 	}
14595569715Spooka 
14695569715Spooka 	argc -= optind;
14795569715Spooka 	argv += optind;
14895569715Spooka 
14995569715Spooka 	if (argc != 1)
15095569715Spooka 		usage();
15195569715Spooka 
15295569715Spooka 	buf = malloc(BUFSIZE);
15395569715Spooka 	if (buf == NULL)
154*d0146fffSchristos 		err(EXIT_FAILURE, "malloc");
15595569715Spooka 
15695569715Spooka 	fd = open(argv[0], O_RDONLY);
15795569715Spooka 	if (fd == -1)
158*d0146fffSchristos 		err(EXIT_FAILURE, "Can't open bus file `%s'", argv[0]);
15995569715Spooka 
16095569715Spooka 	if (fstat(fd, &sb) == -1)
161*d0146fffSchristos 		err(EXIT_FAILURE, "Can't stat bus file `%s'", argv[0]);
16295569715Spooka 
163*d0146fffSchristos 	busmem = mmap(NULL, (size_t)sb.st_size, PROT_READ, MAP_FILE|MAP_SHARED,
164*d0146fffSchristos 	    fd, 0);
16595569715Spooka 	if (busmem == MAP_FAILED)
166*d0146fffSchristos 		err(EXIT_FAILURE, "mmap");
16795569715Spooka 	bmem = busmem;
16895569715Spooka 
169c3118cb3Spooka 	if (bmem->shm_magic != SHMIF_MAGIC) {
17017ca2640Spooka 		if (bmem->shm_magic != swp32(SHMIF_MAGIC))
171*d0146fffSchristos 			errx(EXIT_FAILURE, "%s not a shmif bus: "
172*d0146fffSchristos 			    "bad magic %#x != %#x", argv[0], bmem->shm_magic,
173*d0146fffSchristos 			    SHMIF_MAGIC);
17417ca2640Spooka 		doswap = true;
175c3118cb3Spooka 	}
176*d0146fffSchristos 	useversion = FIXENDIAN32(bmem->shm_version);
177*d0146fffSchristos 	switch (useversion) {
178*d0146fffSchristos 	case 2:
179*d0146fffSchristos 	case SHMIF_VERSION:
180*d0146fffSchristos 		break;
181*d0146fffSchristos 	default:
182*d0146fffSchristos 		errx(EXIT_FAILURE, "Unhandled bus version %d, program %d",
183*d0146fffSchristos 		    useversion, SHMIF_VERSION);
18426dc025cSpooka 	}
185b59e1825Spooka 
186b59e1825Spooka 	if (pcapfile && strcmp(pcapfile, "-") == 0)
187b59e1825Spooka 		dumploc = stderr;
188b59e1825Spooka 
189b59e1825Spooka 	fprintf(dumploc, "bus version %d, lock: %d, generation: %" PRIu64
19095569715Spooka 	    ", firstoff: 0x%04x, lastoff: 0x%04x\n",
19159911dd5Spooka 	    FIXENDIAN32(bmem->shm_version), FIXENDIAN32(bmem->shm_lock),
19259911dd5Spooka 	    FIXENDIAN64(bmem->shm_gen),
19359911dd5Spooka 	    FIXENDIAN32(bmem->shm_first), FIXENDIAN32(bmem->shm_last));
19495569715Spooka 
19595569715Spooka 	if (hflag)
19695569715Spooka 		exit(0);
19795569715Spooka 
19895569715Spooka 	if (pcapfile) {
199c3118cb3Spooka 		pcap_t *pcap = pcap_open_dead(DLT_EN10MB, 1518);
200c3118cb3Spooka 		pdump = pcap_dump_open(pcap, pcapfile);
201*d0146fffSchristos 		if (pdump == NULL) {
202*d0146fffSchristos 			errx(EXIT_FAILURE,
203*d0146fffSchristos 			    "Cannot open pcap dump file `%s': %s", pcapfile,
204*d0146fffSchristos 			    pcap_geterr(pcap));
205*d0146fffSchristos 		}
20695569715Spooka 	} else {
207c3118cb3Spooka 		/* XXXgcc */
208c3118cb3Spooka 		pdump = NULL;
20995569715Spooka 	}
21095569715Spooka 
21159911dd5Spooka 	curbus = FIXENDIAN32(bmem->shm_first);
21259911dd5Spooka 	buslast = FIXENDIAN32(bmem->shm_last);
21395569715Spooka 	if (curbus == BUSMEM_DATASIZE)
21495569715Spooka 		curbus = 0;
21595569715Spooka 
21695569715Spooka 	bonus = 0;
21795569715Spooka 	if (buslast < curbus)
21895569715Spooka 		bonus = 1;
21995569715Spooka 
22095569715Spooka 	i = 0;
22126dc025cSpooka 
22295569715Spooka 	while (curbus <= buslast || bonus) {
223c3118cb3Spooka 		struct pcap_pkthdr packhdr;
22495569715Spooka 		uint32_t oldoff;
225c3118cb3Spooka 		uint32_t curlen;
22626dc025cSpooka 		uint32_t sp_sec, sp_usec, sp_len;
22795569715Spooka 		bool wrap;
22895569715Spooka 
229ad4bdf6fSpooka 		assert(curbus < sb.st_size);
230ad4bdf6fSpooka 
23195569715Spooka 		wrap = false;
23295569715Spooka 		oldoff = curbus;
23326dc025cSpooka 
23426dc025cSpooka 		if (useversion == 3) {
235a8ab2dcfSpooka 			struct shmif_pkthdr sp;
236a8ab2dcfSpooka 
23726dc025cSpooka 			curbus = shmif_busread(bmem,
23826dc025cSpooka 			    &sp, oldoff, sizeof(sp), &wrap);
23971295e4aSpooka 			sp_len = FIXENDIAN32(sp.sp_len);
24071295e4aSpooka 			sp_sec = FIXENDIAN32(sp.sp_sec);
24171295e4aSpooka 			sp_usec = FIXENDIAN32(sp.sp_usec);
24226dc025cSpooka 		} else {
243a8ab2dcfSpooka 			struct shmif_pkthdr2 sp2;
244a8ab2dcfSpooka 
24526dc025cSpooka 			curbus = shmif_busread(bmem,
24626dc025cSpooka 			    &sp2, oldoff, sizeof(sp2), &wrap);
24771295e4aSpooka 			sp_len = FIXENDIAN32(sp2.sp_len);
24871295e4aSpooka 			sp_sec = FIXENDIAN32(sp2.sp_sec);
24971295e4aSpooka 			sp_usec = FIXENDIAN32(sp2.sp_usec);
25026dc025cSpooka 		}
25195569715Spooka 		if (wrap)
25295569715Spooka 			bonus = 0;
25395569715Spooka 
254ad4bdf6fSpooka 		assert(curbus < sb.st_size);
25571295e4aSpooka 		curlen = sp_len;
256ad4bdf6fSpooka 
257c3118cb3Spooka 		if (curlen == 0) {
25895569715Spooka 			continue;
259ad4bdf6fSpooka 		}
26095569715Spooka 
261b59e1825Spooka 		fprintf(dumploc, "packet %d, offset 0x%04x, length 0x%04x, "
26259911dd5Spooka 		    "ts %d/%06d\n", i++, curbus, curlen,
26371295e4aSpooka 		    sp_sec, sp_usec);
26495569715Spooka 
265ad4bdf6fSpooka 		if (!pcapfile) {
26695569715Spooka 			curbus = shmif_busread(bmem,
267c3118cb3Spooka 			    buf, curbus, curlen, &wrap);
26895569715Spooka 			if (wrap)
26995569715Spooka 				bonus = 0;
27095569715Spooka 			continue;
27195569715Spooka 		}
27295569715Spooka 
27395569715Spooka 		memset(&packhdr, 0, sizeof(packhdr));
274c3118cb3Spooka 		packhdr.caplen = packhdr.len = curlen;
27571295e4aSpooka 		packhdr.ts.tv_sec = sp_sec;
276*d0146fffSchristos 		packhdr.ts.tv_usec = (suseconds_t)sp_usec;
277c3118cb3Spooka 		assert(curlen <= BUFSIZE);
27895569715Spooka 
279c3118cb3Spooka 		curbus = shmif_busread(bmem, buf, curbus, curlen, &wrap);
280c3118cb3Spooka 		pcap_dump((u_char *)pdump, &packhdr, (u_char *)buf);
28195569715Spooka 		if (wrap)
28295569715Spooka 			bonus = 0;
28395569715Spooka 	}
28495569715Spooka 
285c3118cb3Spooka 	if (pcapfile)
286c3118cb3Spooka 		pcap_dump_close(pdump);
287c3118cb3Spooka 
288*d0146fffSchristos 	return EXIT_SUCCESS;
28995569715Spooka }
290