Coverage Report

Created: 2025-08-04 07:15

/src/wireshark/epan/dissectors/packet-dcp-etsi.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-dcp-etsi.c
2
 * Routines for ETSI Distribution & Communication Protocol
3
 * Copyright 2006, British Broadcasting Corporation
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
8
 *
9
 * SPDX-License-Identifier: GPL-2.0-or-later
10
 *
11
 * Protocol info
12
 * Ref: ETSI DCP (ETSI TS 102 821)
13
 */
14
15
#include "config.h"
16
17
18
#include <epan/packet.h>
19
#include <epan/expert.h>
20
#include <epan/reassemble.h>
21
#include <epan/crc16-tvb.h>
22
#include <epan/reedsolomon.h>
23
#include <wsutil/array.h>
24
25
/* forward reference */
26
void proto_register_dcp_etsi(void);
27
void proto_reg_handoff_dcp_etsi(void);
28
static int dissect_af (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void* data);
29
static int dissect_pft (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void* data);
30
31
static dissector_handle_t dcp_etsi_handle;
32
static dissector_handle_t af_handle;
33
static dissector_handle_t pft_handle;
34
static dissector_handle_t tpl_handle;
35
36
static dissector_table_t dcp_dissector_table;
37
static dissector_table_t af_dissector_table;
38
static dissector_table_t tpl_dissector_table;
39
40
static int proto_dcp_etsi;
41
static int proto_af;
42
static int proto_pft;
43
static int proto_tpl;
44
static int hf_edcp_sync;
45
static int hf_edcp_len;
46
static int hf_edcp_seq;
47
static int hf_edcp_crcflag;
48
static int hf_edcp_maj;
49
static int hf_edcp_min;
50
static int hf_edcp_pt;
51
static int hf_edcp_crc;
52
static int hf_edcp_crc_ok;
53
/* static int hf_edcp_pft_pt; */
54
static int hf_edcp_pseq;
55
static int hf_edcp_findex;
56
static int hf_edcp_fcount;
57
static int hf_edcp_fecflag;
58
static int hf_edcp_addrflag;
59
static int hf_edcp_plen;
60
static int hf_edcp_rsk;
61
static int hf_edcp_rsz;
62
static int hf_edcp_source;
63
static int hf_edcp_dest;
64
static int hf_edcp_hcrc;
65
static int hf_edcp_hcrc_ok;
66
/* static int hf_edcp_c_max; */
67
/* static int hf_edcp_rx_min; */
68
/* static int hf_edcp_rs_corrected; */
69
static int hf_edcp_rs_ok;
70
static int hf_edcp_pft_payload;
71
72
static int hf_tpl_tlv;
73
/* static int hf_tpl_ptr; */
74
75
static int hf_edcp_fragments;
76
static int hf_edcp_fragment;
77
static int hf_edcp_fragment_overlap;
78
static int hf_edcp_fragment_overlap_conflicts;
79
static int hf_edcp_fragment_multiple_tails;
80
static int hf_edcp_fragment_too_long_fragment;
81
static int hf_edcp_fragment_error;
82
static int hf_edcp_fragment_count;
83
static int hf_edcp_reassembled_in;
84
static int hf_edcp_reassembled_length;
85
86
/* Initialize the subtree pointers */
87
static int ett_edcp;
88
static int ett_af;
89
static int ett_pft;
90
static int ett_tpl;
91
static int ett_edcp_fragment;
92
static int ett_edcp_fragments;
93
94
static expert_field ei_edcp_reassembly;
95
static expert_field ei_edcp_reassembly_info;
96
97
static reassembly_table dcp_reassembly_table;
98
99
static const fragment_items dcp_frag_items = {
100
/* Fragment subtrees */
101
  &ett_edcp_fragment,
102
  &ett_edcp_fragments,
103
/* Fragment fields */
104
  &hf_edcp_fragments,
105
  &hf_edcp_fragment,
106
  &hf_edcp_fragment_overlap,
107
  &hf_edcp_fragment_overlap_conflicts,
108
  &hf_edcp_fragment_multiple_tails,
109
  &hf_edcp_fragment_too_long_fragment,
110
  &hf_edcp_fragment_error,
111
  &hf_edcp_fragment_count,
112
/* Reassembled in field */
113
  &hf_edcp_reassembled_in,
114
/* Reassembled length field */
115
  &hf_edcp_reassembled_length,
116
/* Reassembled data field */
117
  NULL,
118
/* Tag */
119
  "Message fragments"
120
};
121
122
123
/** Dissect a DCP packet. Details follow
124
 *  here.
125
 *  \param[in,out] tvb The buffer containing the packet
126
 *  \param[in,out] pinfo The packet info structure
127
 *  \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
128
static void
129
 */
130
static int
131
dissect_dcp_etsi(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void * data _U_)
132
0
{
133
0
  uint8_t *sync;
134
0
  proto_tree *dcp_tree;
135
0
  proto_item *ti;
136
137
0
  if(tvb_captured_length(tvb) < 11)
138
0
    return false;
139
140
  /* Clear out stuff in the info column */
141
0
  col_clear(pinfo->cinfo, COL_INFO);
142
0
  col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCP (ETSI)");
143
    /*col_append_fstr (pinfo->cinfo, COL_INFO, " tvb %d", tvb_length(tvb));*/
144
145
0
  ti = proto_tree_add_item (tree, proto_dcp_etsi, tvb, 0, -1, ENC_NA);
146
0
  dcp_tree = proto_item_add_subtree (ti, ett_edcp);
147
148
0
  sync = tvb_get_string_enc(pinfo->pool, tvb, 0, 2, ENC_ASCII);
149
0
  dissector_try_string_with_data(dcp_dissector_table, (char*)sync, tvb, pinfo, dcp_tree, true, NULL);
150
151
0
  return tvb_captured_length(tvb);
152
0
}
153
154
/** Heuristic dissector for a DCP packet.
155
 *  \param[in,out] tvb The buffer containing the packet
156
 *  \param[in,out] pinfo The packet info structure
157
 *  \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
158
static void
159
 */
