Coverage Report

Created: 2026-09-28 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/wiretap/dct3trace.c
Line
Count
Source
1
/* dct3trace.c
2
 * Routines for reading signalling traces generated by Gammu (www.gammu.org)
3
 * from Nokia DCT3 phones in Netmonitor mode.
4
 *
5
 * gammu --nokiadebug nhm5_587.txt v18-19
6
 *
7
 * Duncan Salerno <duncan.salerno@googlemail.com>
8
 *
9
 * Wiretap Library
10
 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
11
 *
12
 * SPDX-License-Identifier: GPL-2.0-or-later
13
 */
14
15
#include "config.h"
16
#include "dct3trace.h"
17
#include "wtap_module.h"
18
#include "file_wrappers.h"
19
20
#include <stdlib.h>
21
#include <string.h>
22
#include <errno.h>
23
24
#include <wsutil/strtoi.h>
25
#include <libxml/tree.h>
26
#include <libxml/parser.h>
27
#include <libxml/xpath.h>
28
29
/*
30
   Example downlink data:
31
32
<?xml version="1.0"?>
33
<dump>
34
<l1 direction="down" logicalchannel="96" physicalchannel="19" sequence="268116" error="0" timeshift="2992" bsic="22" data="31063F100DD0297A53E1020103C802398E0B2B2B2B2B2B" >
35
<l2 data="063F100DD0297A53E1020103" rest="C802398E0B2B2B2B2B2B" >
36
</l2>
37
</l1>
38
</dump>
39
40
   Example uplink data (no raw L1):
41
42
<?xml version="1.0"?>
43
<dump>
44
<l1 direction="up" logicalchannel="112" >
45
<l2 type="U" subtype="Unknown" p="0" data="061500400000000000000000000000000000" >
46
</l2>
47
</l1>
48
</dump>
49
50
 */
51
52
typedef struct dct3trace_file_info {
53
  GByteArray* buffer;   // holds current chunk of file
54
  int64_t start_offset;   // where in the file the start of the buffer points
55
} dct3trace_file_info_t;
56
57
/* We expect to find all the info we need to tell if this file is ours
58
 * within this many bytes. Must include the beginTime attribute.
59
 */
60
0
#define MAGIC_BUF_SIZE 512
61
62
 /* String constants sought in the XML data.
63
  * Written as strings instead of lists of chars for readability.
64
  * Use the CLEN() macro to get the length of the constant without counting
65
  * the null byte at the end.
66
  */
67
0
#define CLEN(x) (sizeof(x)-1)
68
69
/* Magic text to check */
70
static const unsigned char c_xml_magic[] = "<?xml";
71
static const char dct3trace_magic_line2[] = "<dump>";
72
static const char dct3trace_magic_record_start[]  = "<l1 ";
73
static const char dct3trace_magic_record_end[]  = "</l1>";
74
75
0
#define RINGBUFFER_START_SIZE INT_MAX
76
0
#define RINGBUFFER_CHUNK_SIZE 1024
77
78
0
#define MAX_PACKET_LEN 23
79
80
static int dct3trace_file_type_subtype = -1;
81
82
void register_dct3trace(void);
83
84
/*
85
 * Following 3 functions taken from gsmdecode-0.7bis, with permission:
86
 *
87
 *   https://web.archive.org/web/20091218112927/http://wiki.thc.org/gsm
88
 */
