Coverage Report

Created: 2026-01-02 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/wiretap/aethra.c
Line
Count
Source
1
/* aethra.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
0
#define WS_LOG_DOMAIN "aethra"
10
11
#include "config.h"
12
#include "aethra.h"
13
14
#include <string.h>
15
16
#include <wsutil/pint.h>
17
18
#include "wtap_module.h"
19
#include "file_wrappers.h"
20
21
/* Magic number in Aethra PC108 files. */
22
#define MAGIC_SIZE  5
23
24
static const unsigned char aethra_magic[MAGIC_SIZE] = {
25
  'V', '0', '2', '0', '8'
26
};
27
28
/* Aethra file header. */
29
struct aethra_hdr {
30
  unsigned char magic[MAGIC_SIZE];
31
  uint8_t unknown1[39]; /* 5-43 */
32
  unsigned char sw_vers[60];  /* 44-103 - software version string, not null-terminated */
33
  uint8_t unknown2[118];  /* 104-221 */
34
  uint8_t start_sec;  /* 222 - seconds of capture start time */
35
  uint8_t start_min;  /* 223 - minutes of capture start time */
36
  uint8_t start_hour; /* 224 - hour of capture start time */
37
  uint8_t unknown3[462];  /* 225-686 */
38
  unsigned char xxx_string[37]; /* 687-723 - null-terminated short comment string? */
39
  uint8_t unknown3_5[4];  /* 724-727 */
40
  unsigned char yyy_string[4504];/* 728-5231 - null-terminated long comment string? */
41
  uint8_t start_year[2];  /* 5232-5233 - year of capture start date */
42
  uint8_t start_month[2]; /* 5234-5235 - month of capture start date */
43
  uint8_t unknown4[2];  /* 5236-5237 */
44
  uint8_t start_day[2]; /* 5238-5239 - day of capture start date */
45
  uint8_t unknown5[8];  /* 5240-5247 */
46
  unsigned char com_info[16]; /* 5248-5263 - COM port and speed, null-padded(?) */
47
  uint8_t unknown6[107];  /* 5264-5370 */
48
  unsigned char xxx_vers[41]; /* 5371-5411 - unknown version string (longer, null-padded?) */
49
};
50
51
/* Aethra record header.  Yes, the alignment is weird.
52
   All multi-byte fields are little-endian. */
53
struct aethrarec_hdr {
54
  uint8_t rec_size[2];  /* record length, not counting the length itself */
55
  uint8_t rec_type; /* record type */
56
  uint8_t timestamp[4]; /* milliseconds since start of capture */
57
  uint8_t flags;    /* low-order bit: 0 = N->U, 1 = U->N */
58
};
59
60
/*
61
 * Record types.
62
 *
63
 * As the indications from the device and signalling messages appear not
64
 * to have the 8th bit set, and at least some B-channel records do, we
65
 * assume, for now, that the 8th bit indicates bearer information.
66
 *
67
 * 0x9F is the record type seen for B31 channel records; that might be
68
 * 0x80|31, so, for now, we assume that if the 8th bit is set, the B
69
 * channel number is in the low 7 bits.
70
 */
71
#define AETHRA_BEARER   0x80  /* bearer information */
72
73
#define AETHRA_DEVICE   0x00  /* indication from the monitoring device */
74
0
#define AETHRA_ISDN_LINK  0x01  /* information from the ISDN link */
75
76
/*
77
 * In AETHRA_DEVICE records, the flags field has what appears to
78
 * be a record subtype.
79
 */
80
#define AETHRA_DEVICE_STOP_MONITOR  0x00  /* Stop Monitor */
81
#define AETHRA_DEVICE_START_MONITOR 0x04  /* Start Monitor */
82
#define AETHRA_DEVICE_ACTIVATION  0x05  /* Activation */
83
#define AETHRA_DEVICE_START_CAPTURE 0x5F  /* Start Capture */
84
85
/*
86
 * In AETHRA_ISDN_LINK and bearer channel records, the flags field has
87
 * a direction flag and possibly some other bits.
88
 *
89
 * In AETHRA_ISDN_LINK records, at least some of the other bits are
90
 * a subtype.
91
 *
92
 * In bearer channel records, there are records with data and
93
 * "Constant Value" records with a single byte.  Data has a
94
 * flags value of 0x14 ORed with the direction flag, and Constant Value
95
 * records have a flags value of 0x16 ORed with the direction flag.
96
 * There are also records of an unknown type with 0x02, probably
97
 * ORed with the direction flag.
98
 */