160
static bool
161
dissect_dcp_etsi_heur(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void * data)
162
1.43k
{
163
  /* 6.1 AF packet structure
164
   *
165
   * AF Header
166
   * SYNC    LEN     SEQ     AR      PT
167
   * 2 bytes 4 bytes 2 bytes 1 byte  1 byte
168
   *
169
   * SYNC: two-byte ASCII representation of "AF".
170
   * LEN: length of the payload, in bytes.
171
   * SEQ: sequence number
172
   * AR: AF protocol Revision - a field combining the CF, MAJ and MIN fields
173
   * CF: CRC Flag, 0 if the CRC field is not used
174
   * MAJ: major revision of the AF protocol in use, see clause 6.2.
175
   * MIN: minor revision of the AF protocol in use, see clause 6.2.
176
   * Protocol Type (PT): single byte encoding the protocol of the data carried in the payload.
177
   * For TAG Packets, the value shall be the ASCII representation of "T".
178
   *
179
   * 7.1 PFT fragment structure
180
   * PFT Header
181
   * 14, 16, 18 or 20 bytes (depending on options)                                                                              Optional present if FEC=1 Optional present if Addr = 1
182
   * Psync              Pseq            Findex          Fcount          FEC             HCRC            Addr    Plen    | RSk           RSz                     | Source        Dest
183
   * 16 bits    16 bits         24 bits         24 bits         1 bit   16 bits         1 bit   14 bits | 8 bits        8 bits          | 16 bits       16 bits
184
   *
185
   * Psync: the ASCII string "PF" is used as the synchronization word for the PFT Layer
186
   *
187
   * Don't accept this packet unless at least a full AF header present(10 bytes).
188
   * It should be possible to strengthen the heuristic further if need be.
189
   */
190
1.43k
  uint16_t word;
191
192
1.43k
  if(tvb_captured_length(tvb) < 11)
193
460
    return false;
194
195
974
  word = tvb_get_ntohs(tvb,0);
196
  /* Check for 'AF or 'PF' */
197
974
  if (word == 0x4146) {
198
    /* AF - check the version, which is only major 1, minor 0 */
199
2
    if ((tvb_get_uint8(tvb, 8) & 0x7F) != 0x10) {
200
1
      return false;
201
1
    }
202
    /* Tag packets are the only payload type */
203
1
    if (tvb_get_uint8(tvb, 9) != 'T') {
204
1
      return false;
205
1
    }
206
972
  } else if (word == 0x5046) {
207
    /* PFT - header length 14, 16, 18, or 20 depending on options.
208
     * Always contains CRC. */
209
5
    if (tvb_captured_length(tvb) < 14) {
210
1
      return false;
211
1
    }
212
4
    uint16_t plen = tvb_get_ntohs(tvb, 10);
213
4
    unsigned header_len = 14;
214
4
    if (plen & 0x8000) {
215
2
      header_len += 2;
216
2
    }
217
4
    if (plen & 0x4000) {
218
3
      header_len += 4;
219
3
    }
220
4
    if (tvb_captured_length(tvb) < header_len) {
221
2
      return false;
222
2
    }
223
2
    if (crc16_x25_ccitt_tvb(tvb, header_len) != 0x1D0F) {
224
2
      return false;
225
2
    }
226
967
  } else {
227
967
    return false;
228
967
  }
229
230
0
  dissect_dcp_etsi(tvb, pinfo, tree, data);
231
232
0
  return true;
233
974
}
234
235
0
#define PFT_RS_N_MAX 207
236
0
#define PFT_RS_K 255
237
0
#define PFT_RS_P (PFT_RS_K - PFT_RS_N_MAX)
238
239
240
static
241
void rs_deinterleave(const uint8_t *input, uint8_t *output, uint16_t plen, uint32_t fcount)
242
0
{
243
0
  unsigned fidx;
244
0
  for(fidx=0; fidx<fcount; fidx++)
245
0
  {
246
0
    int r;
247
0
    for (r=0; r<plen; r++)
248
0
    {
249
0
      output[fidx+r*fcount] = input[fidx*plen+r];
250
0
    }
251
0
  }
252
0
}
253
254
static
255
bool rs_correct_data(uint8_t *deinterleaved, uint8_t *output,
256
 uint32_t c_max, uint16_t rsk, uint16_t rsz _U_)
257
0
{
258
0
  uint32_t i, index_coded = 0, index_out = 0;
259
0
  int err_corr;
260
0
  for (i=0; i<c_max; i++)
261
0
  {
262
0
    memcpy(output+index_out, deinterleaved+index_coded, rsk);
263
0
    index_coded += rsk;
264
0
    memcpy(output+index_out+PFT_RS_N_MAX, deinterleaved+index_coded, PFT_RS_P);
265
0
    index_coded += PFT_RS_P;
266
0
    err_corr = eras_dec_rs(output+index_out, NULL, 0);
267
0
    if (err_corr<0) {
268
0
      return false;
269
0
    }
270
0
    index_out += rsk;
271
0
  }
272
0
  return true;
273
0
}
274
275
/* Don't attempt reassembly if we have a huge number of fragments. */
276
0
#define MAX_FRAGMENTS ((1 * 1024 * 1024) / sizeof(uint32_t))
277
/* If we missed more than this number of consecutive fragments,
278
   we don't attempt reassembly */
