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