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