Don't write out packets that have a "captured length" bigger than we're
[metze/wireshark/wip.git] / wiretap / lanalyzer.c
1 /* lanalyzer.c
2  *
3  * $Id$
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include "config.h"
24 #include <stdlib.h>
25 #include <errno.h>
26 #include "wtap-int.h"
27 #include "file_wrappers.h"
28 #include "buffer.h"
29 #include "lanalyzer.h"
30
31 /* The LANalyzer format is documented (at least in part) in Novell document
32    TID022037, which can be found at, among other places:
33
34         http://www.windowsecurity.com/whitepapers/Description_of_the_LANalysers_output_file.html
35  */
36
37 /*    Record header format */
38
39 typedef struct {
40         guint8  record_type[2];
41         guint8  record_length[2];
42 } LA_RecordHeader;
43
44 #define LA_RecordHeaderSize 4
45
46 /*    Record type codes:                */
47
48 #define     RT_HeaderRegular       0x1001
49 #define     RT_HeaderCyclic        0x1007
50 #define     RT_RxChannelName       0x1006
51 #define     RT_TxChannelName       0x100b
52 #define     RT_FilterName          0x1032
53 #define     RT_RxTemplateName      0x1035
54 #define     RT_TxTemplateName      0x1036
55 #define     RT_DisplayOptions      0x100a
56 #define     RT_Summary             0x1002
57 #define     RT_SubfileSummary      0x1003
58 #define     RT_CyclicInformation   0x1009
59 #define     RT_Index               0x1004
60 #define     RT_PacketData          0x1005
61
62 #define     LA_ProFileLimit       (1024 * 1024 * 32)
63
64 typedef guint8  Eadr[6];
65 typedef guint16 TimeStamp[3];  /* 0.5 microseconds since start of trace */
66
67 /*
68  * These records have only 2-byte alignment for 4-byte quantities,
69  * so the structures aren't necessarily valid; they're kept as comments
70  * for reference purposes.
71  */
72
73 /*
74  * typedef struct {
75  *       guint8      day;
76  *       guint8      mon;
77  *       gint16      year;
78  *       } Date;
79  */
80
81 /*
82  * typedef struct {
83  *       guint8      second;
84  *       guint8      minute;
85  *       guint8      hour;
86  *       guint8      day;
87  *       gint16      reserved;
88  *       } Time;
89  */
90
91 /*
92  * RT_Summary:
93  *
94  * typedef struct {
95  *       Date        datcre;
96  *       Date        datclo;
97  *       Time        timeopn;
98  *       Time        timeclo;
99  *       Eadr        statadr;
100  *       gint16      mxseqno;
101  *       gint16      slcoff;
102  *       gint16      mxslc;
103  *       gint32      totpktt;
104  *       gint32      statrg;
105  *       gint32      stptrg;
106  *       gint32      mxpkta[36];
107  *       gint16      board_type;
108  *       gint16      board_version;
109  *       gint8       reserved[18];
110  *       } Summary;
111  */
112
113 #define SummarySize (18+22+(4*36)+6+6+6+4+4)
114
115 /*
116  * typedef struct {
117  *       gint16      rid;
118  *       gint16      rlen;
119  *       Summary     s;
120  *       } LA_SummaryRecord;
121  */
122
123 #define LA_SummaryRecordSize (SummarySize + 4)
124
125 /* LANalyzer board types (which indicate the type of network on which
126    the capture was done). */
127 #define BOARD_325               226     /* LANalyzer 325 (Ethernet) */
128 #define BOARD_325TR             227     /* LANalyzer 325TR (Token-ring) */
129
130
131 /*
132  * typedef struct {
133  *       gint16      rid;
134  *       gint16      rlen;
135  *       gint16      seqno;
136  *       gint32      totpktf;
137  *       } LA_SubfileSummaryRecord;
138  */
139
140 #define LA_SubfileSummaryRecordSize 10
141
142
143 #define LA_IndexSize 500
144
145 /*
146  * typedef struct {
147  *       gint16      rid;
148  *       gint16      rlen;
149  *       gint16      idxsp;                    = LA_IndexSize
150  *       gint16      idxct;
151  *       gint8       idxgranu;
152  *       gint8       idxvd;
153  *       gint32      trcidx[LA_IndexSize + 2]; +2 undocumented but used by La 2.2
154  *       } LA_IndexRecord;
155  */
156
157 #define LA_IndexRecordSize (10 + 4 * (LA_IndexSize + 2))
158
159
160 /*
161  * typedef struct {
162  *       guint16     rx_channels;
163  *       guint16     rx_errors;
164  *       gint16      rx_frm_len;
165  *       gint16      rx_frm_sln;
166  *       TimeStamp   rx_time;
167  *       guint32     pktno;
168  *       gint16      prvlen;
169  *       gint16      offset;
170  *       gint16      tx_errs;
171  *       gint16      rx_filters;
172  *       gint8       unused[2];
173  *       gint16      hwcolls;
174  *       gint16      hwcollschans;
175  *       Packetdata ....;
176  *       } LA_PacketRecord;
177  */
178
179 #define LA_PacketRecordSize 32
180
181 typedef struct {
182       gboolean        init;
183       struct timeval  start;
184       guint32         pkts;
185       int             encap;
186       int             lastlen;
187       } LA_TmpInfo;
188
189 static const guint8 LA_HeaderRegularFake[] = {
190 0x01,0x10,0x4c,0x00,0x01,0x05,0x54,0x72,0x61,0x63,0x65,0x20,0x44,0x69,0x73,0x70,
191 0x6c,0x61,0x79,0x20,0x54,0x72,0x61,0x63,0x65,0x20,0x46,0x69,0x6c,0x65,0x00,0x00,
192 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
193 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
194 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
195       };
196
197 static const guint8 LA_RxChannelNameFake[] = {
198 0x06,0x10,0x80,0x00,0x43,0x68,0x61,0x6e ,0x6e,0x65,0x6c,0x31,0x00,0x43,0x68,0x61,
199 0x6e,0x6e,0x65,0x6c,0x32,0x00,0x43,0x68 ,0x61,0x6e,0x6e,0x65,0x6c,0x33,0x00,0x43,
200 0x68,0x61,0x6e,0x6e,0x65,0x6c,0x34,0x00 ,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x35,
201 0x00,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c ,0x36,0x00,0x43,0x68,0x61,0x6e,0x6e,0x65,
202 0x6c,0x37,0x00,0x43,0x68,0x61,0x6e,0x6e ,0x65,0x6c,0x38,0x00,0x00,0x00,0x00,0x00,
203 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
204 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
205 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
206 0x00,0x00,0x00,0x00
207       };
208
209 static const guint8 LA_TxChannelNameFake[] = {
210                     0x0b,0x10,0x36,0x00 ,0x54,0x72,0x61,0x6e,0x73,0x31,0x00,0x00,
211 0x00,0x54,0x72,0x61,0x6e,0x73,0x32,0x00 ,0x00,0x00,0x54,0x72,0x61,0x6e,0x73,0x33,
212 0x00,0x00,0x00,0x54,0x72,0x61,0x6e,0x73 ,0x34,0x00,0x00,0x00,0x54,0x72,0x61,0x6e,
213 0x73,0x35,0x00,0x00,0x00,0x54,0x72,0x61 ,0x6e,0x73,0x36,0x00,0x00,0x00
214       };
215
216 static const guint8 LA_RxTemplateNameFake[] = {
217                                                                        0x35,0x10,
218 0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
219 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
220 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
221 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
222 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
223 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
224 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
225 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
226 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
227 0x00,0x00
228       };
229
230 static const guint8 LA_TxTemplateNameFake[] = {
231           0x36,0x10,0x36,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
232 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
233 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
234 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00
235       };
236
237 static const guint8 LA_DisplayOptionsFake[] = {
238                                                              0x0a,0x10,0x0a,0x01,
239 0x00,0x00,0x01,0x00,0x01,0x02,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
240 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
241 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
242 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
243 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
244 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
245 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
246 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
247 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
248 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
249 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
250 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
251 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
252 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
253 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
254 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
255 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00
256       };
257
258 static const guint8 LA_CyclicInformationFake[] = {
259                                                    0x09,0x10,0x1a,0x00,0x00,0x00,
260 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
261 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
262       };
263
264 static const guint8 z64[64] = {
265 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
266 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
267 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
268 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
269       };
270
271 typedef struct {
272         time_t  start;
273 } lanalyzer_t;
274
275 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
276     gint64 *data_offset);
277 static gboolean lanalyzer_seek_read(wtap *wth, gint64 seek_off,
278     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
279 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err);
280
281 int lanalyzer_open(wtap *wth, int *err, gchar **err_info)
282 {
283         int bytes_read;
284         LA_RecordHeader rec_header;
285         char header_fixed[2];
286         char *comment;
287         char summary[210];
288         guint16 board_type, mxslc;
289         guint16 record_type, record_length;
290         guint8 cr_day, cr_month;
291         guint16 cr_year;
292         struct tm tm;
293         lanalyzer_t *lanalyzer;
294
295         errno = WTAP_ERR_CANT_READ;
296         bytes_read = file_read(&rec_header, LA_RecordHeaderSize, wth->fh);
297         if (bytes_read != LA_RecordHeaderSize) {
298                 *err = file_error(wth->fh, err_info);
299                 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
300                         return -1;
301                 return 0;
302         }
303         record_type = pletoh16(rec_header.record_type);
304         record_length = pletoh16(rec_header.record_length); /* make sure to do this for while() loop */
305
306         if (record_type != RT_HeaderRegular && record_type != RT_HeaderCyclic) {
307                 return 0;
308         }
309
310         /* Read the major and minor version numbers */
311         if (record_length < 2) {
312                 /*
313                  * Not enough room for the major and minor version numbers.
314                  * Just treat that as a "not a LANalyzer file" indication.
315                  */
316                 return 0;
317         }
318         bytes_read = file_read(&header_fixed, sizeof header_fixed, wth->fh);
319         if (bytes_read != sizeof header_fixed) {
320                 *err = file_error(wth->fh, err_info);
321                 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
322                         return -1;
323                 return 0;
324         }
325         record_length -= sizeof header_fixed;
326
327         if (record_length != 0) {
328                 /* Read the rest of the record as a comment. */
329                 comment = (char *)g_malloc(record_length + 1);
330                 bytes_read = file_read(comment, record_length, wth->fh);
331                 if (bytes_read != record_length) {
332                         *err = file_error(wth->fh, err_info);
333                         if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
334                                 return -1;
335                         return 0;
336                 }
337                 comment[record_length] = '\0';
338                 wth->shb_hdr.opt_comment = comment;
339         }
340
341         /* If we made it this far, then the file is a LANAlyzer file.
342          * Let's get some info from it. Note that we get wth->snapshot_length
343          * from a record later in the file. */
344         wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_LANALYZER;
345         lanalyzer = (lanalyzer_t *)g_malloc(sizeof(lanalyzer_t));
346         wth->priv = (void *)lanalyzer;
347         wth->subtype_read = lanalyzer_read;
348         wth->subtype_seek_read = lanalyzer_seek_read;
349         wth->snapshot_length = 0;
350         wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
351
352         /* Read records until we find the start of packets */
353         while (1) {
354                 errno = WTAP_ERR_CANT_READ;
355                 bytes_read = file_read(&rec_header, LA_RecordHeaderSize, wth->fh);
356                 if (bytes_read != LA_RecordHeaderSize) {
357                         *err = file_error(wth->fh, err_info);
358                         if (*err == 0)
359                                 *err = WTAP_ERR_SHORT_READ;
360                         return -1;
361                 }
362
363                 record_type = pletoh16(rec_header.record_type);
364                 record_length = pletoh16(rec_header.record_length);
365
366                 /*g_message("Record 0x%04X Length %d", record_type, record_length);*/
367                 switch (record_type) {
368                         /* Trace Summary Record */
369                         case RT_Summary:
370                                 errno = WTAP_ERR_CANT_READ;
371                                 bytes_read = file_read(summary, sizeof summary,
372                                     wth->fh);
373                                 if (bytes_read != sizeof summary) {
374                                         *err = file_error(wth->fh, err_info);
375                                         if (*err == 0)
376                                                 *err = WTAP_ERR_SHORT_READ;
377                                         return -1;
378                                 }
379
380                                 /* Assume that the date of the creation of the trace file
381                                  * is the same date of the trace. Lanalyzer doesn't
382                                  * store the creation date/time of the trace, but only of
383                                  * the file. Unless you traced at 11:55 PM and saved at 00:05
384                                  * AM, the assumption that trace.date == file.date is true.
385                                  */
386                                 cr_day = summary[0];
387                                 cr_month = summary[1];
388                                 cr_year = pletoh16(&summary[2]);
389                                 /*g_message("Day %d Month %d Year %d (%04X)", cr_day, cr_month,
390                                                 cr_year, cr_year);*/
391
392                                 /* Get capture start time. I learned how to do
393                                  * this from Guy's code in ngsniffer.c
394                                  */
395                                 tm.tm_year = cr_year - 1900;
396                                 tm.tm_mon = cr_month - 1;
397                                 tm.tm_mday = cr_day;
398                                 tm.tm_hour = 0;
399                                 tm.tm_min = 0;
400                                 tm.tm_sec = 0;
401                                 tm.tm_isdst = -1;
402                                 lanalyzer->start = mktime(&tm);
403                                 /*g_message("Day %d Month %d Year %d", tm.tm_mday,
404                                                 tm.tm_mon, tm.tm_year);*/
405                                 mxslc = pletoh16(&summary[30]);
406                                 wth->snapshot_length = mxslc;
407
408                                 board_type = pletoh16(&summary[188]);
409                                 switch (board_type) {
410                                         case BOARD_325:
411                                                 wth->file_encap = WTAP_ENCAP_ETHERNET;
412                                                 break;
413                                         case BOARD_325TR:
414                                                 wth->file_encap = WTAP_ENCAP_TOKEN_RING;
415                                                 break;
416                                         default:
417                                                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
418                                                 *err_info = g_strdup_printf("lanalyzer: board type %u unknown",
419                                                     board_type);
420                                                 return -1;
421                                 }
422                                 break;
423
424                         /* Trace Packet Data Record */
425                         case RT_PacketData:
426                                 /* Go back header number of bytes so that lanalyzer_read
427                                  * can read this header */
428                                 if (file_seek(wth->fh, -LA_RecordHeaderSize, SEEK_CUR, err) == -1) {
429                                         return -1;
430                                 }
431                                 return 1;
432
433                         default:
434                                 if (file_seek(wth->fh, record_length, SEEK_CUR, err) == -1) {
435                                         return -1;
436                                 }
437                                 break;
438                 }
439         }
440 }
441
442 #define DESCRIPTOR_LEN  32
443
444 static gboolean lanalyzer_read_trace_record(wtap *wth, FILE_T fh,
445     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
446 {
447         int             bytes_read;
448         char            LE_record_type[2];
449         char            LE_record_length[2];
450         guint16         record_type, record_length;
451         int             record_data_size;
452         int             packet_size;
453         gchar           descriptor[DESCRIPTOR_LEN];
454         lanalyzer_t     *lanalyzer;
455         guint16         time_low, time_med, time_high, true_size;
456         guint64         t;
457         time_t          tsecs;
458
459         /* read the record type and length. */
460         errno = WTAP_ERR_CANT_READ;
461         bytes_read = file_read(LE_record_type, 2, fh);
462         if (bytes_read != 2) {
463                 *err = file_error(fh, err_info);
464                 if (*err == 0 && bytes_read != 0) {
465                         *err = WTAP_ERR_SHORT_READ;
466                 }
467                 return FALSE;
468         }
469         bytes_read = file_read(LE_record_length, 2, fh);
470         if (bytes_read != 2) {
471                 *err = file_error(fh, err_info);
472                 if (*err == 0)
473                         *err = WTAP_ERR_SHORT_READ;
474                 return FALSE;
475         }
476
477         record_type = pletoh16(LE_record_type);
478         record_length = pletoh16(LE_record_length);
479
480         /* Only Trace Packet Data Records should occur now that we're in
481          * the middle of reading packets.  If any other record type exists
482          * after a Trace Packet Data Record, mark it as an error. */
483         if (record_type != RT_PacketData) {
484                 *err = WTAP_ERR_BAD_FILE;
485                 *err_info = g_strdup_printf("lanalyzer: record type %u seen after trace summary record",
486                     record_type);
487                 return FALSE;
488         }
489
490         if (record_length < DESCRIPTOR_LEN) {
491                 /*
492                  * Uh-oh, the record isn't big enough to even have a
493                  * descriptor.
494                  */
495                 *err = WTAP_ERR_BAD_FILE;
496                 *err_info = g_strdup_printf("lanalyzer: file has a %u-byte record, too small to have even a packet descriptor",
497                     record_length);
498                 return FALSE;
499         }
500         record_data_size = record_length - DESCRIPTOR_LEN;
501
502         /* Read the descriptor data */
503         errno = WTAP_ERR_CANT_READ;
504         bytes_read = file_read(descriptor, DESCRIPTOR_LEN, fh);
505         if (bytes_read != DESCRIPTOR_LEN) {
506                 *err = file_error(fh, err_info);
507                 if (*err == 0)
508                         *err = WTAP_ERR_SHORT_READ;
509                 return FALSE;
510         }
511
512         true_size = pletoh16(&descriptor[4]);
513         packet_size = pletoh16(&descriptor[6]);
514
515         /*
516          * OK, is the frame data size greater than than what's left of the
517          * record?
518          */
519         if (packet_size > record_data_size) {
520                 /*
521                  * Yes - treat this as an error.
522                  */
523                 *err = WTAP_ERR_BAD_FILE;
524                 *err_info = g_strdup("lanalyzer: Record length is less than packet size");
525                 return FALSE;
526         }
527
528         phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
529
530         time_low = pletoh16(&descriptor[8]);
531         time_med = pletoh16(&descriptor[10]);
532         time_high = pletoh16(&descriptor[12]);
533         t = (((guint64)time_low) << 0) + (((guint64)time_med) << 16) +
534             (((guint64)time_high) << 32);
535         tsecs = (time_t) (t/2000000);
536         lanalyzer = (lanalyzer_t *)wth->priv;
537         phdr->ts.secs = tsecs + lanalyzer->start;
538         phdr->ts.nsecs = ((guint32) (t - tsecs*2000000)) * 500;
539
540         if (true_size - 4 >= packet_size) {
541                 /*
542                  * It appears that the "true size" includes the FCS;
543                  * make it reflect the non-FCS size (the "packet size"
544                  * appears never to include the FCS, even if no slicing
545                  * is done).
546                  */
547                 true_size -= 4;
548         }
549         phdr->len = true_size;
550         phdr->caplen = packet_size;
551
552         switch (wth->file_encap) {
553
554         case WTAP_ENCAP_ETHERNET:
555                 /* We assume there's no FCS in this frame. */
556                 phdr->pseudo_header.eth.fcs_len = 0;
557                 break;
558         }
559
560         /* Read the packet data */
561         return wtap_read_packet_bytes(fh, buf, packet_size, err, err_info);
562 }
563
564 /* Read the next packet */
565 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
566     gint64 *data_offset)
567 {
568         *data_offset = file_tell(wth->fh);
569
570         /* Read the record  */
571         return lanalyzer_read_trace_record(wth, wth->fh, &wth->phdr,
572             wth->frame_buffer, err, err_info);
573 }
574
575 static gboolean lanalyzer_seek_read(wtap *wth, gint64 seek_off,
576     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
577 {
578         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
579                 return FALSE;
580
581         /* Read the record  */
582         if (!lanalyzer_read_trace_record(wth, wth->random_fh, phdr, buf,
583             err, err_info)) {
584                 if (*err == 0)
585                         *err = WTAP_ERR_SHORT_READ;
586                 return FALSE;
587         }
588         return TRUE;
589 }
590
591 /*---------------------------------------------------
592  * Returns TRUE on success, FALSE on error
593  * Write "cnt" bytes of zero with error control
594  *---------------------------------------------------*/
595 static gboolean s0write(wtap_dumper *wdh, size_t cnt, int *err)
596 {
597         size_t snack;
598
599         while (cnt) {
600                 snack = cnt > 64 ? 64 : cnt;
601
602                 if (!wtap_dump_file_write(wdh, z64, snack, err))
603                         return FALSE;
604                 cnt -= snack;
605         }
606         return TRUE; /* ok */
607 }
608
609 /*---------------------------------------------------
610  * Returns TRUE on success, FALSE on error
611  * Write an 8-bit value with error control
612  *---------------------------------------------------*/
613 static gboolean s8write(wtap_dumper *wdh, const guint8 s8, int *err)
614 {
615         return wtap_dump_file_write(wdh, &s8, 1, err);
616 }
617 /*---------------------------------------------------
618  * Returns TRUE on success, FALSE on error
619  * Write a 16-bit value with error control
620  *---------------------------------------------------*/
621 static gboolean s16write(wtap_dumper *wdh, const guint16 s16, int *err)
622 {
623         return wtap_dump_file_write(wdh, &s16, 2, err);
624 }
625 /*---------------------------------------------------
626  * Returns TRUE on success, FALSE on error
627  * Write a 32-bit value with error control
628  *---------------------------------------------------*/
629 static gboolean s32write(wtap_dumper *wdh, const guint32 s32, int *err)
630 {
631         return wtap_dump_file_write(wdh, &s32, 4, err);
632 }
633 /*---------------------------------------------------
634  *
635  * calculates C.c = A.a - B.b
636  *---------------------------------------------------*/
637 static void my_timersub(const struct timeval *a,
638                         const struct timeval *b,
639                               struct timeval *c)
640 {
641       gint32 usec = (gint32)a->tv_usec;
642
643       c->tv_sec = a->tv_sec - b->tv_sec;
644       if (b->tv_usec > usec) {
645            c->tv_sec--;
646            usec += 1000000;
647            }
648       c->tv_usec = usec - b->tv_usec;
649 }
650 /*---------------------------------------------------
651  * Write a record for a packet to a dump file.
652  * Returns TRUE on success, FALSE on failure.
653  *---------------------------------------------------*/
654 static gboolean lanalyzer_dump(wtap_dumper *wdh,
655         const struct wtap_pkthdr *phdr,
656         const guint8 *pd, int *err)
657 {
658       double x;
659       int    i;
660       int    len;
661       struct timeval tv;
662
663       LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->priv);
664       struct timeval td;
665       int    thisSize = phdr->caplen + LA_PacketRecordSize + LA_RecordHeaderSize;
666
667       if (wdh->bytes_dumped + thisSize > LA_ProFileLimit) {
668             /* printf(" LA_ProFileLimit reached\n");     */
669             *err = EFBIG;
670             return FALSE; /* and don't forget the header */
671             }
672
673       len = phdr->caplen + (phdr->caplen ? LA_PacketRecordSize : 0);
674
675       /* len goes into a 16-bit field, so there's a hard limit of 65535. */
676       if (len > 65535) {
677             *err = WTAP_ERR_PACKET_TOO_LARGE;
678             return FALSE;
679       }
680
681       if (!s16write(wdh, GUINT16_TO_LE(0x1005), err))
682             return FALSE;
683       if (!s16write(wdh, GUINT16_TO_LE(len), err))
684             return FALSE;
685
686       tv.tv_sec  = (long int) phdr->ts.secs;
687       tv.tv_usec = phdr->ts.nsecs / 1000;
688
689       if (!itmp->init) {
690             /* collect some information for the
691              * finally written header
692              */
693                     /* XXX - this conversion could probably improved, if the start uses ns */
694             itmp->start   = tv;
695             itmp->pkts    = 0;
696             itmp->init    = TRUE;
697             itmp->encap   = wdh->encap;
698             itmp->lastlen = 0;
699             }
700
701       my_timersub(&(tv),&(itmp->start),&td);
702
703       x   = (double) td.tv_usec;
704       x  += (double) td.tv_sec * 1000000;
705       x  *= 2;
706
707       if (!s16write(wdh, GUINT16_TO_LE(0x0001), err))             /* pr.rx_channels */
708             return FALSE;
709       if (!s16write(wdh, GUINT16_TO_LE(0x0008), err))             /* pr.rx_errors   */
710             return FALSE;
711       if (!s16write(wdh, GUINT16_TO_LE(phdr->len + 4), err))      /* pr.rx_frm_len  */
712             return FALSE;
713       if (!s16write(wdh, GUINT16_TO_LE(phdr->caplen), err))       /* pr.rx_frm_sln  */
714             return FALSE;
715
716       for (i = 0; i < 3; i++) {
717             if (!s16write(wdh, GUINT16_TO_LE((guint16) x), err))  /* pr.rx_time[i]  */
718                   return FALSE;
719             x /= 0xffff;
720       }
721
722       if (!s32write(wdh, GUINT32_TO_LE(++itmp->pkts), err))       /* pr.pktno      */
723             return FALSE;
724       if (!s16write(wdh, GUINT16_TO_LE(itmp->lastlen), err))      /* pr.prlen      */
725             return FALSE;
726       itmp->lastlen = len;
727
728       if (!s0write(wdh, 12, err))
729             return FALSE;
730
731       if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
732             return FALSE;
733
734       wdh->bytes_dumped += thisSize;
735
736       return TRUE;
737 }
738
739 /*---------------------------------------------------
740  * Returns 0 if we could write the specified encapsulation type,
741  * an error indication otherwise.
742  *---------------------------------------------------*/
743 int lanalyzer_dump_can_write_encap(int encap)
744 {
745       /* Per-packet encapsulations aren't supported. */
746       if (encap == WTAP_ENCAP_PER_PACKET)
747                   return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
748
749       if ( encap != WTAP_ENCAP_ETHERNET
750         && encap != WTAP_ENCAP_TOKEN_RING )
751                   return WTAP_ERR_UNSUPPORTED_ENCAP;
752       /*
753        * printf("lanalyzer_dump_can_write_encap(%d)\n",encap);
754        */
755       return 0;
756 }
757
758 /*---------------------------------------------------
759  * Returns TRUE on success, FALSE on failure; sets "*err" to an
760  * error code on failure
761  *---------------------------------------------------*/
762 gboolean lanalyzer_dump_open(wtap_dumper *wdh, int *err)
763 {
764       int   jump;
765       void  *tmp;
766
767       tmp = g_malloc(sizeof(LA_TmpInfo));
768       if (!tmp) {
769               *err = errno;
770               return FALSE;
771             }
772
773       ((LA_TmpInfo*)tmp)->init = FALSE;
774       wdh->priv          = tmp;
775       wdh->subtype_write = lanalyzer_dump;
776       wdh->subtype_close = lanalyzer_dump_close;
777
778       /* Some of the fields in the file header aren't known yet so
779        just skip over it for now.  It will be created after all
780        of the packets have been written. */
781
782       jump = sizeof (LA_HeaderRegularFake)
783            + sizeof (LA_RxChannelNameFake)
784            + sizeof (LA_TxChannelNameFake)
785            + sizeof (LA_RxTemplateNameFake)
786            + sizeof (LA_TxTemplateNameFake)
787            + sizeof (LA_DisplayOptionsFake)
788            + LA_SummaryRecordSize
789            + LA_SubfileSummaryRecordSize
790            + sizeof (LA_CyclicInformationFake)
791            + LA_IndexRecordSize;
792
793       if (wtap_dump_file_seek(wdh, jump, SEEK_SET, err) == -1)
794               return FALSE;
795
796       wdh->bytes_dumped = jump;
797       return TRUE;
798 }
799
800 /*---------------------------------------------------
801  *
802  *---------------------------------------------------*/
803 static gboolean lanalyzer_dump_header(wtap_dumper *wdh, int *err)
804 {
805       LA_TmpInfo *itmp   = (LA_TmpInfo*)(wdh->priv);
806       guint16 board_type = itmp->encap == WTAP_ENCAP_TOKEN_RING
807                               ? BOARD_325TR     /* LANalyzer Board Type */
808                               : BOARD_325;      /* LANalyzer Board Type */
809       time_t secs;
810       struct tm *fT;
811
812       /* The secs variable is needed to work around 32/64-bit time_t issues.
813          itmp->start is a timeval struct, which declares its tv_sec field
814          (itmp->start.tv_sec) as a long (typically 32 bits). time_t can be 32
815          or 64 bits, depending on the platform. Invoking as follows could
816          pass a pointer to a 32-bit long where a pointer to a 64-bit time_t
817          is expected: localtime((time_t*) &(itmp->start.tv_sec)) */
818       secs = itmp->start.tv_sec;
819       fT = localtime(&secs);
820       if (fT == NULL)
821             return FALSE;
822
823       if (wtap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1)
824             return FALSE;
825
826       if (!wtap_dump_file_write(wdh, &LA_HeaderRegularFake,
827                                 sizeof LA_HeaderRegularFake, err))
828                 return FALSE;
829       if (!wtap_dump_file_write(wdh, &LA_RxChannelNameFake,
830                                 sizeof LA_RxChannelNameFake, err))
831                 return FALSE;
832       if (!wtap_dump_file_write(wdh, &LA_TxChannelNameFake,
833                                 sizeof LA_TxChannelNameFake, err))
834                 return FALSE;
835       if (!wtap_dump_file_write(wdh, &LA_RxTemplateNameFake,
836                                 sizeof LA_RxTemplateNameFake, err))
837                 return FALSE;
838       if (!wtap_dump_file_write(wdh, &LA_TxTemplateNameFake,
839                                 sizeof LA_TxTemplateNameFake, err))
840                 return FALSE;
841       if (!wtap_dump_file_write(wdh, &LA_DisplayOptionsFake,
842                                 sizeof LA_DisplayOptionsFake, err))
843                 return FALSE;
844       /*-----------------------------------------------------------------*/
845       if (!s16write(wdh, GUINT16_TO_LE(RT_Summary), err))         /* rid */
846             return FALSE;
847       if (!s16write(wdh, GUINT16_TO_LE(SummarySize), err))        /* rlen */
848             return FALSE;
849       if (!s8write(wdh, (guint8) fT->tm_mday, err))        /* s.datcre.day */
850             return FALSE;
851       if (!s8write(wdh, (guint8) (fT->tm_mon+1), err))     /* s.datcre.mon */
852             return FALSE;
853       if (!s16write(wdh, GUINT16_TO_LE(fT->tm_year + 1900), err)) /* s.datcre.year */
854             return FALSE;
855       if (!s8write(wdh, (guint8) fT->tm_mday, err))        /* s.datclo.day */
856             return FALSE;
857       if (!s8write(wdh, (guint8) (fT->tm_mon+1), err))     /* s.datclo.mon */
858             return FALSE;
859       if (!s16write(wdh, GUINT16_TO_LE(fT->tm_year + 1900), err)) /* s.datclo.year */
860             return FALSE;
861       if (!s8write(wdh, (guint8) fT->tm_sec, err))         /* s.timeopn.second */
862             return FALSE;
863       if (!s8write(wdh, (guint8) fT->tm_min, err))         /* s.timeopn.minute */
864             return FALSE;
865       if (!s8write(wdh, (guint8) fT->tm_hour, err))        /* s.timeopn.hour */
866             return FALSE;
867       if (!s8write(wdh, (guint8) fT->tm_mday, err))        /* s.timeopn.mday */
868             return FALSE;
869       if (!s0write(wdh, 2, err))
870             return FALSE;
871       if (!s8write(wdh, (guint8) fT->tm_sec, err))         /* s.timeclo.second */
872             return FALSE;
873       if (!s8write(wdh, (guint8) fT->tm_min, err))         /* s.timeclo.minute */
874             return FALSE;
875       if (!s8write(wdh, (guint8) fT->tm_hour, err))        /* s.timeclo.hour */
876             return FALSE;
877       if (!s8write(wdh, (guint8) fT->tm_mday, err))        /* s.timeclo.mday */
878             return FALSE;
879       if (!s0write(wdh, 2, err))
880             return FALSE;
881       if (!s0write(wdh, 6, err))                           /* EAddr  == 0      */
882             return FALSE;
883       if (!s16write(wdh, GUINT16_TO_LE(1), err))                  /* s.mxseqno */
884             return FALSE;
885       if (!s16write(wdh, GUINT16_TO_LE(0), err))                  /* s.slcoffo */
886             return FALSE;
887       if (!s16write(wdh, GUINT16_TO_LE(1514), err))               /* s.mxslc */
888             return FALSE;
889       if (!s32write(wdh, GUINT32_TO_LE(itmp->pkts), err))         /* s.totpktt */
890             return FALSE;
891       /*
892        * statrg == 0; ? -1
893        * stptrg == 0; ? -1
894        * s.mxpkta[0]=0
895        */
896       if (!s0write(wdh, 12, err))
897             return FALSE;
898       if (!s32write(wdh, GUINT32_TO_LE(itmp->pkts), err))         /* sr.s.mxpkta[1]  */
899             return FALSE;
900       if (!s0write(wdh, 34*4, err))                        /* s.mxpkta[2-33]=0  */
901             return FALSE;
902       if (!s16write(wdh, GUINT16_TO_LE(board_type), err))
903             return FALSE;
904       if (!s0write(wdh, 20, err))                             /* board_version == 0 */
905             return FALSE;
906       /*-----------------------------------------------------------------*/
907       if (!s16write(wdh, GUINT16_TO_LE(RT_SubfileSummary), err))     /* ssr.rid */
908             return FALSE;
909       if (!s16write(wdh, GUINT16_TO_LE(LA_SubfileSummaryRecordSize-4), err)) /* ssr.rlen */
910             return FALSE;
911       if (!s16write(wdh, GUINT16_TO_LE(1), err))                     /* ssr.seqno */
912             return FALSE;
913       if (!s32write(wdh, GUINT32_TO_LE(itmp->pkts), err))            /* ssr.totpkts */
914             return FALSE;
915       /*-----------------------------------------------------------------*/
916       if (!wtap_dump_file_write(wdh, &LA_CyclicInformationFake,
917                                 sizeof LA_CyclicInformationFake, err))
918             return FALSE;
919       /*-----------------------------------------------------------------*/
920       if (!s16write(wdh, GUINT16_TO_LE(RT_Index), err))              /* rid */
921             return FALSE;
922       if (!s16write(wdh, GUINT16_TO_LE(LA_IndexRecordSize -4), err)) /* rlen */
923             return FALSE;
924       if (!s16write(wdh, GUINT16_TO_LE(LA_IndexSize), err))          /* idxsp */
925             return FALSE;
926       if (!s0write(wdh, LA_IndexRecordSize - 6, err))
927             return FALSE;
928
929       return TRUE;
930 }
931
932 /*---------------------------------------------------
933  * Finish writing to a dump file.
934  * Returns TRUE on success, FALSE on failure.
935  *---------------------------------------------------*/
936 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err)
937 {
938       lanalyzer_dump_header(wdh,err);
939       return *err ? FALSE : TRUE;
940 }