1 /* $NetBSD: shmif_dumpbus.c,v 1.11 2013/12/20 10:04:33 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.11 2013/12/20 10:04:33 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 #ifdef __NetBSD__ 73 #define SWAPME(a) (doswap ? bswap32(a) : (a)) 74 #define SWAPME64(a) (doswap ? bswap64(a) : (a)) 75 #else 76 /* lazy, but let's assume everyone uses shmif_dumpbus only locally */ 77 #define SWAPME(a) (a) 78 #define SWAPME64(a) (a) 79 #define bswap32(a) (a) 80 #endif 81 int 82 main(int argc, char *argv[]) 83 { 84 struct stat sb; 85 void *busmem; 86 const char *pcapfile = NULL; 87 uint32_t curbus, buslast; 88 struct shmif_mem *bmem; 89 int fd, i, ch; 90 int bonus; 91 char *buf; 92 bool hflag = false, doswap = false; 93 pcap_dumper_t *pdump; 94 FILE *dumploc = stdout; 95 96 #ifdef PLATFORM_HAS_SETGETPROGNAME 97 setprogname(argv[0]); 98 #endif 99 100 while ((ch = getopt(argc, argv, "hp:")) != -1) { 101 switch (ch) { 102 case 'h': 103 hflag = true; 104 break; 105 case 'p': 106 pcapfile = optarg; 107 break; 108 default: 109 usage(); 110 } 111 } 112 113 argc -= optind; 114 argv += optind; 115 116 if (argc != 1) 117 usage(); 118 119 buf = malloc(BUFSIZE); 120 if (buf == NULL) 121 err(1, "malloc"); 122 123 fd = open(argv[0], O_RDONLY); 124 if (fd == -1) 125 err(1, "open bus"); 126 127 if (fstat(fd, &sb) == -1) 128 err(1, "stat"); 129 130 busmem = mmap(NULL, sb.st_size, PROT_READ, MAP_FILE|MAP_SHARED, fd, 0); 131 if (busmem == MAP_FAILED) 132 err(1, "mmap"); 133 bmem = busmem; 134 135 if (bmem->shm_magic != SHMIF_MAGIC) { 136 if (bmem->shm_magic != bswap32(SHMIF_MAGIC)) 137 errx(1, "%s not a shmif bus", argv[0]); 138 doswap = 1; 139 } 140 if (SWAPME(bmem->shm_version) != SHMIF_VERSION) 141 errx(1, "bus vesrsion %d, program %d", 142 SWAPME(bmem->shm_version), SHMIF_VERSION); 143 144 if (pcapfile && strcmp(pcapfile, "-") == 0) 145 dumploc = stderr; 146 147 fprintf(dumploc, "bus version %d, lock: %d, generation: %" PRIu64 148 ", firstoff: 0x%04x, lastoff: 0x%04x\n", 149 SWAPME(bmem->shm_version), SWAPME(bmem->shm_lock), 150 SWAPME64(bmem->shm_gen), 151 SWAPME(bmem->shm_first), SWAPME(bmem->shm_last)); 152 153 if (hflag) 154 exit(0); 155 156 if (pcapfile) { 157 pcap_t *pcap = pcap_open_dead(DLT_EN10MB, 1518); 158 pdump = pcap_dump_open(pcap, pcapfile); 159 if (pdump == NULL) 160 err(1, "cannot open pcap dump file"); 161 } else { 162 /* XXXgcc */ 163 pdump = NULL; 164 } 165 166 curbus = SWAPME(bmem->shm_first); 167 buslast = SWAPME(bmem->shm_last); 168 if (curbus == BUSMEM_DATASIZE) 169 curbus = 0; 170 171 bonus = 0; 172 if (buslast < curbus) 173 bonus = 1; 174 175 i = 0; 176 while (curbus <= buslast || bonus) { 177 struct pcap_pkthdr packhdr; 178 struct shmif_pkthdr sp; 179 uint32_t oldoff; 180 uint32_t curlen; 181 bool wrap; 182 183 assert(curbus < sb.st_size); 184 185 wrap = false; 186 oldoff = curbus; 187 curbus = shmif_busread(bmem, &sp, oldoff, sizeof(sp), &wrap); 188 if (wrap) 189 bonus = 0; 190 191 assert(curbus < sb.st_size); 192 curlen = SWAPME(sp.sp_len); 193 194 if (curlen == 0) { 195 continue; 196 } 197 198 fprintf(dumploc, "packet %d, offset 0x%04x, length 0x%04x, " 199 "ts %d/%06d\n", i++, curbus, 200 curlen, SWAPME(sp.sp_sec), SWAPME(sp.sp_usec)); 201 202 if (!pcapfile) { 203 curbus = shmif_busread(bmem, 204 buf, curbus, curlen, &wrap); 205 if (wrap) 206 bonus = 0; 207 continue; 208 } 209 210 memset(&packhdr, 0, sizeof(packhdr)); 211 packhdr.caplen = packhdr.len = curlen; 212 packhdr.ts.tv_sec = SWAPME(sp.sp_sec); 213 packhdr.ts.tv_usec = SWAPME(sp.sp_usec); 214 assert(curlen <= BUFSIZE); 215 216 curbus = shmif_busread(bmem, buf, curbus, curlen, &wrap); 217 pcap_dump((u_char *)pdump, &packhdr, (u_char *)buf); 218 if (wrap) 219 bonus = 0; 220 } 221 222 if (pcapfile) 223 pcap_dump_close(pdump); 224 225 return 0; 226 } 227