279
0
#define MAX_FRAG_GAP  1000
280
281
static tvbuff_t *
282
dissect_pft_fec_detailed(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
283
  uint32_t findex _U_,
284
  uint32_t fcount,
285
  uint16_t seq,
286
  int offset,
287
  uint16_t plen,
288
  bool fec _U_,
289
  uint16_t rsk,
290
  uint16_t rsz,
291
  fragment_head *fdx
292
)
293
0
{
294
0
  uint32_t decoded_size;
295
0
  uint32_t c_max;
296
0
  uint32_t rx_min;
297
0
  tvbuff_t *new_tvb=NULL;
298
299
0
  if (fcount > MAX_FRAGMENTS) {
300
0
    proto_tree_add_expert_format(tree, pinfo, &ei_edcp_reassembly, tvb , 0, -1, "[Reassembly of %d fragments not attempted]", fcount);
301
0
    return NULL;
302
0
  }
303
304
0
  decoded_size = fcount*plen;
305
0
  c_max = fcount*plen/(rsk+PFT_RS_P);  /* rounded down */
306
0
  rx_min = fcount - (c_max*PFT_RS_P/plen);
307
0
  if (fdx)
308
0
    new_tvb = process_reassembled_data (tvb, offset, pinfo,
309
0
                                        "Reassembled DCP (ETSI)",
310
0
                                        fdx, &dcp_frag_items,
311
0
                                        NULL, tree);
312
0
  else {
313
0
    unsigned fragments=0;
314
0
    uint32_t *got;
315
0
    fragment_item *fd;
316
0
    fragment_head *fd_head;
317
318
0
    proto_tree_add_expert_format(tree, pinfo, &ei_edcp_reassembly_info, tvb, 0, -1, "want %d, got %d need %d",
319
0
                           fcount, fragments, rx_min);
320
0
    got = (uint32_t *)wmem_alloc(pinfo->pool, fcount*sizeof(uint32_t));
321
322
    /* make a list of the findex (offset) numbers of the fragments we have */
323
0
    fd_head = fragment_get(&dcp_reassembly_table, pinfo, seq, NULL);
324
0
    if (fd_head) {
325
0
      for (fd = fd_head->next; fd != NULL && fragments < fcount; fd = fd->next) {
326
0
        if(fd->tvb_data) {
327
0
          got[fragments++] = fd->offset; /* this is the findex of the fragment */
328
0
        }
329
0
      }
330
0
    }
331
    /* have we got enough for Reed Solomon to try to correct ? */
332
0
    if(fragments>=rx_min) { /* yes, in theory */
333
0
      unsigned i,current_findex;
334
0
      fragment_head *frag=NULL;
335
0
      uint8_t *dummy_data = (uint8_t*) wmem_alloc0 (pinfo->pool, plen);
336
0
      tvbuff_t *dummytvb = tvb_new_real_data(dummy_data, plen, plen);
337
      /* try and decode with missing fragments */
338
0
      proto_tree_add_expert_format(tree, pinfo, &ei_edcp_reassembly_info, tvb, 0, -1, "want %d, got %d need %d",
339
0
                               fcount, fragments, rx_min);
340
      /* fill the fragment table with empty fragments */
341
0
      current_findex = 0;
342
0
      for(i=0; i<fragments; i++) {
343
0
        unsigned next_fragment_we_have = got[i];
344
0
        if (next_fragment_we_have > MAX_FRAGMENTS) {
345
0
          proto_tree_add_expert_format(tree, pinfo, &ei_edcp_reassembly, tvb , 0, -1, "[Reassembly of %d fragments not attempted]", next_fragment_we_have);
346
0
          return NULL;
347
0
        }
348
0
        if (next_fragment_we_have-current_findex > MAX_FRAG_GAP) {
349
0
          proto_tree_add_expert_format(tree, pinfo, &ei_edcp_reassembly, tvb, 0, -1,
350
0
              "[Missing %d consecutive packets. Don't attempt reassembly]",
351
0
              next_fragment_we_have-current_findex);
352
0
          return NULL;
353
0
        }
354
0
        for(; current_findex<next_fragment_we_have; current_findex++) {
355
0
          frag = fragment_add_seq_check (&dcp_reassembly_table,
356
0
                                         dummytvb, 0, pinfo, seq, NULL,
357
0
                                         current_findex, plen, (current_findex+1!=fcount));
358
0
        }
359
0
        current_findex++; /* skip over the fragment we have */
360
0
      }
361
0
      tvb_free(dummytvb);
362
363
0
      if(frag)
364
0
        new_tvb = process_reassembled_data (tvb, offset, pinfo,
365
0
                                            "Reassembled DCP (ETSI)",
366
0
                                            frag, &dcp_frag_items,
367
0
                                            NULL, tree);
368
0
    }
369
0
  }
370
0
  if(new_tvb && tvb_captured_length(new_tvb) > 0) {
371
0
    bool decoded;
372
0
    tvbuff_t *dtvb = NULL;
373
0
    const uint8_t *input = tvb_get_ptr(new_tvb, 0, -1);
374
0
    uint32_t reassembled_size = tvb_captured_length(new_tvb);
375
0
    uint8_t *deinterleaved = (uint8_t*) wmem_alloc(pinfo->pool, reassembled_size);
376
0
    uint8_t *output = (uint8_t*) wmem_alloc(pinfo->pool, decoded_size);
377
0
    rs_deinterleave(input, deinterleaved, plen, fcount);
378
379
0
    dtvb = tvb_new_child_real_data(tvb, deinterleaved, reassembled_size, reassembled_size);
380
0
    add_new_data_source(pinfo, dtvb, "Deinterleaved");
381
382
0
    decoded = rs_correct_data(deinterleaved, output, c_max, rsk, rsz);
383
0
    proto_tree_add_boolean (tree, hf_edcp_rs_ok, tvb, offset, 2, decoded);
384
385
0
    new_tvb = tvb_new_child_real_data(dtvb, output, decoded_size, decoded_size);
386
0
    add_new_data_source(pinfo, new_tvb, "RS Error Corrected Data");
387
0
  }
388
0
  return new_tvb;
389
0
}
390
391
392
/** Handle a PFT packet which has the fragmentation header. This uses the
393
 * standard wireshark methods for reassembling fragments. If FEC is used,
394
 * the FEC is handled too. For the moment, all the fragments must be
395
 * available but this could be improved.
396
 *  \param[in,out] tvb The buffer containing the current fragment
397
 *  \param[in,out] pinfo The packet info structure
398
 *  \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
399
 *  \param[in] findex the fragment count
400
 *  \param[in] fcount the number of fragments
401
 *  \param[in] seq the sequence number of the reassembled packet
402
 *  \param[in] offset the offset into the tvb of the fragment
403
 *  \param[in] plen the length of each fragment
404
 *  \param[in] fec is fec used
405
 *  \param[in] rsk the number of useful bytes in each chunk
406
 *  \param[in] rsz the number of padding bytes in each chunk
407
 */
