1 /* Copyright (C) 2008 The Android Open Source Project 2 ** 3 ** This software is licensed under the terms of the GNU General Public 4 ** License version 2, as published by the Free Software Foundation, and 5 ** may be copied, distributed, and modified under those terms. 6 ** 7 ** This program is distributed in the hope that it will be useful, 8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 ** GNU General Public License for more details. 11 */ 12 #include "tcpdump.h" 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <sys/time.h> 16 17 int qemu_tcpdump_active; 18 19 static FILE* capture_file; 20 static uint64_t capture_count; 21 static uint64_t capture_size; 22 static int capture_init; 23 24 static void 25 capture_atexit(void) 26 { 27 if (qemu_tcpdump_active) { 28 fclose(capture_file); 29 qemu_tcpdump_active = 0; 30 } 31 } 32 33 /* See http://wiki.wireshark.org/Development/LibpcapFileFormat for 34 * the complete description of the packet capture file format 35 */ 36 37 #define PCAP_MAGIC 0xa1b2c3d4 38 #define PCAP_MAJOR 2 39 #define PCAP_MINOR 4 40 #define PCAP_SNAPLEN 65535 41 #define PCAP_ETHERNET 1 42 43 static int 44 pcap_write_header( FILE* out ) 45 { 46 typedef struct { 47 uint32_t magic; 48 uint16_t version_major; 49 uint16_t version_minor; 50 int32_t this_zone; 51 uint32_t sigfigs; 52 uint32_t snaplen; 53 uint32_t network; 54 } PcapHeader; 55 56 PcapHeader h; 57 58 h.magic = PCAP_MAGIC; 59 h.version_major = PCAP_MAJOR; 60 h.version_minor = PCAP_MINOR; 61 h.this_zone = 0; 62 h.sigfigs = 0; /* all tools set it to 0 in practice */ 63 h.snaplen = PCAP_SNAPLEN; 64 h.network = PCAP_ETHERNET; 65 66 if (fwrite(&h, sizeof(h), 1, out) != 1) { 67 return -1; 68 } 69 return 0; 70 } 71 72 int 73 qemu_tcpdump_start( const char* filepath ) 74 { 75 if (!capture_init) { 76 capture_init = 1; 77 atexit(capture_atexit); 78 } 79 80 qemu_tcpdump_stop(); 81 82 if (filepath == NULL) 83 return -1; 84 85 capture_file = fopen(filepath, "wb"); 86 if (capture_file == NULL) 87 return -1; 88 89 if (pcap_write_header(capture_file) < 0) 90 return -1; 91 92 qemu_tcpdump_active = 1; 93 return 0; 94 } 95 96 void 97 qemu_tcpdump_stop( void ) 98 { 99 if (!qemu_tcpdump_active) 100 return; 101 102 qemu_tcpdump_active = 0; 103 104 capture_count = 0; 105 capture_size = 0; 106 107 fclose(capture_file); 108 capture_file = NULL; 109 } 110 111 void 112 qemu_tcpdump_packet( const void* base, int len ) 113 { 114 typedef struct { 115 uint32_t ts_sec; 116 uint32_t ts_usec; 117 uint32_t incl_len; 118 uint32_t orig_len; 119 } PacketHeader; 120 121 PacketHeader h; 122 struct timeval now; 123 int len2 = len; 124 125 if (len2 > PCAP_SNAPLEN) 126 len2 = PCAP_SNAPLEN; 127 128 gettimeofday(&now, NULL); 129 h.ts_sec = (uint32_t) now.tv_sec; 130 h.ts_usec = (uint32_t) now.tv_usec; 131 h.incl_len = (uint32_t) len2; 132 h.orig_len = (uint32_t) len; 133 134 fwrite( &h, sizeof(h), 1, capture_file ); 135 fwrite( base, 1, len2, capture_file ); 136 137 capture_count += 1; 138 capture_size += len2; 139 } 140 141 void 142 qemu_tcpdump_stats( uint64_t *pcount, uint64_t* psize ) 143 { 144 *pcount = capture_count; 145 *psize = capture_size; 146 } 147 148