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