408
static tvbuff_t *
409
dissect_pft_fragmented(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
410
  uint32_t findex,
411
  uint32_t fcount,
412
  uint16_t seq,
413
  int offset,
414
  uint16_t plen,
415
  bool fec,
416
  uint16_t rsk,
417
  uint16_t rsz
418
)
419
0
{
420
0
  bool first, last;
421
0
  tvbuff_t *new_tvb=NULL;
422
0
  fragment_head *frag_edcp = NULL;
423
0
  pinfo->fragmented = true;
424
0
  first = findex == 0;
425
0
  last = fcount == (findex+1);
426
0
  frag_edcp = fragment_add_seq_check (
427
0
    &dcp_reassembly_table,
428
0
    tvb, offset,
429
0
    pinfo, seq, NULL,
430
0
    findex,
431
0
    plen,
432
0
    !last);
433
0
  if(fec) {
434
0
    new_tvb = dissect_pft_fec_detailed(
435
0
      tvb, pinfo, tree, findex, fcount, seq, offset, plen, fec, rsk, rsz, frag_edcp
436
0
      );
437
0
  } else {
438
0
    new_tvb = process_reassembled_data (tvb, offset, pinfo,
439
0
                                        "Reassembled DCP (ETSI)",
440
0
                                        frag_edcp, &dcp_frag_items,
441
0
                                        NULL, tree);
442
0
  }
443
0
  if(new_tvb) {
444
0
    col_append_str (pinfo->cinfo, COL_INFO, " (Message Reassembled)");
445
0
  } else {
446
0
    if(last) {
447
0
      col_append_str (pinfo->cinfo, COL_INFO, " (Message Reassembly failure)");
448
0
    } else {
449
0
      col_append_fstr (pinfo->cinfo, COL_INFO, " (Message fragment %u)", findex);
450
0
    }
451
0
  }
452
0
  if(first)
453
0
    col_append_str (pinfo->cinfo, COL_INFO, " (first)");
454
0
  if(last)
455
0
   col_append_str (pinfo->cinfo, COL_INFO, " (last)");
456
0
  return new_tvb;
457
0
  }
458
459
/** Dissect a PFT packet. Details follow
460
 *  here.
461
 *  \param[in,out] tvb The buffer containing the packet
462
 *  \param[in,out] pinfo The packet info structure
463
 *  \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
464
 */
