Update minimum version requirement for GTK to 2.12.
[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_RECORD;
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                 packet_size = record_length - DESCRIPTOR_LEN;
471         }
472
473         /* Read the descriptor data */
474         errno = WTAP_ERR_CANT_READ;
475         bytes_read = file_read(descriptor, DESCRIPTOR_LEN, wth->fh);
476         if (bytes_read != DESCRIPTOR_LEN) {
477                 *err = file_error(wth->fh, err_info);
478                 if (*err == 0)
479                         *err = WTAP_ERR_SHORT_READ;
480                 return FALSE;
481         }
482         wth->data_offset += DESCRIPTOR_LEN;
483
484         /* Read the packet data */
485         buffer_assure_space(wth->frame_buffer, packet_size);
486         *data_offset = wth->data_offset;
487         errno = WTAP_ERR_CANT_READ;
488         bytes_read = file_read(buffer_start_ptr(wth->frame_buffer),
489                 packet_size, wth->fh);
490
491         if (bytes_read != packet_size) {
492                 *err = file_error(wth->fh, err_info);
493                 if (*err == 0)
494                         *err = WTAP_ERR_SHORT_READ;
495                 return FALSE;
496         }
497         wth->data_offset += packet_size;
498
499         true_size = pletohs(&descriptor[4]);
500         packet_size = pletohs(&descriptor[6]);
501
502         /*
503          * OK, is the frame data size greater than than what's left of the
504          * record?
505          */
506         if (packet_size > record_length - DESCRIPTOR_LEN) {
507                 /*
508                  * Yes - treat this as an error.
509                  */
510                 *err = WTAP_ERR_BAD_RECORD;
511                 *err_info = g_strdup("lanalyzer: Record length is less than packet size");
512                 return FALSE;
513         }
514
515         time_low = pletohs(&descriptor[8]);
516         time_med = pletohs(&descriptor[10]);
517         time_high = pletohs(&descriptor[12]);
518         t = (((guint64)time_low) << 0) + (((guint64)time_med) << 16) +
519             (((guint64)time_high) << 32);
520         tsecs = (time_t) (t/2000000);
521         lanalyzer = (lanalyzer_t *)wth->priv;
522         wth->phdr.ts.secs = tsecs + lanalyzer->start;
523         wth->phdr.ts.nsecs = ((guint32) (t - tsecs*2000000)) * 500;
524
525         if (true_size - 4 >= packet_size) {
526                 /*
527                  * It appears that the "true size" includes the FCS;
528                  * make it reflect the non-FCS size (the "packet size"
529                  * appears never to include the FCS, even if no slicing
530                  * is done).
531                  */
532                 true_size -= 4;
533         }
534         wth->phdr.len = true_size;
535         wth->phdr.caplen = packet_size;
536
537         switch (wth->file_encap) {
538
539         case WTAP_ENCAP_ETHERNET:
540                 /* We assume there's no FCS in this frame. */
541                 wth->pseudo_header.eth.fcs_len = 0;
542                 break;
543         }
544
545         return TRUE;
546 }
547
548 static gboolean lanalyzer_seek_read(wtap *wth, gint64 seek_off,
549     union wtap_pseudo_header *pseudo_header, guint8 *pd, int length,
550     int *err, gchar **err_info)
551 {
552         int bytes_read;
553
554         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
555                 return FALSE;
556
557         /*
558          * Read the packet data.
559          */
560         bytes_read = file_read(pd, length, wth->random_fh);
561         if (bytes_read != length) {
562                 *err = file_error(wth->random_fh, err_info);
563                 if (*err == 0)
564                         *err = WTAP_ERR_SHORT_READ;
565                 return FALSE;
566         }
567
568         switch (wth->file_encap) {
569
570         case WTAP_ENCAP_ETHERNET:
571                 /* We assume there's no FCS in this frame. */
572                 pseudo_header->eth.fcs_len = 0;
573                 break;
574         }
575
576         return TRUE;
577 }
578
579 /*---------------------------------------------------
580  * Returns TRUE on success, FALSE on error
581  * Write "cnt" bytes of zero with error control
582  *---------------------------------------------------*/
583 static gboolean s0write(wtap_dumper *wdh, size_t cnt, int *err)
584 {
585         static const guint8 z64[64];
586         size_t snack;
587
588         while (cnt) {
589                 snack = cnt > 64 ? 64 : cnt;
590
591                 if (!wtap_dump_file_write(wdh, z64, snack, err))
592                         return FALSE;
593                 cnt -= snack;
594         }
595         return TRUE; /* ok */
596 }
597
598 /*---------------------------------------------------
599  * Returns TRUE on success, FALSE on error
600  * Write an 8-bit value with error control
601  *---------------------------------------------------*/
602 static gboolean s8write(wtap_dumper *wdh, const guint8 s8, int *err)
603 {
604         return wtap_dump_file_write(wdh, &s8, 1, err);
605 }
606 /*---------------------------------------------------
607  * Returns TRUE on success, FALSE on error
608  * Write a 16-bit value with error control
609  *---------------------------------------------------*/
610 static gboolean s16write(wtap_dumper *wdh, const guint16 s16, int *err)
611 {
612         return wtap_dump_file_write(wdh, &s16, 2, err);
613 }
614 /*---------------------------------------------------
615  * Returns TRUE on success, FALSE on error
616  * Write a 32-bit value with error control
617  *---------------------------------------------------*/
618 static gboolean s32write(wtap_dumper *wdh, const guint32 s32, int *err)
619 {
620         return wtap_dump_file_write(wdh, &s32, 4, err);
621 }
622 /*---------------------------------------------------
623  *
624  * calculates C.c = A.a - B.b
625  *---------------------------------------------------*/
626 static void my_timersub(const struct timeval *a,
627                         const struct timeval *b,
628                               struct timeval *c)
629 {
630       gint32 usec = a->tv_usec;
631
632       c->tv_sec = a->tv_sec - b->tv_sec;
633       if (b->tv_usec > usec) {
634            c->tv_sec--;
635            usec += 1000000;
636            }
637       c->tv_usec = usec - b->tv_usec;
638 }
639 /*---------------------------------------------------
640  * Write a record for a packet to a dump file.
641  * Returns TRUE on success, FALSE on failure.
642  *---------------------------------------------------*/
643 static gboolean lanalyzer_dump(wtap_dumper *wdh,
644         const struct wtap_pkthdr *phdr,
645         const union wtap_pseudo_header *pseudo_header _U_,
646         const guint8 *pd, int *err)
647 {
648       double x;
649       int    i;
650       int    len;
651           struct timeval tv;
652
653       LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->priv);
654       struct timeval td;
655       int    thisSize = phdr->caplen + LA_PacketRecordSize + LA_RecordHeaderSize;
656
657       if (wdh->bytes_dumped + thisSize > LA_ProFileLimit) {
658             /* printf(" LA_ProFileLimit reached\n");     */
659             *err = EFBIG;
660             return FALSE; /* and don't forget the header */
661             }
662
663       len = phdr->caplen + (phdr->caplen ? LA_PacketRecordSize : 0);
664
665       if (!s16write(wdh, htoles(0x1005), err))
666             return FALSE;
667       if (!s16write(wdh, htoles(len), err))
668             return FALSE;
669
670       tv.tv_sec  = (long int) phdr->ts.secs;
671       tv.tv_usec = phdr->ts.nsecs / 1000;
672
673       if (!itmp->init) {
674             /* collect some information for the
675              * finally written header
676              */
677                     /* XXX - this conversion could probably improved, if the start uses ns */
678             itmp->start   = tv;
679             itmp->pkts    = 0;
680             itmp->init    = TRUE;
681             itmp->encap   = wdh->encap;
682             itmp->lastlen = 0;
683             }
684
685       my_timersub(&(tv),&(itmp->start),&td);
686
687       x   = (double) td.tv_usec;
688       x  += (double) td.tv_sec * 1000000;
689       x  *= 2;
690
691       if (!s16write(wdh, htoles(0x0001), err))             /* pr.rx_channels */
692             return FALSE;
693       if (!s16write(wdh, htoles(0x0008), err))             /* pr.rx_errors   */
694             return FALSE;
695       if (!s16write(wdh, htoles(phdr->len + 4), err))      /* pr.rx_frm_len  */
696             return FALSE;
697       if (!s16write(wdh, htoles(phdr->caplen), err))       /* pr.rx_frm_sln  */
698             return FALSE;
699
700       for (i = 0; i < 3; i++) {
701             if (!s16write(wdh, htoles((guint16) x), err))  /* pr.rx_time[i]  */
702                   return FALSE;
703             x /= 0xffff;
704       }
705
706       if (!s32write(wdh, htolel(++itmp->pkts), err))       /* pr.pktno      */
707             return FALSE;
708       if (!s16write(wdh, htoles(itmp->lastlen), err))      /* pr.prlen      */
709             return FALSE;
710       itmp->lastlen = len;
711
712       if (!s0write(wdh, 12, err))
713             return FALSE;
714
715       if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
716             return FALSE;
717
718       wdh->bytes_dumped += thisSize;
719
720       return TRUE;
721 }
722
723 /*---------------------------------------------------
724  * Returns 0 if we could write the specified encapsulation type,
725  * an error indication otherwise.
726  *---------------------------------------------------*/
727 int lanalyzer_dump_can_write_encap(int encap)
728 {
729       /* Per-packet encapsulations aren't supported. */
730       if (encap == WTAP_ENCAP_PER_PACKET)
731                   return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
732
733       if ( encap != WTAP_ENCAP_ETHERNET
734         && encap != WTAP_ENCAP_TOKEN_RING )
735                   return WTAP_ERR_UNSUPPORTED_ENCAP;
736       /*
737        * printf("lanalyzer_dump_can_write_encap(%d)\n",encap);
738        */
739       return 0;
740 }
741
742 /*---------------------------------------------------
743  * Returns TRUE on success, FALSE on failure; sets "*err" to an
744  * error code on failure
745  *---------------------------------------------------*/
746 gboolean lanalyzer_dump_open(wtap_dumper *wdh, int *err)
747 {
748       int   jump;
749       void  *tmp;
750
751       tmp = g_malloc(sizeof(LA_TmpInfo));
752       if (!tmp) {
753               *err = errno;
754               return FALSE;
755             }
756
757       ((LA_TmpInfo*)tmp)->init = FALSE;
758       wdh->priv          = tmp;
759       wdh->subtype_write = lanalyzer_dump;
760       wdh->subtype_close = lanalyzer_dump_close;
761
762       /* Some of the fields in the file header aren't known yet so
763        just skip over it for now.  It will be created after all
764        of the packets have been written. */
765
766       jump = sizeof (LA_HeaderRegularFake)
767            + sizeof (LA_RxChannelNameFake)
768            + sizeof (LA_TxChannelNameFake)
769            + sizeof (LA_RxTemplateNameFake)
770            + sizeof (LA_TxTemplateNameFake)
771            + sizeof (LA_DisplayOptionsFake)
772            + LA_SummaryRecordSize
773            + LA_SubfileSummaryRecordSize
774            + sizeof (LA_CyclicInformationFake)
775            + LA_IndexRecordSize;
776
777       if (fseek(wdh->fh, jump, SEEK_SET) == -1) {
778               *err = errno;
779               return FALSE;
780             }
781       wdh->bytes_dumped = jump;
782       return TRUE;
783 }
784
785 /*---------------------------------------------------
786  *
787  *---------------------------------------------------*/
788 static gboolean lanalyzer_dump_header(wtap_dumper *wdh, int *err)
789 {
790       LA_TmpInfo *itmp   = (LA_TmpInfo*)(wdh->priv);
791       guint16 board_type = itmp->encap == WTAP_ENCAP_TOKEN_RING
792                               ? BOARD_325TR     /* LANalyzer Board Type */
793                               : BOARD_325;      /* LANalyzer Board Type */
794       time_t secs;
795       struct tm *fT;
796
797       /* The secs variable is needed to work around 32/64-bit time_t issues.
798          itmp->start is a timeval struct, which declares its tv_sec field
799          (itmp->start.tv_sec) as a long (typically 32 bits). time_t can be 32
800          or 64 bits, depending on the platform. Invoking as follows could
801          pass a pointer to a 32-bit long where a pointer to a 64-bit time_t
802          is expected: localtime((time_t*) &(itmp->start.tv_sec)) */
803       secs = itmp->start.tv_sec;
804       fT = localtime(&secs);
805       if (fT == NULL)
806             return FALSE;
807
808       fseek(wdh->fh, 0, SEEK_SET);
809
810       if (!wtap_dump_file_write(wdh, &LA_HeaderRegularFake,
811                                 sizeof LA_HeaderRegularFake, err))
812                 return FALSE;
813       if (!wtap_dump_file_write(wdh, &LA_RxChannelNameFake,
814                                 sizeof LA_RxChannelNameFake, err))
815                 return FALSE;
816       if (!wtap_dump_file_write(wdh, &LA_TxChannelNameFake,
817                                 sizeof LA_TxChannelNameFake, err))
818                 return FALSE;
819       if (!wtap_dump_file_write(wdh, &LA_RxTemplateNameFake,
820                                 sizeof LA_RxTemplateNameFake, err))
821                 return FALSE;
822       if (!wtap_dump_file_write(wdh, &LA_TxTemplateNameFake,
823                                 sizeof LA_TxTemplateNameFake, err))
824                 return FALSE;
825       if (!wtap_dump_file_write(wdh, &LA_DisplayOptionsFake,
826                                 sizeof LA_DisplayOptionsFake, err))
827                 return FALSE;
828       /*-----------------------------------------------------------------*/
829       if (!s16write(wdh, htoles(RT_Summary), err))         /* rid */
830             return FALSE;
831       if (!s16write(wdh, htoles(SummarySize), err))        /* rlen */
832             return FALSE;
833       if (!s8write(wdh, (guint8) fT->tm_mday, err))        /* s.datcre.day */
834             return FALSE;
835       if (!s8write(wdh, (guint8) (fT->tm_mon+1), err))     /* s.datcre.mon */
836             return FALSE;
837       if (!s16write(wdh, htoles(fT->tm_year + 1900), err)) /* s.datcre.year */
838             return FALSE;
839       if (!s8write(wdh, (guint8) fT->tm_mday, err))        /* s.datclo.day */
840             return FALSE;
841       if (!s8write(wdh, (guint8) (fT->tm_mon+1), err))     /* s.datclo.mon */
842             return FALSE;
843       if (!s16write(wdh, htoles(fT->tm_year + 1900), err)) /* s.datclo.year */
844             return FALSE;
845       if (!s8write(wdh, (guint8) fT->tm_sec, err))         /* s.timeopn.second */
846             return FALSE;
847       if (!s8write(wdh, (guint8) fT->tm_min, err))         /* s.timeopn.minute */
848             return FALSE;
849       if (!s8write(wdh, (guint8) fT->tm_hour, err))        /* s.timeopn.hour */
850             return FALSE;
851       if (!s8write(wdh, (guint8) fT->tm_mday, err))        /* s.timeopn.mday */
852             return FALSE;
853       if (!s0write(wdh, 2, err))
854             return FALSE;
855       if (!s8write(wdh, (guint8) fT->tm_sec, err))         /* s.timeclo.second */
856             return FALSE;
857       if (!s8write(wdh, (guint8) fT->tm_min, err))         /* s.timeclo.minute */
858             return FALSE;
859       if (!s8write(wdh, (guint8) fT->tm_hour, err))        /* s.timeclo.hour */
860             return FALSE;
861       if (!s8write(wdh, (guint8) fT->tm_mday, err))        /* s.timeclo.mday */
862             return FALSE;
863       if (!s0write(wdh, 2, err))
864             return FALSE;
865       if (!s0write(wdh, 6, err))                           /* EAddr  == 0      */
866             return FALSE;
867       if (!s16write(wdh, htoles(1), err))                  /* s.mxseqno */
868             return FALSE;
869       if (!s16write(wdh, htoles(0), err))                  /* s.slcoffo */
870             return FALSE;
871       if (!s16write(wdh, htoles(1514), err))               /* s.mxslc */
872             return FALSE;
873       if (!s32write(wdh, htolel(itmp->pkts), err))         /* s.totpktt */
874             return FALSE;
875       /*
876        * statrg == 0; ? -1
877        * stptrg == 0; ? -1
878        * s.mxpkta[0]=0
879        */
880       if (!s0write(wdh, 12, err))
881             return FALSE;
882       if (!s32write(wdh, htolel(itmp->pkts), err))         /* sr.s.mxpkta[1]  */
883             return FALSE;
884       if (!s0write(wdh, 34*4, err))                        /* s.mxpkta[2-33]=0  */
885             return FALSE;
886       if (!s16write(wdh, htoles(board_type), err))
887             return FALSE;
888       if (!s0write(wdh, 20, err))                             /* board_version == 0 */
889             return FALSE;
890       /*-----------------------------------------------------------------*/
891       if (!s16write(wdh, htoles(RT_SubfileSummary), err))     /* ssr.rid */
892             return FALSE;
893       if (!s16write(wdh, htoles(LA_SubfileSummaryRecordSize-4), err)) /* ssr.rlen */
894             return FALSE;
895       if (!s16write(wdh, htoles(1), err))                     /* ssr.seqno */
896             return FALSE;
897       if (!s32write(wdh, htolel(itmp->pkts), err))            /* ssr.totpkts */
898             return FALSE;
899       /*-----------------------------------------------------------------*/
900       if (!wtap_dump_file_write(wdh, &LA_CyclicInformationFake,
901                                 sizeof LA_CyclicInformationFake, err))
902             return FALSE;
903       /*-----------------------------------------------------------------*/
904       if (!s16write(wdh, htoles(RT_Index), err))              /* rid */
905             return FALSE;
906       if (!s16write(wdh, htoles(LA_IndexRecordSize -4), err)) /* rlen */
907             return FALSE;
908       if (!s16write(wdh, htoles(LA_IndexSize), err))          /* idxsp */
909             return FALSE;
910       if (!s0write(wdh, LA_IndexRecordSize - 6, err))
911             return FALSE;
912
913       return TRUE;
914 }
915
916 /*---------------------------------------------------
917  * Finish writing to a dump file.
918  * Returns TRUE on success, FALSE on failure.
919  *---------------------------------------------------*/
920 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err)
921 {
922       lanalyzer_dump_header(wdh,err);
923       return *err ? FALSE : TRUE;
924 }