blob: 585a5a07cca93d3bc4e4dd56ce7ad4e447982220 [file] [log] [blame]
/* 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 "android/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;
}