465
static int
466
dissect_pft(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void* data)
467
0
{
468
0
  uint16_t plen;
469
0
  int offset = 0;
470
0
  uint16_t seq, payload_len;
471
0
  uint32_t findex, fcount;
472
0
  proto_tree *pft_tree;
473
0
  proto_item *ti, *li;
474
0
  tvbuff_t *next_tvb = NULL;
475
0
  bool fec = false;
476
0
  uint16_t rsk=0, rsz=0;
477
478
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCP-PFT");
479
480
0
  ti = proto_tree_add_item (tree, proto_pft, tvb, 0, -1, ENC_NA);
481
0
  pft_tree = proto_item_add_subtree (ti, ett_pft);
482
0
  proto_tree_add_item (pft_tree, hf_edcp_sync, tvb, offset, 2, ENC_ASCII);
483
484
0
  offset += 2;
485
0
  seq = tvb_get_ntohs (tvb, offset);
486
0
  proto_tree_add_item (pft_tree, hf_edcp_pseq, tvb, offset, 2, ENC_BIG_ENDIAN);
487
488
0
  offset += 2;
489
0
  findex = tvb_get_ntoh24 (tvb, offset);
490
0
  proto_tree_add_item (pft_tree, hf_edcp_findex, tvb, offset, 3, ENC_BIG_ENDIAN);
491
492
0
  offset += 3;
493
0
  fcount = tvb_get_ntoh24 (tvb, offset);
494
0
  proto_tree_add_item (pft_tree, hf_edcp_fcount, tvb, offset, 3, ENC_BIG_ENDIAN);
495
496
0
  offset += 3;
497
0
  plen = tvb_get_ntohs (tvb, offset);
498
0
  payload_len = plen & 0x3fff;
499
0
  proto_tree_add_item (pft_tree, hf_edcp_fecflag, tvb, offset, 2, ENC_BIG_ENDIAN);
500
0
  proto_tree_add_item (pft_tree, hf_edcp_addrflag, tvb, offset, 2, ENC_BIG_ENDIAN);
501
0
  li = proto_tree_add_item (pft_tree, hf_edcp_plen, tvb, offset, 2, ENC_BIG_ENDIAN);
502
503
0
  offset += 2;
504
0
  if (plen & 0x8000) {
505
0
    fec = true;
506
0
    rsk = tvb_get_uint8 (tvb, offset);
507
0
    proto_tree_add_item (pft_tree, hf_edcp_rsk, tvb, offset, 1, ENC_BIG_ENDIAN);
508
0
    offset += 1;
509
0
    rsz = tvb_get_uint8 (tvb, offset);
510
0
    proto_tree_add_item (pft_tree, hf_edcp_rsz, tvb, offset, 1, ENC_BIG_ENDIAN);
511
0
    offset += 1;
512
0
  }
513
0
  if (plen & 0x4000) {
514
0
    proto_tree_add_item (pft_tree, hf_edcp_source, tvb, offset, 2, ENC_BIG_ENDIAN);
515
0
    offset += 2;
516
0
    proto_tree_add_item (pft_tree, hf_edcp_dest, tvb, offset, 2, ENC_BIG_ENDIAN);
517
0
    offset += 2;
518
0
  }
519
0
  if (tree) {
520
0
    proto_item *ci = NULL;
521
0
    unsigned header_len = offset+2;
522
0
    uint16_t c = crc16_x25_ccitt_tvb(tvb, header_len);
523
0
    ci = proto_tree_add_item (pft_tree, hf_edcp_hcrc, tvb, offset, 2, ENC_BIG_ENDIAN);
524
0
    proto_item_append_text(ci, " (%s)", (c==0x1D0F)?"Ok":"bad");
525
0
    proto_tree_add_boolean(pft_tree, hf_edcp_hcrc_ok, tvb, offset, 2, c==0x1D0F);
526
0
  }
527
0
  offset += 2;
528
0
  if (fcount > 1) {             /* fragmented*/
529
0
    bool save_fragmented = pinfo->fragmented;
530
0
    uint16_t real_len = tvb_captured_length(tvb)-offset;
531
0
    proto_tree_add_item (pft_tree, hf_edcp_pft_payload, tvb, offset, real_len, ENC_NA);
532
0
    if(real_len != payload_len || real_len == 0) {
533
0
      proto_item_append_text(li, " (length error (%d))", real_len);
534
0
    }
535
0
    else {
536
0
      next_tvb = dissect_pft_fragmented(tvb, pinfo, pft_tree, findex, fcount,
537
0
                                        seq, offset, real_len, fec, rsk, rsz);
538
0
    }
539
0
    pinfo->fragmented = save_fragmented;
540
0
  } else {
541
0
    next_tvb = tvb_new_subset_remaining (tvb, offset);
542
0
  }
543
0
  if(next_tvb) {
544
0
    dissect_af(next_tvb, pinfo, tree, data);
545
0
  }
546
0
  return tvb_captured_length(tvb);
547
0
}
548
549
/** Dissect an AF Packet. Parse an AF packet, checking the CRC if the CRC valid
550
 * flag is set and calling any registered sub dissectors on the payload type.
551
 * Currently only a payload type 'T' is defined which is the tag packet layer.
552
 * If any others are defined then they can register themselves.
553
 *  \param[in,out] tvb The buffer containing the packet
554
 *  \param[in,out] pinfo The packet info structure
555
 *  \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
556
 */
557
static int
558
dissect_af (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void* data _U_)
559
0
{
560
0
  int offset = 0;
561
0
  proto_item *ti;
562
0
  proto_item *li = NULL;
563
0
  proto_item *ci;
564
0
  proto_tree *af_tree;
565
0
  uint8_t ver, pt;
566
0
  uint32_t payload_len;
567
0
  tvbuff_t *next_tvb = NULL;
568
569
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCP-AF");
570
571
0
  ti = proto_tree_add_item (tree, proto_af, tvb, 0, -1, ENC_NA);
572
0
  af_tree = proto_item_add_subtree (ti, ett_af);
573
0
  proto_tree_add_item (af_tree, hf_edcp_sync, tvb, offset, 2, ENC_ASCII);
574
575
0
  offset += 2;
576
0
  payload_len = tvb_get_ntohl(tvb, offset);
577
0
  if (tree) {
578
0
    uint32_t real_payload_len = tvb_captured_length(tvb)-12;
579
0
    li = proto_tree_add_item (af_tree, hf_edcp_len, tvb, offset, 4, ENC_BIG_ENDIAN);
580
0
    if(real_payload_len < payload_len) {
581
0
      proto_item_append_text (li, " (wrong len claims %d is %d)",
582
0
      payload_len, real_payload_len
583
0
      );
584
0
    } else if(real_payload_len > payload_len) {
585
0
      proto_item_append_text (li, " (%d bytes in packet after end of AF frame)",
586
0
      real_payload_len-payload_len
587
0
      );
588
0
    }
589
0
  }
590
0
  offset += 4;
591
0
  proto_tree_add_item (af_tree, hf_edcp_seq, tvb, offset, 2, ENC_BIG_ENDIAN);
592
0
  offset += 2;
593
0
  ver = tvb_get_uint8 (tvb, offset);
594
0
  proto_tree_add_item (af_tree, hf_edcp_crcflag, tvb, offset, 1, ENC_BIG_ENDIAN);
595
0
  proto_tree_add_item (af_tree, hf_edcp_maj, tvb, offset, 1, ENC_BIG_ENDIAN);
596
0
  proto_tree_add_item (af_tree, hf_edcp_min, tvb, offset, 1, ENC_BIG_ENDIAN);
597
598
0
  offset += 1;
599
0
  pt = tvb_get_uint8 (tvb, offset);
600
0
  proto_tree_add_item (af_tree, hf_edcp_pt, tvb, offset, 1, ENC_ASCII);
601
0
  offset += 1;
602
0
  next_tvb = tvb_new_subset_length(tvb, offset, payload_len);
603
0
  offset += payload_len;
604
0
  ci = proto_tree_add_item (af_tree, hf_edcp_crc, tvb, offset, 2, ENC_BIG_ENDIAN);
605
0
  if (ver & 0x80) { /* crc valid */
606
0
    unsigned len = offset+2;
607
0
    uint16_t c = crc16_x25_ccitt_tvb(tvb, len);
608
0
    proto_item_append_text(ci, " (%s)", (c==0x1D0F)?"Ok":"bad");
609
0
    proto_tree_add_boolean(af_tree, hf_edcp_crc_ok, tvb, offset, 2, c==0x1D0F);
610
0
  }
611
  /*offset += 2;*/
612
613
0
  dissector_try_uint(af_dissector_table, pt, next_tvb, pinfo, tree);
614
0
  return tvb_captured_length(tvb);
615
0
}
616
617
/** Dissect the Tag Packet Layer.
618
 *  Split the AF packet into its tag items. Each tag item has a 4 character
619
 *  tag, a length in bits and a value. The *ptr tag is dissected in the routine.
620
 *  All other tags are listed and may be handled by other dissectors.
621
 *  Child dissectors are tied to the parent tree, not to this tree, so that
622
 *  they appear at the same level as DCP.
623
 *  \param[in,out] tvb The buffer containing the packet
624
 *  \param[in,out] pinfo The packet info structure
625
 *  \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
626
 */
