shmif_dumpbus.c revision 1.17 1 /* $NetBSD: shmif_dumpbus.c,v 1.17 2014/08/18 14:40:17 pooka Exp $ */
2
3 /*-
4 * Copyright (c) 2010 Antti Kantee. All Rights Reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 /*
29 * Convert shmif bus traffic to a pcap file which can be then
30 * examined with tcpdump -r, wireshark, etc.
31 */
32
33 #include <rump/rumpuser_port.h>
34
35 #ifndef lint
36 __RCSID("$NetBSD: shmif_dumpbus.c,v 1.17 2014/08/18 14:40:17 pooka Exp $");
37 #endif /* !lint */
38
39 #include <sys/types.h>
40 #include <sys/mman.h>
41 #include <sys/stat.h>
42 #ifdef __NetBSD__
43 #include <sys/bswap.h>
44 #endif
45
46 #include <assert.h>
47 #include <err.h>
48 #include <fcntl.h>
49 #include <inttypes.h>
50 #include <pcap.h>
51 #include <stdbool.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56
57 #include "shmifvar.h"
58
59 __dead static void
60 usage(void)
61 {
62
63 #ifndef PLATFORM_HAS_SETGETPROGNAME
64 #define getprogname() "shmif_dumpbus"
65 #endif
66
67 fprintf(stderr, "usage: %s [-h] [-p pcapfile] buspath\n",getprogname());
68 exit(1);
69 }
70
71 #define BUFSIZE 64*1024
72
73 /*
74 * byte swapdom
75 */
76 static uint32_t
77 swp32(uint32_t x)
78 {
79 uint32_t v;
80
81 v = (((x) & 0xff000000) >> 24) |
82 (((x) & 0x00ff0000) >> 8) |
83 (((x) & 0x0000ff00) << 8) |
84 (((x) & 0x000000ff) << 24);
85 return v;
86 }
87
88 static uint64_t
89 swp64(uint64_t x)
90 {
91 uint64_t v;
92
93 v = (((x) & 0xff00000000000000ull) >> 56) |
94 (((x) & 0x00ff000000000000ull) >> 40) |
95 (((x) & 0x0000ff0000000000ull) >> 24) |
96 (((x) & 0x000000ff00000000ull) >> 8) |
97 (((x) & 0x00000000ff000000ull) << 8) |
98 (((x) & 0x0000000000ff0000ull) << 24) |
99 (((x) & 0x000000000000ff00ull) << 40) |
100 (((x) & 0x00000000000000ffull) << 56);
101 return v;
102 }
103
104 #define FIXENDIAN32(x) (doswap ? swp32(x) : (x))
105 #define FIXENDIAN64(x) (doswap ? swp64(x) : (x))
106
107 /* compat for bus version 2 */
108 struct shmif_pkthdr2 {
109 uint32_t sp_len;
110
111 uint32_t sp_sec;
112 uint32_t sp_usec;
113 };
114
115 int
116 main(int argc, char *argv[])
117 {
118 struct stat sb;
119 void *busmem;
120 const char *pcapfile = NULL;
121 uint32_t curbus, buslast;
122 struct shmif_mem *bmem;
123 int fd, i, ch;
124 int bonus;
125 char *buf;
126 bool hflag = false, doswap = false;
127 pcap_dumper_t *pdump;
128 FILE *dumploc = stdout;
129 int useversion;
130
131 #ifdef PLATFORM_HAS_SETGETPROGNAME
132 setprogname(argv[0]);
133 #endif
134
135 while ((ch = getopt(argc, argv, "hp:")) != -1) {
136 switch (ch) {
137 case 'h':
138 hflag = true;
139 break;
140 case 'p':
141 pcapfile = optarg;
142 break;
143 default:
144 usage();
145 }
146 }
147
148 argc -= optind;
149 argv += optind;
150
151 if (argc != 1)
152 usage();
153
154 buf = malloc(BUFSIZE);
155 if (buf == NULL)
156 err(1, "malloc");
157
158 fd = open(argv[0], O_RDONLY);
159 if (fd == -1)
160 err(1, "open bus");
161
162 if (fstat(fd, &sb) == -1)
163 err(1, "stat");
164
165 busmem = mmap(NULL, sb.st_size, PROT_READ, MAP_FILE|MAP_SHARED, fd, 0);
166 if (busmem == MAP_FAILED)
167 err(1, "mmap");
168 bmem = busmem;
169
170 if (bmem->shm_magic != SHMIF_MAGIC) {
171 if (bmem->shm_magic != swp32(SHMIF_MAGIC))
172 errx(1, "%s not a shmif bus", argv[0]);
173 doswap = true;
174 }
175 if (FIXENDIAN32(bmem->shm_version) != SHMIF_VERSION) {
176 if (FIXENDIAN32(bmem->shm_version) != 2) {
177 errx(1, "bus version %d, program %d",
178 FIXENDIAN32(bmem->shm_version), SHMIF_VERSION);
179 }
180 useversion = 2;
181 } else {
182 useversion = 3;
183 }
184
185 if (pcapfile && strcmp(pcapfile, "-") == 0)
186 dumploc = stderr;
187
188 fprintf(dumploc, "bus version %d, lock: %d, generation: %" PRIu64
189 ", firstoff: 0x%04x, lastoff: 0x%04x\n",
190 FIXENDIAN32(bmem->shm_version), FIXENDIAN32(bmem->shm_lock),
191 FIXENDIAN64(bmem->shm_gen),
192 FIXENDIAN32(bmem->shm_first), FIXENDIAN32(bmem->shm_last));
193
194 if (hflag)
195 exit(0);
196
197 if (pcapfile) {
198 pcap_t *pcap = pcap_open_dead(DLT_EN10MB, 1518);
199 pdump = pcap_dump_open(pcap, pcapfile);
200 if (pdump == NULL)
201 err(1, "cannot open pcap dump file");
202 } else {
203 /* XXXgcc */
204 pdump = NULL;
205 }
206
207 curbus = FIXENDIAN32(bmem->shm_first);
208 buslast = FIXENDIAN32(bmem->shm_last);
209 if (curbus == BUSMEM_DATASIZE)
210 curbus = 0;
211
212 bonus = 0;
213 if (buslast < curbus)
214 bonus = 1;
215
216 i = 0;
217
218 while (curbus <= buslast || bonus) {
219 struct pcap_pkthdr packhdr;
220 uint32_t oldoff;
221 uint32_t curlen;
222 uint32_t sp_sec, sp_usec, sp_len;
223 bool wrap;
224
225 assert(curbus < sb.st_size);
226
227 wrap = false;
228 oldoff = curbus;
229
230 if (useversion == 3) {
231 struct shmif_pkthdr sp;
232
233 curbus = shmif_busread(bmem,
234 &sp, oldoff, sizeof(sp), &wrap);
235 sp_len = FIXENDIAN32(sp.sp_len);
236 sp_sec = FIXENDIAN32(sp.sp_sec);
237 sp_usec = FIXENDIAN32(sp.sp_usec);
238 } else {
239 struct shmif_pkthdr2 sp2;
240
241 curbus = shmif_busread(bmem,
242 &sp2, oldoff, sizeof(sp2), &wrap);
243 sp_len = FIXENDIAN32(sp2.sp_len);
244 sp_sec = FIXENDIAN32(sp2.sp_sec);
245 sp_usec = FIXENDIAN32(sp2.sp_usec);
246 }
247 if (wrap)
248 bonus = 0;
249
250 assert(curbus < sb.st_size);
251 curlen = sp_len;
252
253 if (curlen == 0) {
254 continue;
255 }
256
257 fprintf(dumploc, "packet %d, offset 0x%04x, length 0x%04x, "
258 "ts %d/%06d\n", i++, curbus, curlen,
259 sp_sec, sp_usec);
260
261 if (!pcapfile) {
262 curbus = shmif_busread(bmem,
263 buf, curbus, curlen, &wrap);
264 if (wrap)
265 bonus = 0;
266 continue;
267 }
268
269 memset(&packhdr, 0, sizeof(packhdr));
270 packhdr.caplen = packhdr.len = curlen;
271 packhdr.ts.tv_sec = sp_sec;
272 packhdr.ts.tv_usec = sp_usec;
273 assert(curlen <= BUFSIZE);
274
275 curbus = shmif_busread(bmem, buf, curbus, curlen, &wrap);
276 pcap_dump((u_char *)pdump, &packhdr, (u_char *)buf);
277 if (wrap)
278 bonus = 0;
279 }
280
281 if (pcapfile)
282 pcap_dump_close(pdump);
283
284 return 0;
285 }
286