89
90
static int
91
hc2b(unsigned char hex)
92
0
{
93
0
  hex = g_ascii_tolower(hex);
94
0
  if ((hex >= '0') && (hex <= '9'))
95
0
    return hex - '0';
96
0
  if ((hex >= 'a') && (hex <= 'f'))
97
0
    return hex - 'a' + 10;
98
0
  return -1;
99
0
}
100
101
static int
102
hex2bin(uint8_t *out, uint8_t *out_end, char *in)
103
0
{
104
0
  uint8_t *out_start = out;
105
0
  int is_low = 0;
106
0
  int c;
107
108
0
  while (*in != '\0')
109
0
  {
110
0
    c = hc2b(*(unsigned char *)in);
111
0
    if (c < 0)
112
0
    {
113
0
      in++;
114
0
      continue;
115
0
    }
116
0
    if (out >= out_end)
117
0
    {
118
      /* Too much data */
119
0
      return -1;
120
0
    }
121
0
    if (is_low == 0)
122
0
    {
123
0
      *out = c << 4;
124
0
      is_low = 1;
125
0
    } else {
126
0
      *out |= (c & 0x0f);
127
0
      is_low = 0;
128
0
      out++;
129
0
    }
130
0
    in++;
131
0
  }
132
133
0
  return (int)(out - out_start);
134
0
}
135
136
static bool
137
xml_get_int(const char* name, xmlChar* str, int* val, int* err, char** err_info)
138
0
{
139
0
  if (str != NULL) {
140
0
    if (!ws_strtoi32((const char*)str, NULL, val)) {
141
0
      *err = WTAP_ERR_BAD_FILE;
142
0
      if (errno == ERANGE) {
143
0
        if (*val < 0)
144
0
          *err_info = ws_strdup_printf("dct3trace: %s value is too small, minimum is %d", name, *val);
145
0
        else
146
0
          *err_info = ws_strdup_printf("dct3trace: %s value is too large, maximum is %d", name, *val);
147
0
      }
148
0
      else
149
0
        *err_info = ws_strdup_printf("dct3trace: %s value \"%s\" not a number", name, str);
150
0
      return false;
151
0
    }
152
0
  }
153
154
0
  return true;
155
0
}
156
157
static bool
158
dct3trace_get_packet(wtap* wth, wtap_rec* rec, const char* text, size_t len, int* err, char** err_info)
159
0
{
160
0
  xmlDocPtr           doc;
161
0
  xmlNodePtr root_element;
162
0
  bool status = true;
163
0
  uint8_t databuf[MAX_PACKET_LEN], * bufp;
164
0
  int local_len = 0;
165
0
  bool have_data = false;
166
167
0
  doc = xmlParseMemory(text, (int)len);
168
0
  if (doc == NULL) {
169
0
    return false;
170
0
  }
171
172
0
  root_element = xmlDocGetRootElement(doc);
173
0
  if (root_element == NULL) {
174
0
    ws_debug("empty xml doc");
175
0
    status = false;
176
0
    goto end;
177
0
  }
178
179
  //Sanity check
180
0
  if (xmlStrcmp(root_element->name, (const xmlChar*)"l1") != 0) {
181
0
    *err = WTAP_ERR_BAD_FILE;
182
0
    *err_info = ws_strdup("dct3trace: Did not start with \"<l1\"");
183
0
    status = false;
184
0
    goto end;
185
0
  }
186
187
  /* Walk the attributes of the l1 tag */
188
0
  bufp = &databuf[0];
189
0
  for (xmlAttrPtr attr = root_element->properties; attr; attr = attr->next) {
190
0
    int channel = 0, tmp = 0;
191
0
    if (xmlStrcmp(attr->name, (const xmlChar*)"direction") == 0) {
192
0
      xmlChar* str = xmlNodeListGetString(root_element->doc, attr->children, 1);
193
0
      if (str != NULL) {
194
0
        rec->rec_header.packet_header.pseudo_header.gsm_um.uplink = !strstr((const char*)str, "down");
195
0
        xmlFree(str);
196
0
      }
197
0
    }
198
0
    else if (xmlStrcmp(attr->name, (const xmlChar*)"logicalchannel") == 0) {
199
0
      xmlChar* str = xmlNodeListGetString(root_element->doc, attr->children, 1);
200
0
      status = xml_get_int("logicalchannel", str, &channel, err, err_info);
201
0
      xmlFree(str);
202
0
      if (!status)
203
0
        goto end;
204
205
0
      switch (channel)
206
0
      {
207
0
      case 128: rec->rec_header.packet_header.pseudo_header.gsm_um.channel = GSM_UM_CHANNEL_SDCCH; break;
208
0
      case 112: rec->rec_header.packet_header.pseudo_header.gsm_um.channel = GSM_UM_CHANNEL_SACCH; break;
209
0
      case 176: rec->rec_header.packet_header.pseudo_header.gsm_um.channel = GSM_UM_CHANNEL_FACCH; break;
210
0
      case 96: rec->rec_header.packet_header.pseudo_header.gsm_um.channel = GSM_UM_CHANNEL_CCCH; break;
211
0
      case 80: rec->rec_header.packet_header.pseudo_header.gsm_um.channel = GSM_UM_CHANNEL_BCCH; break;
212
0
      default: rec->rec_header.packet_header.pseudo_header.gsm_um.channel = GSM_UM_CHANNEL_UNKNOWN; break;
213
0
      }
214
0
    }
215
0
    else if (xmlStrcmp(attr->name, (const xmlChar*)"data") == 0) {
216
0
      have_data = true; /* Found data */
217
0
      xmlChar* str = xmlNodeListGetString(root_element->doc, attr->children, 1);
218
0
      local_len = hex2bin(bufp, &databuf[MAX_PACKET_LEN], (char*)str);
219
0
      xmlFree(str);
220
0
      if (local_len == -1)
221
0
      {
222
0
        *err = WTAP_ERR_BAD_FILE;
223
0
        *err_info = ws_strdup_printf("dct3trace: record length %d too long", rec->rec_header.packet_header.caplen);
224
0
        status = false;
225
0
        goto end;
226
0
      }
227
228
0
    }
229
0
    else if (!rec->rec_header.packet_header.pseudo_header.gsm_um.uplink) {
230
      /* Parse downlink only fields */
231
232
0
      if (xmlStrcmp(attr->name, (const xmlChar*)"physicalchannel") == 0) {
233
0
        xmlChar* str = xmlNodeListGetString(root_element->doc, attr->children, 1);
234
0
        status = xml_get_int("physicalchannel", str, &tmp, err, err_info);
235
0
        xmlFree(str);
236
0
        if (!status)
237
0
          goto end;
238
239
0
        rec->rec_header.packet_header.pseudo_header.gsm_um.arfcn = tmp;
240
0
      }
241
0
      else if (xmlStrcmp(attr->name, (const xmlChar*)"sequence") == 0) {
242
0
        xmlChar* str = xmlNodeListGetString(root_element->doc, attr->children, 1);
243
0
        status = xml_get_int("sequence", str, &tmp, err, err_info);
244
0
        xmlFree(str);
245
0
        if (!status)
246
0
          goto end;
247
248
0
        rec->rec_header.packet_header.pseudo_header.gsm_um.tdma_frame = tmp;
249
0
      }
250
0
      else if (xmlStrcmp(attr->name, (const xmlChar*)"bsic") == 0) {
251
0
        xmlChar* str = xmlNodeListGetString(root_element->doc, attr->children, 1);
252
0
        status = xml_get_int("bsic", str, &tmp, err, err_info);
253
0
        xmlFree(str);
254
0
        if (!status)
255
0
          goto end;
256
257
0
        rec->rec_header.packet_header.pseudo_header.gsm_um.bsic = tmp;
258
0
      }
259
0
      else if (xmlStrcmp(attr->name, (const xmlChar*)"error") == 0) {
260
0
        xmlChar* str = xmlNodeListGetString(root_element->doc, attr->children, 1);
261
0
        status = xml_get_int("error", str, &tmp, err, err_info);
262
0
        xmlFree(str);
263
0
        if (!status)
264
0
          goto end;
265
266
0
        rec->rec_header.packet_header.pseudo_header.gsm_um.error = tmp;
267
0
      }
268
0
      else if (xmlStrcmp(attr->name, (const xmlChar*)"timeshift") == 0) {
269
0
        xmlChar* str = xmlNodeListGetString(root_element->doc, attr->children, 1);
270
0
        status = xml_get_int("timeshift", str, &tmp, err, err_info);
271
0
        xmlFree(str);
272
0
        if (!status)
273
0
          goto end;
274
275
0
        rec->rec_header.packet_header.pseudo_header.gsm_um.timeshift = tmp;
276
0
      }
277
0
    }
278
0
  }
279
280
0
  if (!have_data)
281
0
  {
282
0
    for (xmlNodePtr cur = root_element->children; cur != NULL; cur = cur->next) {
283
      /* Get data from l2 tag */
284
0
      if ((cur->type == XML_ELEMENT_NODE) && (xmlStrcmp(cur->name, (const xmlChar*)"l2") == 0)) {
285
0
        for (xmlAttrPtr attr = cur->properties; attr; attr = attr->next) {
286
287
          /* For uplink packets we might not get the raw L1, so have to recreate it from the L2 */
288
          /* Parse L2 header if didn't get data from L1 <l2 ...> */
289
0
          if (xmlStrcmp(attr->name, (const xmlChar*)"data") == 0) {
290
0
            int data_len;
291
292
0
            have_data = true; /* Found data */
293
294
            /*
295
             * We know we have no data already, so we know
296
             * we have enough room for the header.
297
             */
298
0
            switch(rec->rec_header.packet_header.pseudo_header.gsm_um.channel)
299
0
            {
300
0
            case GSM_UM_CHANNEL_SACCH:
301
0
            case GSM_UM_CHANNEL_FACCH:
302
0
            case GSM_UM_CHANNEL_SDCCH:
303
              /* Add LAPDm B header */
304
0
              memset(bufp, 0x1, 2);
305
0
              local_len = 3;
306
0
              break;
307
0
            default:
308
              /* Add LAPDm Bbis header */
309
0
              local_len = 1;
310
0
              break;
311
0
            }
312
0
            bufp += local_len;
313
314
0
            xmlChar* str = xmlNodeListGetString(cur->doc, attr->children, 1);
315
0
            data_len = hex2bin(bufp, &databuf[MAX_PACKET_LEN], (char*)str);
316
0
            xmlFree(str);
317
0
            if (data_len == -1)
318
0
            {
319
0
              *err = WTAP_ERR_BAD_FILE;
320
0
              *err_info = ws_strdup_printf("dct3trace: record length %d too long", rec->rec_header.packet_header.caplen);
321
0
              status = false;
322
0
              goto end;
323
0
            }
324
0
            local_len += data_len;
325
326
            /* Add LAPDm length byte */
327
0
            *(bufp - 1) = data_len << 2 | 0x1;
328
0
          }
329
0
        }
330
        /* There should be only a single "l2" child element
331
         * within a "l1" element, so break. (This keeps us
332
         * from writing to bufp a seconds time.) */
333
0
        break;
334
0
      }
335
0
    }
336
0
  }
337
338
0
  if (have_data) {
339
    /* We've got a full packet! */
340
0
    wtap_setup_packet_rec(rec, wth->file_encap);
341
0
    rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
342
0
    rec->presence_flags = 0; /* no time stamp, no separate "on the wire" length */
343
0
    rec->ts.secs = 0;
344
0
    rec->ts.nsecs = 0;
345
0
    rec->rec_header.packet_header.caplen = local_len;
346
0
    rec->rec_header.packet_header.len = local_len;
347
348
    /* Append data to the packet buffer */
349
0
    ws_buffer_append(&rec->data, databuf, rec->rec_header.packet_header.caplen);
350
0
  }
351
0
  else {
352
    /* If not got any data return error */
353
0
    *err = WTAP_ERR_BAD_FILE;
354
0
    *err_info = g_strdup("dct3trace: record without data");
355
0
    status = false;
356
0
  }
357
358
0
end:
359
0
  xmlFreeDoc(doc);
360
0
  return status;
361
0
}
362
363
/* Read from fh and store into buffer, until buffer contains needle.
364
 * Returns location of needle once found, or NULL if it's never found
365
 * (due to either EOF or read error).
366
 */