627
static int
628
dissect_tpl(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void* data _U_)
629
0
{
630
0
  proto_tree *tpl_tree;
631
0
  unsigned offset=0;
632
0
  proto_item *ti;
633
634
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCP-TPL");
635
636
0
  ti = proto_tree_add_item (tree, proto_tpl, tvb, 0, -1, ENC_NA);
637
0
  tpl_tree = proto_item_add_subtree (ti, ett_tpl);
638
639
0
  while(offset<tvb_reported_length(tvb)) {
640
0
    tvbuff_t *next_tvb;
641
0
    uint32_t bits;
642
0
    uint32_t bytes;
643
0
    char *tag = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset, 4, ENC_ASCII);
644
0
    bits = tvb_get_ntohl(tvb, offset+4);
645
0
    bytes = bits / 8;
646
0
    if(bits % 8)
647
0
      bytes++;
648
649
0
    proto_tree_add_bytes_format(tpl_tree, hf_tpl_tlv, tvb,
650
0
            offset, 8+bytes, NULL,
651
0
            "%s (%u bits)", tag, bits);
652
653
0
    next_tvb = tvb_new_subset_length(tvb, offset+8, bytes);
654
0
    dissector_try_string_with_data(tpl_dissector_table, tag, next_tvb, pinfo, tree, true, NULL);
655
656
0
    offset += (8+bytes);
657
0
  }
658
659
0
  return tvb_captured_length(tvb);
