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