/* Copyright (C) 2008 The Android Open Source Project ** ** This software is licensed under the terms of the GNU General Public ** License version 2, as published by the Free Software Foundation, and ** may be copied, distributed, and modified under those terms. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. */ #include "tcpdump.h" #include <stdio.h> #include <stdlib.h> #include <sys/time.h> int qemu_tcpdump_active; static FILE* capture_file; static uint64_t capture_count; static uint64_t capture_size; static int capture_init; static void capture_atexit(void) { if (qemu_tcpdump_active) { fclose(capture_file); qemu_tcpdump_active = 0; } } /* See http://wiki.wireshark.org/Development/LibpcapFileFormat for * the complete description of the packet capture file format */ #define PCAP_MAGIC 0xa1b2c3d4 #define PCAP_MAJOR 2 #define PCAP_MINOR 4 #define PCAP_SNAPLEN 65535 #define PCAP_ETHERNET 1 static int pcap_write_header( FILE* out ) { typedef struct { uint32_t magic; uint16_t version_major; uint16_t version_minor; int32_t this_zone; uint32_t sigfigs; uint32_t snaplen; uint32_t network; } PcapHeader; PcapHeader h; h.magic = PCAP_MAGIC; h.version_major = PCAP_MAJOR; h.version_minor = PCAP_MINOR; h.this_zone = 0; h.sigfigs = 0; /* all tools set it to 0 in practice */ h.snaplen = PCAP_SNAPLEN; h.network = PCAP_ETHERNET; if (fwrite(&h, sizeof(h), 1, out) != 1) { return -1; } return 0; } int qemu_tcpdump_start( const char* filepath ) { if (!capture_init) { capture_init = 1; atexit(capture_atexit); } qemu_tcpdump_stop(); if (filepath == NULL) return -1; capture_file = fopen(filepath, "wb"); if (capture_file == NULL) return -1; if (pcap_write_header(capture_file) < 0) return -1; qemu_tcpdump_active = 1; return 0; } void qemu_tcpdump_stop( void ) { if (!qemu_tcpdump_active) return; qemu_tcpdump_active = 0; capture_count = 0; capture_size = 0; fclose(capture_file); capture_file = NULL; } void qemu_tcpdump_packet( const void* base, int len ) { typedef struct { uint32_t ts_sec; uint32_t ts_usec; uint32_t incl_len; uint32_t orig_len; } PacketHeader; PacketHeader h; struct timeval now; int len2 = len; if (len2 > PCAP_SNAPLEN) len2 = PCAP_SNAPLEN; gettimeofday(&now, NULL); h.ts_sec = (uint32_t) now.tv_sec; h.ts_usec = (uint32_t) now.tv_usec; h.incl_len = (uint32_t) len2; h.orig_len = (uint32_t) len; fwrite( &h, sizeof(h), 1, capture_file ); fwrite( base, 1, len2, capture_file ); capture_count += 1; capture_size += len2; } void qemu_tcpdump_stats( uint64_t *pcount, uint64_t* psize ) { *pcount = capture_count; *psize = capture_size; }