For LANalyzer files, make the "File type name" be the file comment.
[metze/wireshark/wip.git] / wiretap / lanalyzer.c
1 /* lanalyzer.c
2  *
3  * $Id$
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 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 header_fixed[2];
282         char *comment;
283         char summary[210];
284         guint16 board_type, mxslc;
285         guint16 record_type, record_length;
286         guint8 cr_day, cr_month;
287         guint16 cr_year;
288         struct tm tm;
289         lanalyzer_t *lanalyzer;
290
291         errno = WTAP_ERR_CANT_READ;
292         bytes_read = file_read(&rec_header, LA_RecordHeaderSize, wth->fh);
293         if (bytes_read != LA_RecordHeaderSize) {
294                 *err = file_error(wth->fh, err_info);
295                 if (*err != 0)
296                         return -1;
297                 return 0;
298         }
299         wth->data_offset += LA_RecordHeaderSize;
300         record_type = pletohs(rec_header.record_type);
301         record_length = pletohs(rec_header.record_length); /* make sure to do this for while() loop */
302
303         if (record_type != RT_HeaderRegular && record_type != RT_HeaderCyclic) {
304                 return 0;
305         }
306
307         /* Read the major and minor version numbers */
308         if (record_length < 2) {
309                 /* Not enough room for the major and minor version numbers. */
310                 *err = WTAP_ERR_BAD_FILE;
311                 *err_info = g_strdup_printf("lanalyzer: trace header record length %u < 2",
312                     record_length);
313                 return -1;
314         }
315         bytes_read = file_read(&header_fixed, sizeof header_fixed, wth->fh);
316         if (bytes_read != sizeof header_fixed) {
317                 *err = file_error(wth->fh, err_info);
318                 if (*err == 0)
319                         *err = WTAP_ERR_SHORT_READ;
320                 return -1;
321         }
322         wth->data_offset += sizeof header_fixed;
323         record_length -= sizeof header_fixed;
324
325         if (record_length != 0) {
326                 /* Read the rest of the record as a comment. */
327                 comment = 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)
332                                 *err = WTAP_ERR_SHORT_READ;
333                         return -1;
334                 }
335                 comment[record_length] = '\0';
336                 wth->data_offset += record_length;
337                 wth->shb_hdr.opt_comment = comment;
338         }
339
340         /* If we made it this far, then the file is a LANAlyzer file.
341          * Let's get some info from it. Note that we get wth->snapshot_length
342          * from a record later in the file. */
343         wth->file_type = WTAP_FILE_LANALYZER;
344         lanalyzer = (lanalyzer_t *)g_malloc(sizeof(lanalyzer_t));;
345         wth->priv = (void *)lanalyzer;
346         wth->subtype_read = lanalyzer_read;
347         wth->subtype_seek_read = lanalyzer_seek_read;
348         wth->snapshot_length = 0;
349         wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
350
351         /* Read records until we find the start of packets */
352         while (1) {
353                 errno = WTAP_ERR_CANT_READ;
354                 bytes_read = file_read(&rec_header, LA_RecordHeaderSize, wth->fh);
355                 if (bytes_read != LA_RecordHeaderSize) {
356                         *err = file_error(wth->fh, err_info);
357                         if (*err != 0) {
358                                 g_free(wth->priv);
359                                 return -1;
360                         }
361                         g_free(wth->priv);
362                         return 0;
363                 }
364                 wth->data_offset += LA_RecordHeaderSize;
365
366                 record_type = pletohs(rec_header.record_type);
367                 record_length = pletohs(rec_header.record_length);
368
369                 /*g_message("Record 0x%04X Length %d", record_type, record_length);*/
370                 switch (record_type) {
371                         /* Trace Summary Record */
372                         case RT_Summary:
373                                 errno = WTAP_ERR_CANT_READ;
374                                 bytes_read = file_read(summary, sizeof summary,
375                                     wth->fh);
376                                 if (bytes_read != sizeof summary) {
377                                         *err = file_error(wth->fh, err_info);
378                                         if (*err != 0) {
379                                                 g_free(wth->priv);
380                                                 return -1;
381                                         }
382                                         g_free(wth->priv);
383                                         return 0;
384                                 }
385                                 wth->data_offset += sizeof summary;
386
387                                 /* Assume that the date of the creation of the trace file
388                                  * is the same date of the trace. Lanalyzer doesn't
389                                  * store the creation date/time of the trace, but only of
390                                  * the file. Unless you traced at 11:55 PM and saved at 00:05
391                                  * AM, the assumption that trace.date == file.date is true.
392                                  */
393                                 cr_day = summary[0];
394                                 cr_month = summary[1];
395                                 cr_year = pletohs(&summary[2]);
396                                 /*g_message("Day %d Month %d Year %d (%04X)", cr_day, cr_month,
397                                                 cr_year, cr_year);*/
398
399                                 /* Get capture start time. I learned how to do
400                                  * this from Guy's code in ngsniffer.c
401                                  */
402                                 tm.tm_year = cr_year - 1900;
403                                 tm.tm_mon = cr_month - 1;
404                                 tm.tm_mday = cr_day;
405                                 tm.tm_hour = 0;
406                                 tm.tm_min = 0;
407                                 tm.tm_sec = 0;
408                                 tm.tm_isdst = -1;
409                                 lanalyzer->start = mktime(&tm);
410                                 /*g_message("Day %d Month %d Year %d", tm.tm_mday,
411                                                 tm.tm_mon, tm.tm_year);*/
412                                 mxslc = pletohs(&summary[30]);
413                                 wth->snapshot_length = mxslc;
414
415                                 board_type = pletohs(&summary[188]);
416                                 switch (board_type) {
417                                         case BOARD_325:
418                                                 wth->file_encap = WTAP_ENCAP_ETHERNET;
419                                                 break;
420                                         case BOARD_325TR:
421                                                 wth->file_encap = WTAP_ENCAP_TOKEN_RING;
422                                                 break;
423                                         default:
424                                                 g_free(wth->priv);
425                                                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
426                                                 *err_info = g_strdup_printf("lanalyzer: board type %u unknown",
427                                                     board_type);
428                                                 return -1;
429                                 }
430                                 break;
431
432                         /* Trace Packet Data Record */
433                         case RT_PacketData:
434                                 /* Go back header number of bytes so that lanalyzer_read
435                                  * can read this header */
436                                 if (file_seek(wth->fh, -LA_RecordHeaderSize, SEEK_CUR, err) == -1) {
437                                         g_free(wth->priv);
438                                         return -1;
439                                 }
440                                 wth->data_offset -= LA_RecordHeaderSize;
441                                 return 1;
442
443                         default:
444                                 if (file_seek(wth->fh, record_length, SEEK_CUR, err) == -1) {
445                                         g_free(wth->priv);
446                                         return -1;
447                                 }
448                                 wth->data_offset += record_length;
449                                 break;
450                 }
451         }
452 }
453
454 #define DESCRIPTOR_LEN  32
455
456 /* Read the next packet */
457 static gboolean lanalyzer_read(wtap *wth, int *err, gchar **err_info,
458     gint64 *data_offset)
459 {
460         int             packet_size = 0;
461         int             bytes_read;
462         char            LE_record_type[2];
463         char            LE_record_length[2];
464         guint16         record_type, record_length;
465         gchar           descriptor[DESCRIPTOR_LEN];
466         guint16         time_low, time_med, time_high, true_size;
467         guint64         t;
468         time_t          tsecs;
469         lanalyzer_t     *lanalyzer;
470
471         /* read the record type and length. */
472         errno = WTAP_ERR_CANT_READ;
473         bytes_read = file_read(LE_record_type, 2, wth->fh);
474         if (bytes_read != 2) {
475                 *err = file_error(wth->fh, err_info);
476                 if (*err == 0 && bytes_read != 0) {
477                         *err = WTAP_ERR_SHORT_READ;
478                 }
479                 return FALSE;
480         }
481         wth->data_offset += 2;
482         bytes_read = file_read(LE_record_length, 2, wth->fh);
483         if (bytes_read != 2) {
484                 *err = file_error(wth->fh, err_info);
485                 if (*err == 0)
486                         *err = WTAP_ERR_SHORT_READ;
487                 return FALSE;
488         }
489         wth->data_offset += 2;
490
491         record_type = pletohs(LE_record_type);
492         record_length = pletohs(LE_record_length);
493
494         /* Only Trace Packet Data Records should occur now that we're in
495          * the middle of reading packets.  If any other record type exists
496          * after a Trace Packet Data Record, mark it as an error. */
497         if (record_type != RT_PacketData) {
498                 *err = WTAP_ERR_BAD_FILE;
499                 *err_info = g_strdup_printf("lanalyzer: record type %u seen after trace summary record",
500                     record_type);
501                 return FALSE;
502         }
503         else {
504                 if (record_length < DESCRIPTOR_LEN) {
505                         /*
506                          * Uh-oh, the record isn't big enough to even have a
507                          * descriptor.
508                          */
509                         *err = WTAP_ERR_BAD_FILE;
510                         *err_info = g_strdup_printf("lanalyzer: file has a %u-byte record, too small to have even a packet descriptor",
511                             record_length);
512                         return FALSE;
513                 }
514                 packet_size = record_length - DESCRIPTOR_LEN;
515         }
516
517         /* Read the descriptor data */
518         errno = WTAP_ERR_CANT_READ;
519         bytes_read = file_read(descriptor, DESCRIPTOR_LEN, wth->fh);
520         if (bytes_read != DESCRIPTOR_LEN) {
521                 *err = file_error(wth->fh, err_info);
522                 if (*err == 0)
523                         *err = WTAP_ERR_SHORT_READ;
524                 return FALSE;
525         }
526         wth->data_offset += DESCRIPTOR_LEN;
527
528         /* Read the packet data */
529         buffer_assure_space(wth->frame_buffer, packet_size);
530         *data_offset = wth->data_offset;
531         errno = WTAP_ERR_CANT_READ;
532         bytes_read = file_read(buffer_start_ptr(wth->frame_buffer),
533                 packet_size, wth->fh);
534
535         if (bytes_read != packet_size) {
536                 *err = file_error(wth->fh, err_info);
537                 if (*err == 0)
538                         *err = WTAP_ERR_SHORT_READ;
539                 return FALSE;
540         }
541         wth->data_offset += packet_size;
542
543         true_size = pletohs(&descriptor[4]);
544         packet_size = pletohs(&descriptor[6]);
545
546         /*
547          * OK, is the frame data size greater than than what's left of the
548          * record?
549          */
550         if (packet_size > record_length - DESCRIPTOR_LEN) {
551                 /*
552                  * Yes - treat this as an error.
553                  */
554                 *err = WTAP_ERR_BAD_FILE;
555                 *err_info = g_strdup("lanalyzer: Record length is less than packet size");
556                 return FALSE;
557         }
558
559         wth->phdr.presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
560
561         time_low = pletohs(&descriptor[8]);
562         time_med = pletohs(&descriptor[10]);
563         time_high = pletohs(&descriptor[12]);
564         t = (((guint64)time_low) << 0) + (((guint64)time_med) << 16) +
565             (((guint64)time_high) << 32);
566         tsecs = (time_t) (t/2000000);
567         lanalyzer = (lanalyzer_t *)wth->priv;
568         wth->phdr.ts.secs = tsecs + lanalyzer->start;
569         wth->phdr.ts.nsecs = ((guint32) (t - tsecs*2000000)) * 500;
570
571         if (true_size - 4 >= packet_size) {
572                 /*
573                  * It appears that the "true size" includes the FCS;
574                  * make it reflect the non-FCS size (the "packet size"
575                  * appears never to include the FCS, even if no slicing
576                  * is done).
577                  */
578                 true_size -= 4;
579         }
580         wth->phdr.len = true_size;
581         wth->phdr.caplen = packet_size;
582
583         switch (wth->file_encap) {
584
585         case WTAP_ENCAP_ETHERNET:
586                 /* We assume there's no FCS in this frame. */
587                 wth->pseudo_header.eth.fcs_len = 0;
588                 break;
589         }
590
591         return TRUE;
592 }
593
594 static gboolean lanalyzer_seek_read(wtap *wth, gint64 seek_off,
595     union wtap_pseudo_header *pseudo_header, guint8 *pd, int length,
596     int *err, gchar **err_info)
597 {
598         int bytes_read;
599
600         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
601                 return FALSE;
602
603         /*
604          * Read the packet data.
605          */
606         bytes_read = file_read(pd, length, wth->random_fh);
607         if (bytes_read != length) {
608                 *err = file_error(wth->random_fh, err_info);
609                 if (*err == 0)
610                         *err = WTAP_ERR_SHORT_READ;
611                 return FALSE;
612         }
613
614         switch (wth->file_encap) {
615
616         case WTAP_ENCAP_ETHERNET:
617                 /* We assume there's no FCS in this frame. */
618                 pseudo_header->eth.fcs_len = 0;
619                 break;
620         }
621
622         return TRUE;
623 }
624
625 /*---------------------------------------------------
626  * Returns TRUE on success, FALSE on error
627  * Write "cnt" bytes of zero with error control
628  *---------------------------------------------------*/
629 static gboolean s0write(wtap_dumper *wdh, size_t cnt, int *err)
630 {
631         static const guint8 z64[64];
632         size_t snack;
633
634         while (cnt) {
635                 snack = cnt > 64 ? 64 : cnt;
636
637                 if (!wtap_dump_file_write(wdh, z64, snack, err))
638                         return FALSE;
639                 cnt -= snack;
640         }
641         return TRUE; /* ok */
642 }
643
644 /*---------------------------------------------------
645  * Returns TRUE on success, FALSE on error
646  * Write an 8-bit value with error control
647  *---------------------------------------------------*/
648 static gboolean s8write(wtap_dumper *wdh, const guint8 s8, int *err)
649 {
650         return wtap_dump_file_write(wdh, &s8, 1, err);
651 }
652 /*---------------------------------------------------
653  * Returns TRUE on success, FALSE on error
654  * Write a 16-bit value with error control
655  *---------------------------------------------------*/
656 static gboolean s16write(wtap_dumper *wdh, const guint16 s16, int *err)
657 {
658         return wtap_dump_file_write(wdh, &s16, 2, err);
659 }
660 /*---------------------------------------------------
661  * Returns TRUE on success, FALSE on error
662  * Write a 32-bit value with error control
663  *---------------------------------------------------*/
664 static gboolean s32write(wtap_dumper *wdh, const guint32 s32, int *err)
665 {
666         return wtap_dump_file_write(wdh, &s32, 4, err);
667 }
668 /*---------------------------------------------------
669  *
670  * calculates C.c = A.a - B.b
671  *---------------------------------------------------*/
672 static void my_timersub(const struct timeval *a,
673                         const struct timeval *b,
674                               struct timeval *c)
675 {
676       gint32 usec = a->tv_usec;
677
678       c->tv_sec = a->tv_sec - b->tv_sec;
679       if (b->tv_usec > usec) {
680            c->tv_sec--;
681            usec += 1000000;
682            }
683       c->tv_usec = usec - b->tv_usec;
684 }
685 /*---------------------------------------------------
686  * Write a record for a packet to a dump file.
687  * Returns TRUE on success, FALSE on failure.
688  *---------------------------------------------------*/
689 static gboolean lanalyzer_dump(wtap_dumper *wdh,
690         const struct wtap_pkthdr *phdr,
691         const union wtap_pseudo_header *pseudo_header _U_,
692         const guint8 *pd, int *err)
693 {
694       double x;
695       int    i;
696       int    len;
697           struct timeval tv;
698
699       LA_TmpInfo *itmp = (LA_TmpInfo*)(wdh->priv);
700       struct timeval td;
701       int    thisSize = phdr->caplen + LA_PacketRecordSize + LA_RecordHeaderSize;
702
703       if (wdh->bytes_dumped + thisSize > LA_ProFileLimit) {
704             /* printf(" LA_ProFileLimit reached\n");     */
705             *err = EFBIG;
706             return FALSE; /* and don't forget the header */
707             }
708
709       len = phdr->caplen + (phdr->caplen ? LA_PacketRecordSize : 0);
710
711       if (!s16write(wdh, htoles(0x1005), err))
712             return FALSE;
713       if (!s16write(wdh, htoles(len), err))
714             return FALSE;
715
716       tv.tv_sec  = (long int) phdr->ts.secs;
717       tv.tv_usec = phdr->ts.nsecs / 1000;
718
719       if (!itmp->init) {
720             /* collect some information for the
721              * finally written header
722              */
723                     /* XXX - this conversion could probably improved, if the start uses ns */
724             itmp->start   = tv;
725             itmp->pkts    = 0;
726             itmp->init    = TRUE;
727             itmp->encap   = wdh->encap;
728             itmp->lastlen = 0;
729             }
730
731       my_timersub(&(tv),&(itmp->start),&td);
732
733       x   = (double) td.tv_usec;
734       x  += (double) td.tv_sec * 1000000;
735       x  *= 2;
736
737       if (!s16write(wdh, htoles(0x0001), err))             /* pr.rx_channels */
738             return FALSE;
739       if (!s16write(wdh, htoles(0x0008), err))             /* pr.rx_errors   */
740             return FALSE;
741       if (!s16write(wdh, htoles(phdr->len + 4), err))      /* pr.rx_frm_len  */
742             return FALSE;
743       if (!s16write(wdh, htoles(phdr->caplen), err))       /* pr.rx_frm_sln  */
744             return FALSE;
745
746       for (i = 0; i < 3; i++) {
747             if (!s16write(wdh, htoles((guint16) x), err))  /* pr.rx_time[i]  */
748                   return FALSE;
749             x /= 0xffff;
750       }
751
752       if (!s32write(wdh, htolel(++itmp->pkts), err))       /* pr.pktno      */
753             return FALSE;
754       if (!s16write(wdh, htoles(itmp->lastlen), err))      /* pr.prlen      */
755             return FALSE;
756       itmp->lastlen = len;
757
758       if (!s0write(wdh, 12, err))
759             return FALSE;
760
761       if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
762             return FALSE;
763
764       wdh->bytes_dumped += thisSize;
765
766       return TRUE;
767 }
768
769 /*---------------------------------------------------
770  * Returns 0 if we could write the specified encapsulation type,
771  * an error indication otherwise.
772  *---------------------------------------------------*/
773 int lanalyzer_dump_can_write_encap(int encap)
774 {
775       /* Per-packet encapsulations aren't supported. */
776       if (encap == WTAP_ENCAP_PER_PACKET)
777                   return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
778
779       if ( encap != WTAP_ENCAP_ETHERNET
780         && encap != WTAP_ENCAP_TOKEN_RING )
781                   return WTAP_ERR_UNSUPPORTED_ENCAP;
782       /*
783        * printf("lanalyzer_dump_can_write_encap(%d)\n",encap);
784        */
785       return 0;
786 }
787
788 /*---------------------------------------------------
789  * Returns TRUE on success, FALSE on failure; sets "*err" to an
790  * error code on failure
791  *---------------------------------------------------*/
792 gboolean lanalyzer_dump_open(wtap_dumper *wdh, int *err)
793 {
794       int   jump;
795       void  *tmp;
796
797       tmp = g_malloc(sizeof(LA_TmpInfo));
798       if (!tmp) {
799               *err = errno;
800               return FALSE;
801             }
802
803       ((LA_TmpInfo*)tmp)->init = FALSE;
804       wdh->priv          = tmp;
805       wdh->subtype_write = lanalyzer_dump;
806       wdh->subtype_close = lanalyzer_dump_close;
807
808       /* Some of the fields in the file header aren't known yet so
809        just skip over it for now.  It will be created after all
810        of the packets have been written. */
811
812       jump = sizeof (LA_HeaderRegularFake)
813            + sizeof (LA_RxChannelNameFake)
814            + sizeof (LA_TxChannelNameFake)
815            + sizeof (LA_RxTemplateNameFake)
816            + sizeof (LA_TxTemplateNameFake)
817            + sizeof (LA_DisplayOptionsFake)
818            + LA_SummaryRecordSize
819            + LA_SubfileSummaryRecordSize
820            + sizeof (LA_CyclicInformationFake)
821            + LA_IndexRecordSize;
822
823       if (fseek(wdh->fh, jump, SEEK_SET) == -1) {
824               *err = errno;
825               return FALSE;
826             }
827       wdh->bytes_dumped = jump;
828       return TRUE;
829 }
830
831 /*---------------------------------------------------
832  *
833  *---------------------------------------------------*/
834 static gboolean lanalyzer_dump_header(wtap_dumper *wdh, int *err)
835 {
836       LA_TmpInfo *itmp   = (LA_TmpInfo*)(wdh->priv);
837       guint16 board_type = itmp->encap == WTAP_ENCAP_TOKEN_RING
838                               ? BOARD_325TR     /* LANalyzer Board Type */
839                               : BOARD_325;      /* LANalyzer Board Type */
840       time_t secs;
841       struct tm *fT;
842
843       /* The secs variable is needed to work around 32/64-bit time_t issues.
844          itmp->start is a timeval struct, which declares its tv_sec field
845          (itmp->start.tv_sec) as a long (typically 32 bits). time_t can be 32
846          or 64 bits, depending on the platform. Invoking as follows could
847          pass a pointer to a 32-bit long where a pointer to a 64-bit time_t
848          is expected: localtime((time_t*) &(itmp->start.tv_sec)) */
849       secs = itmp->start.tv_sec;
850       fT = localtime(&secs);
851       if (fT == NULL)
852             return FALSE;
853
854       fseek(wdh->fh, 0, SEEK_SET);
855
856       if (!wtap_dump_file_write(wdh, &LA_HeaderRegularFake,
857                                 sizeof LA_HeaderRegularFake, err))
858                 return FALSE;
859       if (!wtap_dump_file_write(wdh, &LA_RxChannelNameFake,
860                                 sizeof LA_RxChannelNameFake, err))
861                 return FALSE;
862       if (!wtap_dump_file_write(wdh, &LA_TxChannelNameFake,
863                                 sizeof LA_TxChannelNameFake, err))
864                 return FALSE;
865       if (!wtap_dump_file_write(wdh, &LA_RxTemplateNameFake,
866                                 sizeof LA_RxTemplateNameFake, err))
867                 return FALSE;
868       if (!wtap_dump_file_write(wdh, &LA_TxTemplateNameFake,
869                                 sizeof LA_TxTemplateNameFake, err))
870                 return FALSE;
871       if (!wtap_dump_file_write(wdh, &LA_DisplayOptionsFake,
872                                 sizeof LA_DisplayOptionsFake, err))
873                 return FALSE;
874       /*-----------------------------------------------------------------*/
875       if (!s16write(wdh, htoles(RT_Summary), err))         /* rid */
876             return FALSE;
877       if (!s16write(wdh, htoles(SummarySize), err))        /* rlen */
878             return FALSE;
879       if (!s8write(wdh, (guint8) fT->tm_mday, err))        /* s.datcre.day */
880             return FALSE;
881       if (!s8write(wdh, (guint8) (fT->tm_mon+1), err))     /* s.datcre.mon */
882             return FALSE;
883       if (!s16write(wdh, htoles(fT->tm_year + 1900), err)) /* s.datcre.year */
884             return FALSE;
885       if (!s8write(wdh, (guint8) fT->tm_mday, err))        /* s.datclo.day */
886             return FALSE;
887       if (!s8write(wdh, (guint8) (fT->tm_mon+1), err))     /* s.datclo.mon */
888             return FALSE;
889       if (!s16write(wdh, htoles(fT->tm_year + 1900), err)) /* s.datclo.year */
890             return FALSE;
891       if (!s8write(wdh, (guint8) fT->tm_sec, err))         /* s.timeopn.second */
892             return FALSE;
893       if (!s8write(wdh, (guint8) fT->tm_min, err))         /* s.timeopn.minute */
894             return FALSE;
895       if (!s8write(wdh, (guint8) fT->tm_hour, err))        /* s.timeopn.hour */
896             return FALSE;
897       if (!s8write(wdh, (guint8) fT->tm_mday, err))        /* s.timeopn.mday */
898             return FALSE;
899       if (!s0write(wdh, 2, err))
900             return FALSE;
901       if (!s8write(wdh, (guint8) fT->tm_sec, err))         /* s.timeclo.second */
902             return FALSE;
903       if (!s8write(wdh, (guint8) fT->tm_min, err))         /* s.timeclo.minute */
904             return FALSE;
905       if (!s8write(wdh, (guint8) fT->tm_hour, err))        /* s.timeclo.hour */
906             return FALSE;
907       if (!s8write(wdh, (guint8) fT->tm_mday, err))        /* s.timeclo.mday */
908             return FALSE;
909       if (!s0write(wdh, 2, err))
910             return FALSE;
911       if (!s0write(wdh, 6, err))                           /* EAddr  == 0      */
912             return FALSE;
913       if (!s16write(wdh, htoles(1), err))                  /* s.mxseqno */
914             return FALSE;
915       if (!s16write(wdh, htoles(0), err))                  /* s.slcoffo */
916             return FALSE;
917       if (!s16write(wdh, htoles(1514), err))               /* s.mxslc */
918             return FALSE;
919       if (!s32write(wdh, htolel(itmp->pkts), err))         /* s.totpktt */
920             return FALSE;
921       /*
922        * statrg == 0; ? -1
923        * stptrg == 0; ? -1
924        * s.mxpkta[0]=0
925        */
926       if (!s0write(wdh, 12, err))
927             return FALSE;
928       if (!s32write(wdh, htolel(itmp->pkts), err))         /* sr.s.mxpkta[1]  */
929             return FALSE;
930       if (!s0write(wdh, 34*4, err))                        /* s.mxpkta[2-33]=0  */
931             return FALSE;
932       if (!s16write(wdh, htoles(board_type), err))
933             return FALSE;
934       if (!s0write(wdh, 20, err))                             /* board_version == 0 */
935             return FALSE;
936       /*-----------------------------------------------------------------*/
937       if (!s16write(wdh, htoles(RT_SubfileSummary), err))     /* ssr.rid */
938             return FALSE;
939       if (!s16write(wdh, htoles(LA_SubfileSummaryRecordSize-4), err)) /* ssr.rlen */
940             return FALSE;
941       if (!s16write(wdh, htoles(1), err))                     /* ssr.seqno */
942             return FALSE;
943       if (!s32write(wdh, htolel(itmp->pkts), err))            /* ssr.totpkts */
944             return FALSE;
945       /*-----------------------------------------------------------------*/
946       if (!wtap_dump_file_write(wdh, &LA_CyclicInformationFake,
947                                 sizeof LA_CyclicInformationFake, err))
948             return FALSE;
949       /*-----------------------------------------------------------------*/
950       if (!s16write(wdh, htoles(RT_Index), err))              /* rid */
951             return FALSE;
952       if (!s16write(wdh, htoles(LA_IndexRecordSize -4), err)) /* rlen */
953             return FALSE;
954       if (!s16write(wdh, htoles(LA_IndexSize), err))          /* idxsp */
955             return FALSE;
956       if (!s0write(wdh, LA_IndexRecordSize - 6, err))
957             return FALSE;
958
959       return TRUE;
960 }
961
962 /*---------------------------------------------------
963  * Finish writing to a dump file.
964  * Returns TRUE on success, FALSE on failure.
965  *---------------------------------------------------*/
966 static gboolean lanalyzer_dump_close(wtap_dumper *wdh, int *err)
967 {
968       lanalyzer_dump_header(wdh,err);
969       return *err ? FALSE : TRUE;
970 }