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
capture_atexit(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
pcap_write_header(FILE * out)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
qemu_tcpdump_start(const char * filepath)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
qemu_tcpdump_stop(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
qemu_tcpdump_packet(const void * base,int len)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
qemu_tcpdump_stats(uint64_t * pcount,uint64_t * psize)142 qemu_tcpdump_stats( uint64_t *pcount, uint64_t* psize )
143 {
144 *pcount = capture_count;
145 *psize = capture_size;
146 }
147
148