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