Coverage Report

Created: 2026-05-14 06:28

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