2 * Routines for opening etherpeek files
3 * Copyright (c) 2001, Daniel Thompson <d.thompson@gmx.net>
5 * $Id: etherpeek.c,v 1.5 2001/10/04 08:30:35 guy Exp $
8 * Copyright (c) 1998 by Gilbert Ramirez <gram@xiexie.org>
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #include "file_wrappers.h"
34 #include "etherpeek.h"
35 #ifdef HAVE_NETINET_IN_H
36 #include <netinet/in.h>
41 * This file decoder could not have been writen without examining how
42 * tcptrace (http://www.tcptrace.org/) handles etherpeek files.
46 typedef struct etherpeek_master_header {
49 } etherpeek_master_header_t;
50 #define ETHERPEEK_MASTER_HDR_SIZE 2
52 /* secondary header (Mac V5,V6,V7) */
53 typedef struct etherpeek_m567_header {
60 } etherpeek_m567_header_t;
61 #define ETHERPEEK_M567_HDR_SIZE 48
64 typedef struct etherpeek_header {
65 etherpeek_master_header_t master;
67 etherpeek_m567_header_t m567;
71 /* packet header (Mac V5, V6) */
72 typedef struct etherpeek_m56_packet {
82 } etherpeek_m56_packet_t;
83 #define ETHERPEEK_M56_PKT_SIZE 24
85 /* 64-bit time in micro seconds from the (Mac) epoch */
86 typedef struct etherpeek_utime {
91 /* packet header (Mac V7) */
92 typedef struct etherpeek_m7_packet {
100 } etherpeek_m7_packet_t;
101 #define ETHERPEEK_M7_PKT_SIZE 16
103 typedef struct etherpeek_encap_lookup {
106 } etherpeek_encap_lookup_t;
108 static const unsigned int mac2unix = 2082844800u;
109 static const etherpeek_encap_lookup_t etherpeek_encap[] = {
110 { 1400, WTAP_ENCAP_ETHERNET }
112 #define NUM_ETHERPEEK_ENCAPS \
113 (sizeof (etherpeek_encap) / sizeof (etherpeek_encap[0]))
115 static gboolean etherpeek_read_m7(wtap *wth, int *err, long *data_offset);
116 static gboolean etherpeek_read_m56(wtap *wth, int *err, long *data_offset);
118 int etherpeek_open(wtap *wth, int *err)
120 etherpeek_header_t ep_hdr;
122 /* etherpeek files to not start with a magic value large enough
123 * to be unique hence we use the following algorithm to determine
124 * the type of an unknown file
125 * - populate the master header and reject file if there is no match
126 * - populate the secondary header and check that the reserved space
127 * is zero; there is an obvious flaw here so this algorithm will
128 * probably need to be revisiting when improving etherpeek
132 g_assert(sizeof(ep_hdr.master) == ETHERPEEK_MASTER_HDR_SIZE);
133 wtap_file_read_unknown_bytes(
134 &ep_hdr.master, sizeof(ep_hdr.master), wth->fh, err);
135 wth->data_offset += sizeof(ep_hdr.master);
137 /* switch on the file version */
138 switch (ep_hdr.master.version) {
142 /* get the secondary header */
143 g_assert(sizeof(ep_hdr.secondary.m567) ==
144 ETHERPEEK_M567_HDR_SIZE);
145 wtap_file_read_unknown_bytes(
146 &ep_hdr.secondary.m567,
147 sizeof(ep_hdr.secondary.m567), wth->fh, err);
148 wth->data_offset += sizeof(ep_hdr.secondary.m567);
150 if ((0 != ep_hdr.secondary.m567.reserved[0]) ||
151 (0 != ep_hdr.secondary.m567.reserved[1]) ||
152 (0 != ep_hdr.secondary.m567.reserved[2]) ||
153 (0 != ep_hdr.secondary.m567.reserved[3])) {
158 /* we have a match for a Mac V5, V6 or V7,
159 * so it is worth preforming byte swaps
161 ep_hdr.secondary.m567.filelength =
162 ntohl(ep_hdr.secondary.m567.filelength);
163 ep_hdr.secondary.m567.numPackets =
164 ntohl(ep_hdr.secondary.m567.numPackets);
165 ep_hdr.secondary.m567.timeDate =
166 ntohl(ep_hdr.secondary.m567.timeDate);
167 ep_hdr.secondary.m567.timeStart =
168 ntohl(ep_hdr.secondary.m567.timeStart);
169 ep_hdr.secondary.m567.timeStop =
170 ntohl(ep_hdr.secondary.m567.timeStop);
172 /* populate the pseudo header */
173 wth->pseudo_header.etherpeek.reference_time.tv_sec =
174 ep_hdr.secondary.m567.timeDate - mac2unix;
175 wth->pseudo_header.etherpeek.reference_time.tv_usec =
182 /* at this point we have recognised the file type and have populated
183 * the whole ep_hdr structure in host byte order
186 switch (ep_hdr.master.version) {
189 wth->file_type = WTAP_FILE_ETHERPEEK_MAC_V56;
190 wth->subtype_read = etherpeek_read_m56;
191 wth->subtype_seek_read = wtap_def_seek_read;
194 wth->file_type = WTAP_FILE_ETHERPEEK_MAC_V7;
195 wth->subtype_read = etherpeek_read_m7;
196 wth->subtype_seek_read = wtap_def_seek_read;
199 /* this is impossible */
200 g_assert_not_reached();
203 wth->file_encap = WTAP_ENCAP_PER_PACKET;
204 wth->snapshot_length = 16384; /* just guessing */
209 static gboolean etherpeek_read_m7(wtap *wth, int *err, long *data_offset)
211 etherpeek_m7_packet_t ep_pkt;
215 g_assert(sizeof(ep_pkt) == ETHERPEEK_M7_PKT_SIZE);
216 wtap_file_read_expected_bytes(&ep_pkt, sizeof(ep_pkt), wth->fh, err);
217 wth->data_offset += sizeof(ep_pkt);
220 ep_pkt.protoNum = ntohs(ep_pkt.protoNum);
221 ep_pkt.length = ntohs(ep_pkt.length);
222 ep_pkt.sliceLength = ntohs(ep_pkt.sliceLength);
223 ep_pkt.timestamp.upper = ntohl(ep_pkt.timestamp.upper);
224 ep_pkt.timestamp.lower = ntohl(ep_pkt.timestamp.lower);
226 /* force sliceLength to be the actual length of the packet */
227 if (0 == ep_pkt.sliceLength) {
228 ep_pkt.sliceLength = ep_pkt.length;
231 /* test for corrupt data */
232 if (ep_pkt.sliceLength > WTAP_MAX_PACKET_SIZE) {
233 *err = WTAP_ERR_BAD_RECORD;
237 *data_offset = wth->data_offset;
239 /* read the frame data */
240 buffer_assure_space(wth->frame_buffer, ep_pkt.sliceLength);
241 wtap_file_read_expected_bytes(buffer_start_ptr(wth->frame_buffer),
242 ep_pkt.sliceLength, wth->fh, err);
243 wth->data_offset += ep_pkt.sliceLength;
245 /* fill in packet header values */
246 wth->phdr.len = ep_pkt.length;
247 wth->phdr.caplen = ep_pkt.sliceLength;
249 t = (double) ep_pkt.timestamp.lower +
250 (double) ep_pkt.timestamp.upper * 4294967296.0;
251 t -= (double) mac2unix * 1000000.0;
252 wth->phdr.ts.tv_sec = (time_t) (t/1000000.0);
253 wth->phdr.ts.tv_usec = (guint32) (t - (double) wth->phdr.ts.tv_sec *
255 wth->phdr.pkt_encap = WTAP_ENCAP_UNKNOWN;
256 for (i=0; i<NUM_ETHERPEEK_ENCAPS; i++) {
257 if (etherpeek_encap[i].protoNum == ep_pkt.protoNum) {
258 wth->phdr.pkt_encap = etherpeek_encap[i].encap;
265 static gboolean etherpeek_read_m56(wtap *wth, int *err, long *data_offset)
267 etherpeek_m56_packet_t ep_pkt;
270 g_assert(sizeof(ep_pkt) == ETHERPEEK_M56_PKT_SIZE);
271 wtap_file_read_expected_bytes(&ep_pkt, sizeof(ep_pkt), wth->fh, err);
272 wth->data_offset += sizeof(ep_pkt);
275 ep_pkt.length = ntohs(ep_pkt.length);
276 ep_pkt.sliceLength = ntohs(ep_pkt.sliceLength);
277 ep_pkt.timestamp = ntohl(ep_pkt.timestamp);
278 ep_pkt.destNum = ntohs(ep_pkt.destNum);
279 ep_pkt.srcNum = ntohs(ep_pkt.srcNum);
280 ep_pkt.protoNum = ntohs(ep_pkt.protoNum);
282 /* force sliceLength to be the actual length of the packet */
283 if (0 == ep_pkt.sliceLength) {
284 ep_pkt.sliceLength = ep_pkt.length;
287 /* test for corrupt data */
288 if (ep_pkt.sliceLength > WTAP_MAX_PACKET_SIZE) {
289 *err = WTAP_ERR_BAD_RECORD;
293 *data_offset = wth->data_offset;
295 /* fill in packet header values */
296 wth->phdr.len = ep_pkt.length;
297 wth->phdr.caplen = ep_pkt.sliceLength;
298 /* timestamp is in milliseconds since reference_time */
299 wth->phdr.ts.tv_sec = wth->pseudo_header.etherpeek.
300 reference_time.tv_sec + (ep_pkt.timestamp / 1000);
301 wth->phdr.ts.tv_usec = 1000 * (ep_pkt.timestamp % 1000);
303 wth->phdr.pkt_encap = WTAP_ENCAP_UNKNOWN;
304 for (i=0; i<NUM_ETHERPEEK_ENCAPS; i++) {
305 if (etherpeek_encap[i].protoNum == ep_pkt.protoNum) {
306 wth->phdr.pkt_encap = etherpeek_encap[i].encap;