99
0
#define AETHRA_U_TO_N       0x01  /* set for TE->NT */
100
101
0
#define AETHRA_ISDN_LINK_SUBTYPE    0xFE
102
0
#define AETHRA_ISDN_LINK_LAPD     0x00  /* LAPD frame */
103
0
#define AETHRA_ISDN_LINK_SA_BITS    0x2E  /* 2048K PRI Sa bits (G.704 section 2.3.2) */
104
0
#define AETHRA_ISDN_LINK_ALL_ALARMS_CLEARED 0x30  /* All Alarms Cleared */
105
106
typedef struct {
107
  time_t       start;
108
  unsigned int packet_number;
109
} aethra_t;
110
111
static int aethra_file_type_subtype = -1;
112
113
void register_aethra(void);
114
115
static bool
116
aethra_read_rec_header(wtap* wth, FILE_T fh, struct aethrarec_hdr* hdr,
117
  wtap_rec* rec, int* err, char** err_info)
118
0
{
119
0
  aethra_t* aethra = (aethra_t*)wth->priv;
120
0
  uint32_t rec_size;
121
0
  uint32_t packet_size;
122
0
  uint32_t msecs;
123
124
  /* Read record header. */
125
0
  if (!wtap_read_bytes_or_eof(fh, hdr, sizeof * hdr, err, err_info))
126
0
    return false;
127
128
0
  rec_size = pletohu16(hdr->rec_size);
129
0
  if (rec_size < (sizeof * hdr - sizeof hdr->rec_size)) {
130
    /* The record is shorter than a record header. */
131
0
    *err = WTAP_ERR_BAD_FILE;
132
0
    *err_info = ws_strdup_printf("aethra: File has %u-byte record, less than minimum of %u",
133
0
      rec_size,
134
0
      (unsigned int)(sizeof * hdr - sizeof hdr->rec_size));
135
0
    return false;
136
0
  }
137
0
  if (rec_size > WTAP_MAX_PACKET_SIZE_STANDARD) {
138
    /*
139
     * Probably a corrupt capture file; return an error,
140
     * so that our caller doesn't blow up trying to allocate
141
     * space for an immensely-large packet.
142
     */
143
0
    *err = WTAP_ERR_BAD_FILE;
144
0
    *err_info = ws_strdup_printf("aethra: File has %u-byte packet, bigger than maximum of %u",
145
0
      rec_size, WTAP_MAX_PACKET_SIZE_STANDARD);
146
0
    return false;
147
0
  }
148
149
0
  packet_size = rec_size - (uint32_t)(sizeof * hdr - sizeof hdr->rec_size);
150
151
0
  wtap_setup_packet_rec(rec, wth->file_encap);
152
0
  rec->presence_flags = WTAP_HAS_TS;
153
0
  msecs = pletohu32(hdr->timestamp);
154
0
  rec->ts.secs = aethra->start + (msecs / 1000);
155
0
  rec->ts.nsecs = (msecs % 1000) * 1000000;
156
0
  rec->rec_header.packet_header.caplen = packet_size;
157
0
  rec->rec_header.packet_header.len = packet_size;
158
0
  rec->rec_header.packet_header.pseudo_header.isdn.uton = (hdr->flags & AETHRA_U_TO_N);
159
0
  rec->rec_header.packet_header.pseudo_header.isdn.channel = 0; /* XXX - D channel */
160
161
0
  return true;
162
0
}
163
164
/* Read the next packet */
165
static bool aethra_read(wtap *wth, wtap_rec *rec, int *err,
166
    char **err_info, int64_t *data_offset)
