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