367
static uint8_t*
368
read_until(GByteArray* buffer, const unsigned char* needle, FILE_T fh, int* err, char** err_info)
369
0
{
370
0
  uint8_t read_buffer[RINGBUFFER_CHUNK_SIZE];
371
0
  uint8_t* found_it;
372
0
  int bytes_read = 0;
373
374
0
  while (NULL == (found_it = (uint8_t*)g_strstr_len((const char*)buffer->data, buffer->len, (const char*)needle))) {
375
0
    bytes_read = file_read(read_buffer, RINGBUFFER_CHUNK_SIZE, fh);
376
0
    if (bytes_read < 0) {
377
0
      *err = file_error(fh, err_info);
378
0
      break;
379
0
    }
380
0
    if (bytes_read == 0) {
381
0
      break;
382
0
    }
383
0
    g_byte_array_append(buffer, read_buffer, bytes_read);
384
0
  }
385
0
  return found_it;
386
0
}
387
388
/* Find the next packet and parse it; called from wtap_read(). */
389
static bool dct3trace_read(wtap *wth, wtap_rec *rec,
390
    int *err, char **err_info, int64_t *data_offset)
391
0
{
392
0
  dct3trace_file_info_t* file_info = (dct3trace_file_info_t*)wth->priv;
393
0
  uint8_t* buf_start;
394
0
  uint8_t* msg_start, * msg_end;
395
0
  unsigned msg_offset = 0;
396
0
  size_t msg_len = 0;
397
0
  bool status = false;
398
399
  /* Make sure we have a start and end of message in our buffer -- end first */
400
0
  msg_end = read_until(file_info->buffer, (const uint8_t*)dct3trace_magic_record_end, wth->fh, err, err_info);
401
0
  if (msg_end == NULL) {
402
0
    goto end;
403
0
  }
404
405
0
  buf_start = file_info->buffer->data;
406
  /* Now search backwards for the message start
407
   * (doing it this way should skip over any empty "<msg ... />" tags we have)
408
   */
409
0
  msg_start = (uint8_t*)g_strrstr_len((const char*)buf_start, (unsigned)(msg_end - buf_start), dct3trace_magic_record_start);
410
0
  if (msg_start == NULL || msg_start > msg_end) {
411
0
    *err_info = ws_strdup_printf("dct3trace: Found \"%s\" without matching \"%s\"", dct3trace_magic_record_end, dct3trace_magic_record_start);
412
0
    *err = WTAP_ERR_BAD_FILE;
413
0
    goto end;
414
0
  }
415
416
  /* We know we have a message, what's its offset from the buffer start? */
417
0
  msg_offset = (unsigned)(msg_start - buf_start);
418
0
  msg_end += CLEN(dct3trace_magic_record_end);
419
0
  msg_len = (unsigned)(msg_end - msg_start);
420
421
  /* Tell Wireshark to put us at the start of the "<msg" for seek_read later */
422
0
  *data_offset = file_info->start_offset + msg_offset;
423
424
  /* pass all of <l1....</l1> to dct3trace_get_packet() */
425
0
  status = dct3trace_get_packet(wth, rec, (const char*)msg_start, msg_len, err, err_info);
426
427
  /* Finally, shift our buffer to the end of this message to get ready for the next one.
428
   * Re-use msg_len to get the length of the data we're done with.
429
   */
430
0
  msg_len = msg_end - file_info->buffer->data;
431
0
  while (G_UNLIKELY(msg_len > UINT_MAX)) {
432
0
    g_byte_array_remove_range(file_info->buffer, 0, UINT_MAX);
433
0
    msg_len -= UINT_MAX;
434
0
  }
435
0
  g_byte_array_remove_range(file_info->buffer, 0, (unsigned)msg_len);
436
0
  file_info->start_offset += msg_len;
437
438
0
end:
439
0
  if (status == false) {
440
    /* There's no more to read. Empty out the buffer */
441
0
    g_byte_array_set_size(file_info->buffer, 0);
442
0
  }
443
444
0
  return status;
445
0
}
446
447
448
/* Used to read packets in random-access fashion */
449
static bool dct3trace_seek_read(wtap *wth, int64_t seek_off,
450
  wtap_rec *rec, int *err, char **err_info)
