1 /* $NetBSD: shmif_dumpbus.c,v 1.18 2014/11/04 19:05: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.18 2014/11/04 19:05: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 HAVE_GETPROGNAME 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 setprogname(argv[0]); 132 while ((ch = getopt(argc, argv, "hp:")) != -1) { 133 switch (ch) { 134 case 'h': 135 hflag = true; 136 break; 137 case 'p': 138 pcapfile = optarg; 139 break; 140 default: 141 usage(); 142 } 143 } 144 145 argc -= optind; 146 argv += optind; 147 148 if (argc != 1) 149 usage(); 150 151 buf = malloc(BUFSIZE); 152 if (buf == NULL) 153 err(1, "malloc"); 154 155 fd = open(argv[0], O_RDONLY); 156 if (fd == -1) 157 err(1, "open bus"); 158 159 if (fstat(fd, &sb) == -1) 160 err(1, "stat"); 161 162 busmem = mmap(NULL, sb.st_size, PROT_READ, MAP_FILE|MAP_SHARED, fd, 0); 163 if (busmem == MAP_FAILED) 164 err(1, "mmap"); 165 bmem = busmem; 166 167 if (bmem->shm_magic != SHMIF_MAGIC) { 168 if (bmem->shm_magic != swp32(SHMIF_MAGIC)) 169 errx(1, "%s not a shmif bus", argv[0]); 170 doswap = true; 171 } 172 if (FIXENDIAN32(bmem->shm_version) != SHMIF_VERSION) { 173 if (FIXENDIAN32(bmem->shm_version) != 2) { 174 errx(1, "bus version %d, program %d", 175 FIXENDIAN32(bmem->shm_version), SHMIF_VERSION); 176 } 177 useversion = 2; 178 } else { 179 useversion = 3; 180 } 181 182 if (pcapfile && strcmp(pcapfile, "-") == 0) 183 dumploc = stderr; 184 185 fprintf(dumploc, "bus version %d, lock: %d, generation: %" PRIu64 186 ", firstoff: 0x%04x, lastoff: 0x%04x\n", 187 FIXENDIAN32(bmem->shm_version), FIXENDIAN32(bmem->shm_lock), 188 FIXENDIAN64(bmem->shm_gen), 189 FIXENDIAN32(bmem->shm_first), FIXENDIAN32(bmem->shm_last)); 190 191 if (hflag) 192 exit(0); 193 194 if (pcapfile) { 195 pcap_t *pcap = pcap_open_dead(DLT_EN10MB, 1518); 196 pdump = pcap_dump_open(pcap, pcapfile); 197 if (pdump == NULL) 198 err(1, "cannot open pcap dump file"); 199 } else { 200 /* XXXgcc */ 201 pdump = NULL; 202 } 203 204 curbus = FIXENDIAN32(bmem->shm_first); 205 buslast = FIXENDIAN32(bmem->shm_last); 206 if (curbus == BUSMEM_DATASIZE) 207 curbus = 0; 208 209 bonus = 0; 210 if (buslast < curbus) 211 bonus = 1; 212 213 i = 0; 214 215 while (curbus <= buslast || bonus) { 216 struct pcap_pkthdr packhdr; 217 uint32_t oldoff; 218 uint32_t curlen; 219 uint32_t sp_sec, sp_usec, sp_len; 220 bool wrap; 221 222 assert(curbus < sb.st_size); 223 224 wrap = false; 225 oldoff = curbus; 226 227 if (useversion == 3) { 228 struct shmif_pkthdr sp; 229 230 curbus = shmif_busread(bmem, 231 &sp, oldoff, sizeof(sp), &wrap); 232 sp_len = FIXENDIAN32(sp.sp_len); 233 sp_sec = FIXENDIAN32(sp.sp_sec); 234 sp_usec = FIXENDIAN32(sp.sp_usec); 235 } else { 236 struct shmif_pkthdr2 sp2; 237 238 curbus = shmif_busread(bmem, 239 &sp2, oldoff, sizeof(sp2), &wrap); 240 sp_len = FIXENDIAN32(sp2.sp_len); 241 sp_sec = FIXENDIAN32(sp2.sp_sec); 242 sp_usec = FIXENDIAN32(sp2.sp_usec); 243 } 244 if (wrap) 245 bonus = 0; 246 247 assert(curbus < sb.st_size); 248 curlen = sp_len; 249 250 if (curlen == 0) { 251 continue; 252 } 253 254 fprintf(dumploc, "packet %d, offset 0x%04x, length 0x%04x, " 255 "ts %d/%06d\n", i++, curbus, curlen, 256 sp_sec, sp_usec); 257 258 if (!pcapfile) { 259 curbus = shmif_busread(bmem, 260 buf, curbus, curlen, &wrap); 261 if (wrap) 262 bonus = 0; 263 continue; 264 } 265 266 memset(&packhdr, 0, sizeof(packhdr)); 267 packhdr.caplen = packhdr.len = curlen; 268 packhdr.ts.tv_sec = sp_sec; 269 packhdr.ts.tv_usec = sp_usec; 270 assert(curlen <= BUFSIZE); 271 272 curbus = shmif_busread(bmem, buf, curbus, curlen, &wrap); 273 pcap_dump((u_char *)pdump, &packhdr, (u_char *)buf); 274 if (wrap) 275 bonus = 0; 276 } 277 278 if (pcapfile) 279 pcap_dump_close(pdump); 280 281 return 0; 282 } 283