167
0
{
168
0
  aethra_t* aethra = (aethra_t*)wth->priv;
169
0
  struct aethrarec_hdr hdr;
170
171
  /*
172
   * Keep reading until we see an AETHRA_ISDN_LINK with a subtype
173
   * of AETHRA_ISDN_LINK_LAPD record or get an end-of-file.
174
   */
175
0
  for (;;) {
176
0
    *data_offset = file_tell(wth->fh);
177
178
    /* Read record header. */
179
0
    if (!aethra_read_rec_header(wth, wth->fh, &hdr, rec, err, err_info))
180
0
      return false;
181
182
    /*
183
     * XXX - if this is big, we might waste memory by
184
     * growing the buffer to handle it.
185
     */
186
0
    if (rec->rec_header.packet_header.caplen != 0) {
187
0
      if (!wtap_read_bytes_buffer(wth->fh, &rec->data,
188
0
          rec->rec_header.packet_header.caplen, err, err_info))
189
0
        return false; /* Read error */
190
0
    }
191
0
    aethra->packet_number++;
192
193
0
    switch (hdr.rec_type) {
194
195
0
    case AETHRA_ISDN_LINK:
196
0
      ws_noisy("Packet %u: type 0x%02x (AETHRA_ISDN_LINK)\n", aethra->packet_number, hdr.rec_type);
197
0
      switch (hdr.flags & AETHRA_ISDN_LINK_SUBTYPE) {
198
199
0
      case AETHRA_ISDN_LINK_LAPD:
200
        /*
201
         * The data is a LAPD frame.
202
         */
203
0
        ws_noisy("    subtype 0x%02x (AETHRA_ISDN_LINK_LAPD)\n", hdr.flags & AETHRA_ISDN_LINK_SUBTYPE);
204
0
        goto found;
205
206
0
      case AETHRA_ISDN_LINK_SA_BITS:
207
        /*
208
         * These records have one data byte, which
209
         * has the Sa bits in the lower 5 bits.
210
         *
211
         * XXX - what about stuff other than 2048K
212
         * PRI lines?
213
         */
214
0
        ws_noisy("    subtype 0x%02x (AETHRA_ISDN_LINK_SA_BITS)\n", hdr.flags & AETHRA_ISDN_LINK_SUBTYPE);
215
0
        break;
216
217
0
      case AETHRA_ISDN_LINK_ALL_ALARMS_CLEARED:
218
        /*
219
         * No data, just an "all alarms cleared"
220
         * indication.
221
         */
222
0
        ws_noisy("    subtype 0x%02x (AETHRA_ISDN_LINK_ALL_ALARMS_CLEARED)\n", hdr.flags & AETHRA_ISDN_LINK_SUBTYPE);
223
0
        break;
224
225
0
      default:
226
0
        ws_noisy("    subtype 0x%02x, packet_size %u, direction 0x%02x\n",
227
0
            hdr.flags & AETHRA_ISDN_LINK_SUBTYPE, rec->rec_header.packet_header.caplen, hdr.flags & AETHRA_U_TO_N);
228
0
        break;
229
0
      }
230
0
      break;
231
232
0
    default:
233
0
      ws_debug("Packet %u: type 0x%02x, packet_size %u, flags 0x%02x\n", aethra->packet_number, hdr.rec_type, rec->rec_header.packet_header.caplen, hdr.flags);
234
0
      break;
235
0
    }
236
0
  }
237
238
0
found:
239
0
  rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
240
0
  return true;
241
0
}
242
243
static bool
244
aethra_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec,
245
    int *err, char **err_info)
