1 /* $NetBSD: shmif_dumpbus.c,v 1.19 2020/04/01 21:04:34 christos 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.19 2020/04/01 21:04:34 christos 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", 68 getprogname()); 69 exit(EXIT_FAILURE); 70 } 71 72 #define BUFSIZE 64*1024 73 74 /* 75 * byte swapdom 76 */ 77 static uint32_t 78 swp32(uint32_t x) 79 { 80 uint32_t v; 81 82 v = (((x) & 0xff000000) >> 24) | 83 (((x) & 0x00ff0000) >> 8) | 84 (((x) & 0x0000ff00) << 8) | 85 (((x) & 0x000000ff) << 24); 86 return v; 87 } 88 89 static uint64_t 90 swp64(uint64_t x) 91 { 92 uint64_t v; 93 94 v = (((x) & 0xff00000000000000ull) >> 56) | 95 (((x) & 0x00ff000000000000ull) >> 40) | 96 (((x) & 0x0000ff0000000000ull) >> 24) | 97 (((x) & 0x000000ff00000000ull) >> 8) | 98 (((x) & 0x00000000ff000000ull) << 8) | 99 (((x) & 0x0000000000ff0000ull) << 24) | 100 (((x) & 0x000000000000ff00ull) << 40) | 101 (((x) & 0x00000000000000ffull) << 56); 102 return v; 103 } 104 105 #define FIXENDIAN32(x) (doswap ? swp32(x) : (uint32_t)(x)) 106 #define FIXENDIAN64(x) (doswap ? swp64(x) : (uint64_t)(x)) 107 108 /* compat for bus version 2 */ 109 struct shmif_pkthdr2 { 110 uint32_t sp_len; 111 112 uint32_t sp_sec; 113 uint32_t sp_usec; 114 }; 115 116 int 117 main(int argc, char *argv[]) 118 { 119 struct stat sb; 120 void *busmem; 121 const char *pcapfile = NULL; 122 uint32_t curbus, buslast; 123 struct shmif_mem *bmem; 124 int fd, i, ch; 125 int bonus; 126 char *buf; 127 bool hflag = false, doswap = false; 128 pcap_dumper_t *pdump; 129 FILE *dumploc = stdout; 130 uint32_t useversion; 131 132 setprogname(argv[0]); 133 while ((ch = getopt(argc, argv, "hp:")) != -1) { 134 switch (ch) { 135 case 'h': 136 hflag = true; 137 break; 138 case 'p': 139 pcapfile = optarg; 140 break; 141 default: 142 usage(); 143 } 144 } 145 146 argc -= optind; 147 argv += optind; 148 149 if (argc != 1) 150 usage(); 151 152 buf = malloc(BUFSIZE); 153 if (buf == NULL) 154 err(EXIT_FAILURE, "malloc"); 155 156 fd = open(argv[0], O_RDONLY); 157 if (fd == -1) 158 err(EXIT_FAILURE, "Can't open bus file `%s'", argv[0]); 159 160 if (fstat(fd, &sb) == -1) 161 err(EXIT_FAILURE, "Can't stat bus file `%s'", argv[0]); 162 163 busmem = mmap(NULL, (size_t)sb.st_size, PROT_READ, MAP_FILE|MAP_SHARED, 164 fd, 0); 165 if (busmem == MAP_FAILED) 166 err(EXIT_FAILURE, "mmap"); 167 bmem = busmem; 168 169 if (bmem->shm_magic != SHMIF_MAGIC) { 170 if (bmem->shm_magic != swp32(SHMIF_MAGIC)) 171 errx(EXIT_FAILURE, "%s not a shmif bus: " 172 "bad magic %#x != %#x", argv[0], bmem->shm_magic, 173 SHMIF_MAGIC); 174 doswap = true; 175 } 176 useversion = FIXENDIAN32(bmem->shm_version); 177 switch (useversion) { 178 case 2: 179 case SHMIF_VERSION: 180 break; 181 default: 182 errx(EXIT_FAILURE, "Unhandled bus version %d, program %d", 183 useversion, SHMIF_VERSION); 184 } 185 186 if (pcapfile && strcmp(pcapfile, "-") == 0) 187 dumploc = stderr; 188 189 fprintf(dumploc, "bus version %d, lock: %d, generation: %" PRIu64 190 ", firstoff: 0x%04x, lastoff: 0x%04x\n", 191 FIXENDIAN32(bmem->shm_version), FIXENDIAN32(bmem->shm_lock), 192 FIXENDIAN64(bmem->shm_gen), 193 FIXENDIAN32(bmem->shm_first), FIXENDIAN32(bmem->shm_last)); 194 195 if (hflag) 196 exit(0); 197 198 if (pcapfile) { 199 pcap_t *pcap = pcap_open_dead(DLT_EN10MB, 1518); 200 pdump = pcap_dump_open(pcap, pcapfile); 201 if (pdump == NULL) { 202 errx(EXIT_FAILURE, 203 "Cannot open pcap dump file `%s': %s", pcapfile, 204 pcap_geterr(pcap)); 205 } 206 } else { 207 /* XXXgcc */ 208 pdump = NULL; 209 } 210 211 curbus = FIXENDIAN32(bmem->shm_first); 212 buslast = FIXENDIAN32(bmem->shm_last); 213 if (curbus == BUSMEM_DATASIZE) 214 curbus = 0; 215 216 bonus = 0; 217 if (buslast < curbus) 218 bonus = 1; 219 220 i = 0; 221 222 while (curbus <= buslast || bonus) { 223 struct pcap_pkthdr packhdr; 224 uint32_t oldoff; 225 uint32_t curlen; 226 uint32_t sp_sec, sp_usec, sp_len; 227 bool wrap; 228 229 assert(curbus < sb.st_size); 230 231 wrap = false; 232 oldoff = curbus; 233 234 if (useversion == 3) { 235 struct shmif_pkthdr sp; 236 237 curbus = shmif_busread(bmem, 238 &sp, oldoff, sizeof(sp), &wrap); 239 sp_len = FIXENDIAN32(sp.sp_len); 240 sp_sec = FIXENDIAN32(sp.sp_sec); 241 sp_usec = FIXENDIAN32(sp.sp_usec); 242 } else { 243 struct shmif_pkthdr2 sp2; 244 245 curbus = shmif_busread(bmem, 246 &sp2, oldoff, sizeof(sp2), &wrap); 247 sp_len = FIXENDIAN32(sp2.sp_len); 248 sp_sec = FIXENDIAN32(sp2.sp_sec); 249 sp_usec = FIXENDIAN32(sp2.sp_usec); 250 } 251 if (wrap) 252 bonus = 0; 253 254 assert(curbus < sb.st_size); 255 curlen = sp_len; 256 257 if (curlen == 0) { 258 continue; 259 } 260 261 fprintf(dumploc, "packet %d, offset 0x%04x, length 0x%04x, " 262 "ts %d/%06d\n", i++, curbus, curlen, 263 sp_sec, sp_usec); 264 265 if (!pcapfile) { 266 curbus = shmif_busread(bmem, 267 buf, curbus, curlen, &wrap); 268 if (wrap) 269 bonus = 0; 270 continue; 271 } 272 273 memset(&packhdr, 0, sizeof(packhdr)); 274 packhdr.caplen = packhdr.len = curlen; 275 packhdr.ts.tv_sec = sp_sec; 276 packhdr.ts.tv_usec = (suseconds_t)sp_usec; 277 assert(curlen <= BUFSIZE); 278 279 curbus = shmif_busread(bmem, buf, curbus, curlen, &wrap); 280 pcap_dump((u_char *)pdump, &packhdr, (u_char *)buf); 281 if (wrap) 282 bonus = 0; 283 } 284 285 if (pcapfile) 286 pcap_dump_close(pdump); 287 288 return EXIT_SUCCESS; 289 } 290