660
0
}
661
662
void
663
proto_reg_handoff_dcp_etsi (void)
664
14
{
665
14
  heur_dissector_add("udp", dissect_dcp_etsi_heur, "DCP (ETSI) over UDP", "dcp_etsi_udp", proto_dcp_etsi, HEURISTIC_ENABLE);
666
14
  dissector_add_for_decode_as("udp.port", dcp_etsi_handle);
667
14
  dissector_add_string("dcp-etsi.sync", "AF", af_handle);
668
14
  dissector_add_string("dcp-etsi.sync", "PF", pft_handle);
669
  /* if there are ever other payload types ...*/
670
14
  dissector_add_uint("dcp-af.pt", 'T', tpl_handle);
671
14
}
672
673
void
674
proto_register_dcp_etsi (void)
675
14
{
676
14
  static hf_register_info hf_edcp[] = {
677
14
    {&hf_edcp_sync,
678
14
     {"sync", "dcp-etsi.sync",
679
14
      FT_STRING, BASE_NONE, NULL, 0,
680
14
      "AF or PF", HFILL}
681
14
     }
682
14
    };
683
14
  static hf_register_info hf_af[] = {
684
14
    {&hf_edcp_len,
685
14
     {"length", "dcp-af.len",
686
14
      FT_UINT32, BASE_DEC, NULL, 0,
687
14
      "length in bytes of the payload", HFILL}
688
14
     },
689
14
    {&hf_edcp_seq,
690
14
     {"frame count", "dcp-af.seq",
691
14
      FT_UINT16, BASE_DEC, NULL, 0,
692
14
      "Logical Frame Number", HFILL}
693
14
     },
694
14
    {&hf_edcp_crcflag,
695
14
     {"crc flag", "dcp-af.crcflag",
696
14
      FT_BOOLEAN, 8, NULL, 0x80,
697
14
      "Frame is protected by CRC", HFILL}
698
14
     },
699
14
    {&hf_edcp_maj,
700
14
     {"Major Revision", "dcp-af.maj",
701
14
      FT_UINT8, BASE_DEC, NULL, 0x70,
702
14
      "Major Protocol Revision", HFILL}
703
14
     },
704
14
    {&hf_edcp_min,
705
14
     {"Minor Revision", "dcp-af.min",
706
14
      FT_UINT8, BASE_DEC, NULL, 0x0f,
707
14
      "Minor Protocol Revision", HFILL}
708
14
     },
709
14
    {&hf_edcp_pt,
710
14
     {"Payload Type", "dcp-af.pt",
711
14
      FT_STRING, BASE_NONE, NULL, 0,
712
14
      "T means Tag Packets, all other values reserved", HFILL}
713
14
     },
714
14
    {&hf_edcp_crc,
715
14
     {"CRC", "dcp-af.crc",
716
14
      FT_UINT16, BASE_HEX, NULL, 0,
717
14
      NULL, HFILL}
718
14
     },
719
14
    {&hf_edcp_crc_ok,
720
14
     {"CRC OK", "dcp-af.crc_ok",
721
14
      FT_BOOLEAN, BASE_NONE, NULL, 0x0,
722
14
      "AF CRC OK", HFILL}
723
14
     }
724
14
    };
725
726
14
  static hf_register_info hf_pft[] = {
727
#if 0
728
    {&hf_edcp_pft_pt,
729
     {"Sub-protocol", "dcp-pft.pt",
730
      FT_UINT8, BASE_DEC, NULL, 0,
731
      "Always AF", HFILL}
732
     },
733
#endif
734
14
    {&hf_edcp_pseq,
735
14
     {"Sequence No", "dcp-pft.seq",
736
14
      FT_UINT16, BASE_DEC, NULL, 0,
737
14
      "PFT Sequence No", HFILL}
738
14
     },
739
14
    {&hf_edcp_findex,
740
14
     {"Fragment Index", "dcp-pft.findex",
741
14
      FT_UINT24, BASE_DEC, NULL, 0,
742
14
      "Index of the fragment within one AF Packet", HFILL}
743
14
     },
744
14
    {&hf_edcp_fcount,
745
14
     {"Fragment Count", "dcp-pft.fcount",
746
14
      FT_UINT24, BASE_DEC, NULL, 0,
747
14
      "Number of fragments produced from this AF Packet", HFILL}
748
14
     },
749
14
    {&hf_edcp_fecflag,
750
14
     {"FEC", "dcp-pft.fec",
751
14
      FT_BOOLEAN, 16, NULL, 0x8000,
752
14
      "When set the optional RS header is present", HFILL}
753
14
     },
754
14
    {&hf_edcp_addrflag,
755
14
     {"Addr", "dcp-pft.addr",
756
14
      FT_BOOLEAN, 16, NULL, 0x4000,
757
14
      "When set the optional transport header is present", HFILL}
758
14
     },
759
14
    {&hf_edcp_plen,
760
14
     {"fragment length", "dcp-pft.len",
761
14
      FT_UINT16, BASE_DEC, NULL, 0x3fff,
762
14
      "length in bytes of the payload of this fragment", HFILL}
763
14
     },
764
14
    {&hf_edcp_rsk,
765
14
     {"RSk", "dcp-pft.rsk",
766
14
      FT_UINT8, BASE_DEC, NULL, 0,
767
14
      "The length of the Reed Solomon data word", HFILL}
768
14
     },
769
14
    {&hf_edcp_rsz,
770
14
     {"RSz", "dcp-pft.rsz",
771
14
      FT_UINT8, BASE_DEC, NULL, 0,
772
14
      "The number of padding bytes in the last Reed Solomon block", HFILL}
773
14
     },
774
14
    {&hf_edcp_source,
775
14
     {"source addr", "dcp-pft.source",
776
14
      FT_UINT16, BASE_DEC, NULL, 0,
777
14
      "PFT source identifier", HFILL}
778
14
     },
779
14
    {&hf_edcp_dest,
780
14
     {"dest addr", "dcp-pft.dest",
781
14
      FT_UINT16, BASE_DEC, NULL, 0,
782
14
      "PFT destination identifier", HFILL}
783
14
     },
784
14
    {&hf_edcp_hcrc,
785
14
     {"header CRC", "dcp-pft.crc",
786
14
      FT_UINT16, BASE_HEX, NULL, 0,
787
14
      "PFT Header CRC", HFILL}
788
14
     },
789
14
    {&hf_edcp_hcrc_ok,
790
14
     {"PFT CRC OK", "dcp-pft.crc_ok",
791
14
      FT_BOOLEAN, BASE_NONE, NULL, 0x0,
792
14
      "PFT Header CRC OK", HFILL}
793
14
     },
794
14
    {&hf_edcp_fragments,
795
14
     {"Message fragments", "dcp-pft.fragments",
796
14
      FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL}},
797
14
    {&hf_edcp_fragment,
798
14
     {"Message fragment", "dcp-pft.fragment",
799
14
      FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL}},
800
14
    {&hf_edcp_fragment_overlap,
801
14
     {"Message fragment overlap", "dcp-pft.fragment.overlap",
802
14
      FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}},
803
14
    {&hf_edcp_fragment_overlap_conflicts,
804
14
     {"Message fragment overlapping with conflicting data",
805
14
      "dcp-pft.fragment.overlap.conflicts",
806
14
      FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}},
807
14
    {&hf_edcp_fragment_multiple_tails,
808
14
     {"Message has multiple tail fragments",
809
14
      "dcp-pft.fragment.multiple_tails",
810
14
      FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}},
811
14
    {&hf_edcp_fragment_too_long_fragment,
812
14
     {"Message fragment too long", "dcp-pft.fragment.too_long_fragment",
813
14
      FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}},
814
14
    {&hf_edcp_fragment_error,
815
14
     {"Message defragmentation error", "dcp-pft.fragment.error",
816
14
      FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL}},
817
14
    {&hf_edcp_fragment_count,
818
14
     {"Message fragment count", "dcp-pft.fragment.count",
819
14
      FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL}},
820
14
    {&hf_edcp_reassembled_in,
821
14
     {"Reassembled in", "dcp-pft.reassembled.in",
822
14
      FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL}},
823
14
    {&hf_edcp_reassembled_length,
824
14
     {"Reassembled DCP (ETSI) length", "dcp-pft.reassembled.length",
825
14
      FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL}},
826
#if 0
827
    {&hf_edcp_c_max,
828
     {"C max", "dcp-pft.cmax",
829
      FT_UINT16, BASE_DEC, NULL, 0,
830
      "Maximum number of RS chunks sent", HFILL}
831
     },
832
    {&hf_edcp_rx_min,
833
     {"Rx min", "dcp-pft.rxmin",
834
      FT_UINT16, BASE_DEC, NULL, 0,
835
      "Minimum number of fragments needed for RS decode", HFILL}
836
     },
837
    {&hf_edcp_rs_corrected,
838
     {"RS Symbols Corrected", "dcp-pft.rs_corrected",
839
      FT_INT16, BASE_DEC, NULL, 0,
840
      "Number of symbols corrected by RS decode or -1 for failure", HFILL}
841
     },
842
#endif
843
14
    {&hf_edcp_rs_ok,
844
14
     {"RS decode OK", "dcp-pft.rs_ok",
845
14
      FT_BOOLEAN, BASE_NONE, NULL, 0x0,
846
14
      "successfully decoded RS blocks", HFILL}
847
14
     },
848
14
    {&hf_edcp_pft_payload,
849
14
     {"payload", "dcp-pft.payload",
850
14
      FT_BYTES, BASE_NONE, NULL, 0,
851
14
      "PFT Payload", HFILL}
852
14
    }
853
14
  };
854
855
14
  static hf_register_info hf_tpl[] = {
856
14
    {&hf_tpl_tlv,
857
14
     {"tag", "dcp-tpl.tlv",
858
14
      FT_BYTES, BASE_NONE, NULL, 0,
859
14
      "Tag Packet", HFILL}
860
14
     },
861
#if 0
862
    {&hf_tpl_ptr,
863
     {"Type", "dcp-tpl.ptr",
864
      FT_STRING, BASE_NONE, NULL, 0,
865
      "Protocol Type & Revision", HFILL}
866
     }
867
#endif
868
14
    };
869
870
/* Setup protocol subtree array */
871
14
  static int *ett[] = {
872
14
    &ett_edcp,
873
14
    &ett_af,
874
14
    &ett_pft,
875
14
    &ett_tpl,
876
14
    &ett_edcp_fragment,
877
14
    &ett_edcp_fragments
878
14
  };
879
880
14
  static ei_register_info ei[] = {
881
14
     { &ei_edcp_reassembly, { "dcp-etsi.reassembly_failed", PI_REASSEMBLE, PI_ERROR, "Reassembly failed", EXPFILL }},
882
14
     { &ei_edcp_reassembly_info, { "dcp-etsi.reassembly_info", PI_REASSEMBLE, PI_CHAT, "Reassembly information", EXPFILL }},
883
14
  };
884
885
14
  expert_module_t* expert_dcp_etsi;
886
887
14
  proto_dcp_etsi = proto_register_protocol ("ETSI Distribution & Communication Protocol (for DRM)",     /* name */
888
14
                                            "DCP (ETSI)",       /* short name */
889
14
                                            "dcp-etsi"  /* abbrev */
890
14
    );
891
14
  proto_af = proto_register_protocol ("DCP Application Framing Layer", "DCP-AF", "dcp-af");
892
14
  proto_pft = proto_register_protocol ("DCP Protection, Fragmentation & Transport Layer", "DCP-PFT", "dcp-pft");
893
14
  proto_tpl = proto_register_protocol ("DCP Tag Packet Layer", "DCP-TPL", "dcp-tpl");
894
895
14
  proto_register_field_array (proto_dcp_etsi, hf_edcp, array_length (hf_edcp));
896
14
  proto_register_field_array (proto_af, hf_af, array_length (hf_af));
897
14
  proto_register_field_array (proto_pft, hf_pft, array_length (hf_pft));
898
14
  proto_register_field_array (proto_tpl, hf_tpl, array_length (hf_tpl));
899
14
  proto_register_subtree_array (ett, array_length (ett));
900
14
  expert_dcp_etsi = expert_register_protocol(proto_dcp_etsi);
901
14
  expert_register_field_array(expert_dcp_etsi, ei, array_length(ei));
902
903
  /* subdissector code */
904
14
  dcp_dissector_table = register_dissector_table("dcp-etsi.sync",
905
14
            "DCP Sync", proto_dcp_etsi, FT_STRING, STRING_CASE_SENSITIVE);
906
14
  af_dissector_table = register_dissector_table("dcp-af.pt",
907
14
            "DCP-AF Payload Type", proto_dcp_etsi, FT_UINT8, BASE_DEC);
908
909
14
  tpl_dissector_table = register_dissector_table("dcp-tpl.ptr",
910
14
            "DCP-TPL Protocol Type & Revision", proto_dcp_etsi, FT_STRING, STRING_CASE_SENSITIVE);
911
912
14
  reassembly_table_register (&dcp_reassembly_table,
913
14
                         &addresses_reassembly_table_functions);
914
915
14
  dcp_etsi_handle = register_dissector("dcp-etsi", dissect_dcp_etsi, proto_dcp_etsi);
916
14
  af_handle = register_dissector("dcp-af", dissect_af, proto_af);
917
14
  pft_handle = register_dissector("dcp-pft", dissect_pft, proto_pft);
918
14
  tpl_handle = register_dissector("dcp-tpl", dissect_tpl, proto_tpl);
919
14
}
920
921
/*
922
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
923
 *
924
 * Local variables:
925
 * c-basic-offset: 2
926
 * tab-width: 8
927
 * indent-tabs-mode: nil
928
 * End:
929
 *
930
 * vi: set shiftwidth=2 tabstop=8 expandtab:
931
 * :indentSize=2:tabSize=8:noTabs=true:
932
 */