246
0
{
247
0
  struct aethrarec_hdr hdr;
248
249
0
  if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
250
0
    return false;
251
252
0
  if (!aethra_read_rec_header(wth, wth->random_fh, &hdr, rec, err,
253
0
      err_info)) {
254
0
    if (*err == 0)
255
0
      *err = WTAP_ERR_SHORT_READ;
256
0
    return false;
257
0
  }
258
259
  /*
260
   * Read the packet data.
261
   */
262
0
  if (!wtap_read_bytes_buffer(wth->random_fh, &rec->data,
263
0
      rec->rec_header.packet_header.caplen, err, err_info))
264
0
    return false; /* failed */
265
266
0
  rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
267
0
  return true;
268
0
}
269
270
wtap_open_return_val aethra_open(wtap* wth, int* err, char** err_info)
271
0
{
272
0
  struct aethra_hdr hdr;
273
0
  struct tm tm;
274
0
  aethra_t* aethra;
275
276
  /* Read in the string that should be at the start of a "aethra" file */
277
0
  if (!wtap_read_bytes(wth->fh, hdr.magic, sizeof hdr.magic, err,
278
0
    err_info)) {
279
0
    if (*err != WTAP_ERR_SHORT_READ)
280
0
      return WTAP_OPEN_ERROR;
281
0
    return WTAP_OPEN_NOT_MINE;
282
0
  }
283
284
0
  if (memcmp(hdr.magic, aethra_magic, sizeof aethra_magic) != 0)
285
0
    return WTAP_OPEN_NOT_MINE;
286
287
  /* Read the rest of the header. */
288
0
  if (!wtap_read_bytes(wth->fh, (char*)&hdr + sizeof hdr.magic,
289
0
    sizeof hdr - sizeof hdr.magic, err, err_info))
290
0
    return WTAP_OPEN_ERROR;
291
0
  wth->file_type_subtype = aethra_file_type_subtype;
292
0
  aethra = g_new(aethra_t, 1);
293
0
  wth->priv = (void*)aethra;
294
0
  wth->subtype_read = aethra_read;
295
0
  wth->subtype_seek_read = aethra_seek_read;
296
297
  /*
298
   * Convert the time stamp to a "time_t".
299
   */
300
0
  tm.tm_year = pletohu16(&hdr.start_year) - 1900;
301
0
  tm.tm_mon = pletohu16(&hdr.start_month) - 1;
302
0
  tm.tm_mday = pletohu16(&hdr.start_day);
303
0
  tm.tm_hour = hdr.start_hour;
304
0
  tm.tm_min = hdr.start_min;
305
0
  tm.tm_sec = hdr.start_sec;
306
0
  tm.tm_isdst = -1;
307
0
  aethra->start = mktime(&tm);
308
0
  aethra->packet_number = 0;
309
310
  /*
311
   * We've only seen ISDN files, so, for now, we treat all
312
   * files as ISDN.
313
   */
314
0
  wth->file_encap = WTAP_ENCAP_ISDN;
315
0
  wth->snapshot_length = 0; /* not available in header */
316
0
  wth->file_tsprec = WTAP_TSPREC_MSEC;
317
318
  /*
319
   * Add an IDB; we don't know how many interfaces were
320
   * involved, so we just say one interface, about which
321
   * we only know the link-layer type, snapshot length,
322
   * and time stamp resolution.
323
   */
324
0
  wtap_add_generated_idb(wth);
325
326
0
  return WTAP_OPEN_MINE;
327
0
}
328
329
static const struct supported_block_type aethra_blocks_supported[] = {
330
  /*
331
   * We support packet blocks, with no comments or other options.
332
   */
333
  { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
334
};
335
336
static const struct file_type_subtype_info aethra_info = {
337
  "Aethra .aps file", "aethra", "aps", NULL,
338
  false, BLOCKS_SUPPORTED(aethra_blocks_supported),
339
  NULL, NULL, NULL
340
};
341
342
void register_aethra(void)
343
14
{
344
14
  aethra_file_type_subtype = wtap_register_file_type_subtype(&aethra_info);
345
346
  /*
347
   * Register name for backwards compatibility with the
348
   * wtap_filetypes table in Lua.
349
   */
350
14
  wtap_register_backwards_compatibility_lua_name("AETHRA",
351
14
      aethra_file_type_subtype);
352
14
}
353
354
/*
355
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
356
 *
357
 * Local variables:
358
 * c-basic-offset: 8
359
 * tab-width: 8
360
 * indent-tabs-mode: t
361
 * End:
362
 *
363
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
364
 * :indentSize=8:tabSize=8:noTabs=false:
365
 */