The Sniffer-reading code now checks to make sure that it is trying
[obnox/wireshark/wip.git] / wiretap / ngsniffer.c
1 /* ngsniffer.c
2  *
3  * $Id: ngsniffer.c,v 1.6 1998/11/21 05:08:40 gram Exp $
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@verdict.uthscsa.edu>
7  * 
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  * 
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  */
23
24 /* The code in ngsniffer.c that decodes the time fields for each packet in the
25  * Sniffer trace originally came from code from TCPVIEW:
26  *
27  * TCPVIEW
28  *
29  * Author:      Martin Hunt
30  *              Networks and Distributed Computing
31  *              Computing & Communications
32  *              University of Washington
33  *              Administration Building, AG-44
34  *              Seattle, WA  98195
35  *              Internet: martinh@cac.washington.edu
36  *
37  *
38  * Copyright 1992 by the University of Washington
39  *
40  * Permission to use, copy, modify, and distribute this software and its
41  * documentation for any purpose and without fee is hereby granted, provided
42  * that the above copyright notice appears in all copies and that both the
43  * above copyright notice and this permission notice appear in supporting
44  * documentation, and that the name of the University of Washington not be
45  * used in advertising or publicity pertaining to distribution of the software
46  * without specific, written prior permission.  This software is made
47  * available "as is", and
48  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
49  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
50  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
51  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
52  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
53  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
54  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
55  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
56  *
57  */
58
59 #include <stdlib.h>
60 #include "wtap.h"
61 #include "ngsniffer.h"
62
63 /* values for V.timeunit */
64 #define NUM_NGSNIFF_TIMEUNITS 7
65 static double Usec[] = { 15.0, 0.838096, 15.0, 0.5, 2.0, 0.0, 0.1 };
66
67 #define NUM_NGSNIFF_ENCAPS 11
68 static int sniffer_encap[] = {
69                 WTAP_ENCAP_TR,
70                 WTAP_ENCAP_ETHERNET,
71                 WTAP_ENCAP_ARCNET,
72                 WTAP_ENCAP_NONE,        /* StarLAN */
73                 WTAP_ENCAP_NONE,        /* PC Network broadband */
74                 WTAP_ENCAP_NONE,        /* LocalTalk */
75                 WTAP_ENCAP_NONE,        /* Znet */
76                 WTAP_ENCAP_NONE,        /* Internetwork analyzer */
77                 WTAP_ENCAP_NONE,        /* type 8 not defined in Sniffer */
78                 WTAP_ENCAP_FDDI,
79                 WTAP_ENCAP_NONE         /* ATM */
80 };
81
82 /* Returns WTAP_FILE_NGSNIFFER on success, WTAP_FILE_UNKNOWN on failure */
83 int ngsniffer_open(wtap *wth)
84 {
85         int bytes_read;
86         char magic[18];
87         char record_type[2];
88         char record_length[4]; /* only the first 2 bytes are length,
89                                                           the last 2 are "reserved" and are thrown away */
90         guint16 type, length = 0;
91         char    format;
92         char    network;
93         char    version[18]; /* to hold the entire version record */
94         char    timeunit;
95
96         /* Read in the string that should be at the start of a Sniffer file */
97         fseek(wth->fh, 0, SEEK_SET);
98         bytes_read = fread(magic, 1, 17, wth->fh);
99
100         if (bytes_read != 17) {
101                 return WTAP_FILE_UNKNOWN;
102         }
103
104         magic[17] = 0;
105
106         if (strcmp(magic, "TRSNIFF data    \x1a")) {
107                 return WTAP_FILE_UNKNOWN;
108         }
109
110         /* This is a ngsniffer file */
111         wth->capture.ngsniffer = g_malloc(sizeof(ngsniffer_t));
112         wth->subtype_read = ngsniffer_read;
113         wth->snapshot_length = 16384;   /* XXX - available in header? */
114         /*wth->frame_number = 0;*/
115         /*wth->file_byte_offset = 0x10b;*/
116
117         /* Read records until we find the start of packets */
118         while (1) {
119                 fseek(wth->fh, length, SEEK_CUR);
120                 bytes_read = fread(record_type, 1, 2, wth->fh);
121                 bytes_read += fread(record_length, 1, 4, wth->fh);
122                 if (bytes_read != 6) {
123                         free(wth->capture.ngsniffer);
124                         return WTAP_FILE_UNKNOWN;
125                 }
126
127                 type = pletohs(record_type);
128                 length = pletohs(record_length);
129
130                 switch (type) {
131                         /* Version Record */
132                         case REC_VERS:
133                                 fread(version, 1, 18, wth->fh);
134                                 length = 0; /* to fake the next iteration of while() */
135
136                                 /* Make sure this is an uncompressed Sniffer file */
137                                 format = version[10];
138                                 if (format != 1) {
139                                         g_message("ngsniffer: This Sniffer file type is not supported");
140                                         free(wth->capture.ngsniffer);
141                                         return WTAP_FILE_UNKNOWN;
142                                 }
143
144                                 /* Get data link type */
145                                 network = version[9];
146                                 if (network >= NUM_NGSNIFF_ENCAPS) {
147                                         g_message("ngsniffer: network type %d unknown", network);
148                                         free(wth->capture.ngsniffer);
149                                         return WTAP_FILE_UNKNOWN;
150                                 }
151                                 else {
152                                         wth->encapsulation = sniffer_encap[network];
153                                 }
154
155                                 /* Get time unit */
156                                 timeunit = version[11];
157                                 if (timeunit >= NUM_NGSNIFF_TIMEUNITS) {
158                                         g_message("ngsniffer: Unknown timeunit %d", timeunit);
159                                         free(wth->capture.ngsniffer);
160                                         return WTAP_FILE_UNKNOWN;
161                                 }
162                                 else {
163                                         wth->capture.ngsniffer->timeunit = Usec[timeunit];
164                                 }
165                                 break;
166
167                         case REC_FRAME2:
168                                 wth->capture.ngsniffer->pkt_len = length - 14;
169                                 return WTAP_FILE_NGSNIFFER;
170
171                         default:
172                                 /* Continue with while() loop */
173                 }
174         }
175
176         /* never gets here */
177         return WTAP_FILE_NGSNIFFER;
178 }
179
180 /* Read the next packet */
181 int ngsniffer_read(wtap *wth)
182 {
183         int     packet_size = wth->capture.ngsniffer->pkt_len;
184         int     bytes_read;
185         char record_type[2];
186         char record_length[4]; /* only 1st 2 bytes are length */
187         guint16 type, length;
188         char frame2[14];
189         double t, x;
190         guint16 time_low, time_med, time_high, true_size, size;
191         int     data_offset;
192
193         /* if this is the very first packet, then the fh cursor will be at the
194          * start of a f_frame2_struct instead of at the start of the record.
195          * Check for this */
196         if (!packet_size) {
197
198                 /* Read record info */
199                 bytes_read = fread(record_type, 1, 2, wth->fh);
200                 bytes_read += fread(record_length, 1, 4, wth->fh);
201                 if (bytes_read != 6) {
202                         return 0;
203                 }
204
205                 type = pletohs(record_type);
206                 length = pletohs(record_length);
207
208                 if (type != REC_FRAME2) {
209                         return 0;
210                 }
211                 else {
212                         packet_size = length - 14;
213                 }
214         }
215         else {
216                 wth->capture.ngsniffer->pkt_len = 0;
217         }
218
219         /* Read the f_frame2_struct */
220         bytes_read = fread(frame2, 1, 14, wth->fh);
221         if (bytes_read != 14) {
222                 g_message("ngsniffer_read: not enough frame2 data (%d bytes)",
223                                 bytes_read);
224                 return 0;
225         }
226
227         /* Read some of the fields in frame2 */
228         size = pletohs(&frame2[6]);
229         true_size = pletohs(&frame2[10]);
230         time_low = pletohs(&frame2[0]);
231         time_med = pletohs(&frame2[2]);
232         time_high = frame2[4];
233
234         buffer_assure_space(&wth->frame_buffer, packet_size);
235         data_offset = ftell(wth->fh);
236         bytes_read = fread(buffer_start_ptr(&wth->frame_buffer), 1,
237                         packet_size, wth->fh);
238
239         if (bytes_read != packet_size) {
240                 if (ferror(wth->fh)) {
241                         g_message("ngsniffer_read: fread for data: read error\n");
242                 } else {
243                         g_message("ngsniffer_read: fread for data: %d bytes out of %d",
244                                 bytes_read, packet_size);
245                 }
246                 return -1;
247         }
248
249         x = 4.0 * (double)(1<<30);
250         t = (double)time_low+(double)(time_med)*65536.0 +
251                 (double)time_high*x;
252         t = t/1000000.0 * wth->capture.ngsniffer->timeunit; /* t = # of secs */
253
254         wth->phdr.ts.tv_sec = (long)t;
255         wth->phdr.ts.tv_usec = (unsigned long)((t-(double)(wth->phdr.ts.tv_sec))
256                         *1.0e6);
257         wth->phdr.len = true_size ? true_size : size;
258         wth->phdr.caplen = size;
259
260         return data_offset;
261 }