451
0
{
452
0
  dct3trace_file_info_t* file_info = (dct3trace_file_info_t*)wth->priv;
453
0
  bool status = false;
454
0
  uint8_t* msg_end;
455
0
  unsigned msg_len = 0;
456
457
  /* We stored the offset of the "<msg" for this packet */
458
0
  if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
459
0
    return false;
460
461
0
  msg_end = read_until(file_info->buffer, (const uint8_t*)dct3trace_magic_record_end, wth->random_fh, err, err_info);
462
0
  if (msg_end == NULL) {
463
0
    return false;
464
0
  }
465
0
  msg_end += CLEN(dct3trace_magic_record_end);
466
0
  msg_len = (unsigned)(msg_end - file_info->buffer->data);
467
468
0
  status = dct3trace_get_packet(wth, rec, (const char*)file_info->buffer->data, msg_len, err, err_info);
469
0
  g_byte_array_set_size(file_info->buffer, 0);
470
0
  return status;
471
0
}
472
473
/* Clean up any memory we allocated for dealing with this file.
474
 * Set as the subtype_close function in the file_open function below.
475
 * (wiretap frees wth->priv itself)
476
 */
477
static void
478
dct3trace_close(wtap* wth)
479
0
{
480
0
  dct3trace_file_info_t* file_info = (dct3trace_file_info_t*)wth->priv;
481
482
0
  if (file_info != NULL && file_info->buffer != NULL) {
483
0
    g_byte_array_free(file_info->buffer, true);
484
0
    file_info->buffer = NULL;
485
0
  }
486
0
}
487
488
wtap_open_return_val dct3trace_open(wtap* wth, int* err, char** err_info)
489
0
{
490
0
  char magic_buf[MAGIC_BUF_SIZE + 1];
491
0
  int bytes_read;
492
0
  const char* curr_pos;
493
0
  dct3trace_file_info_t* file_info;
494
0
  int64_t start_offset;
495
496
0
  start_offset = file_tell(wth->fh); // Most likely 0 but doesn't hurt to check
497
0
  bytes_read = file_read(magic_buf, MAGIC_BUF_SIZE, wth->fh);
498
499
0
  if (bytes_read < 0) {
500
0
    *err = file_error(wth->fh, err_info);
501
0
    return WTAP_OPEN_ERROR;
502
0
  }
503
0
  if (bytes_read == 0) {
504
0
    return WTAP_OPEN_NOT_MINE;
505
0
  }
506
507
0
  if (memcmp(magic_buf, c_xml_magic, CLEN(c_xml_magic)) != 0) {
508
0
    return WTAP_OPEN_NOT_MINE;
509
0
  }
510
511
0
  curr_pos = g_strstr_len(magic_buf, bytes_read, dct3trace_magic_line2);
512
0
  if (!curr_pos) {
513
0
    return WTAP_OPEN_NOT_MINE;
514
0
  }
515
0
  curr_pos += CLEN(dct3trace_magic_line2);
516
517
  /* Ok it's our file. From here we'll need to free memory */
518
0
  file_info = g_new0(dct3trace_file_info_t, 1);
519
0
  file_info->start_offset = start_offset + (curr_pos - magic_buf);
520
0
  file_info->buffer = g_byte_array_sized_new(RINGBUFFER_START_SIZE);
521
0
  g_byte_array_append(file_info->buffer, (const uint8_t*)curr_pos, (unsigned)(bytes_read - (curr_pos - magic_buf)));
522
523
0
  wth->file_type_subtype = dct3trace_file_type_subtype;
524
0
  wth->file_encap = WTAP_ENCAP_GSM_UM;
525
0
  wth->file_tsprec = WTAP_TSPREC_SEC;
526
0
  wth->subtype_read = dct3trace_read;
527
0
  wth->subtype_seek_read = dct3trace_seek_read;
528
0
  wth->subtype_close = dct3trace_close;
529
0
  wth->snapshot_length = 0;/* not known */
530
0
  wth->priv = (void*)file_info;
531
532
  /*
533
   * Add an IDB; we don't know how many interfaces were
534
   * involved, so we just say one interface, about which
535
   * we only know the link-layer type, snapshot length,
536
   * and time stamp resolution.
537
   */
538
0
  wtap_add_generated_idb(wth);
539
540
0
  return WTAP_OPEN_MINE;
541
0
}
542
543
static const struct supported_block_type dct3trace_blocks_supported[] = {
544
  /*
545
   * We support packet blocks, with no comments or other options.
546
   */
547
  { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
548
};
549
550
static const struct file_type_subtype_info dct3trace_info = {
551
  "Gammu DCT3 trace", "dct3trace", "xml", NULL,
552
  false, BLOCKS_SUPPORTED(dct3trace_blocks_supported),
553
  NULL, NULL, NULL
554
};
555
556
void register_dct3trace(void)
557
16
{
558
16
  dct3trace_file_type_subtype = wtap_register_file_type_subtype(&dct3trace_info);
559
560
  /*
561
   * Register name for backwards compatibility with the
562
   * wtap_filetypes table in Lua.
563
   */
564
16
  wtap_register_backwards_compatibility_lua_name("DCT3TRACE",
565
16
      dct3trace_file_type_subtype);
566
16
}
567
568
/*
569
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
570
 *
571
 * Local variables:
572
 * c-basic-offset: 8
573
 * tab-width: 8
574
 * indent-tabs-mode: t
575
 * End:
576
 *
577
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
578
 * :indentSize=8:tabSize=8:noTabs=false:
579
 */