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 17int qemu_tcpdump_active; 18 19static FILE* capture_file; 20static uint64_t capture_count; 21static uint64_t capture_size; 22static int capture_init; 23 24static void 25capture_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 43static int 44pcap_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 72int 73qemu_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 96void 97qemu_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 111void 112qemu_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 141void 142qemu_tcpdump_stats( uint64_t *pcount, uint64_t* psize ) 143{ 144 *pcount = capture_count; 145 *psize = capture_size; 146} 147 148