Coverage Report

Created: 2025-12-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-pgm.c
Line
Count
Source
1
/* packet-pgm.c
2
 * Routines for PGM packet disassembly, RFC 3208
3
 *
4
 * Copyright (c) 2000 by Talarian Corp
5
 * Rewritten by Jaap Keuter
6
 *
7
 * Wireshark - Network traffic analyzer
8
 * By Gerald Combs <gerald@wireshark.org>
9
 * Copyright 1999 Gerald Combs
10
 *
11
 * SPDX-License-Identifier: GPL-2.0-or-later
12
 */
13
14
#include "config.h"
15
16
#include <epan/packet.h>
17
#include <epan/in_cksum.h>
18
#include <epan/prefs.h>
19
#include <epan/ptvcursor.h>
20
#include <epan/expert.h>
21
#include <epan/tfs.h>
22
#include <wsutil/array.h>
23
24
#include "packet-iana-data.h"
25
/*
26
 * RFC 3208
27
 *
28
 * Plus https://dl.acm.org/doi/pdf/10.1145/347057.347390 for PGMCC,
29
 * whence the ACK packet type comes; there are some I-Ds for PGMCC,
30
 * draft-ietf-rmt-bb-pgmcc-00 through draft-ietf-rmt-bb-pgmcc-03,
31
 * but none of them give any description of the packet-level
32
 * changes to PGM, unlike the paper in question, which merely gives
33
 * an *insufficient* description of said changes.  In particular,
34
 * it doesn't indicate what the packet type code for ACK is.
35
 *
36
 * Luigi Rizzo's PGMCC code for FreeBSD, at
37
 *
38
 *     https://web.archive.org/web/20020302084503/http://info.iet.unipi.it/~luigi/pgm-code/
39
 *
40
 * uses 0x0b (11) for ACK, as does tcpdump's dissector.
41
 *
42
 * A capture file attached to
43
 *
44
 *     https://gitlab.com/wireshark/wireshark/-/issues/4798
45
 *
46
 * has packets that use 0x0d for ACK, as did this dissector, and
47
 * as does OpenPGM at https://github.com/steve-o/openpgm.  It may
48
 * be that some proprietary PGMCC implementations, such as SmartPGM,
49
 * do so as well.
50
 *
51
 * We use *both*, treating *either one* as a PGMCC ACK, pending
52
 * more information, such as an answer to
53
 *
54
 *    https://github.com/steve-o/openpgm/issues/75.
55
 */
56
57
void proto_register_pgm(void);
58
void proto_reg_handoff_pgm(void);
59
60
static dissector_handle_t pgm_handle;
61
62
/*
63
 * Flag to control whether to check the PGM checksum.
64
 */
65
static bool pgm_check_checksum = true;
66
67
/* constants for hdr types */
68
19
#define PGM_SPM_PCKT  0x00
69
250
#define PGM_ODATA_PCKT  0x04
70
260
#define PGM_RDATA_PCKT  0x05
71
4
#define PGM_NAK_PCKT  0x08
72
7
#define PGM_NNAK_PCKT  0x09
73
10
#define PGM_NCF_PCKT 0x0A
74
12
#define PGM_POLL_PCKT 0x01
75
8
#define PGM_POLR_PCKT 0x02
76
77
/*
78
 * See above comment for why there are two values for the PGMCC
79
 * ACK packet's packet type.
80
 */
81
2
#define PGM_ACK_PCKT 0x0B
82
4
#define PGM_ACK2_PCKT 0x0D
83
84
/* option flags (main PGM header) */
85
452
#define PGM_OPT 0x01
86
240
#define PGM_OPT_NETSIG 0x02
87
240
#define PGM_OPT_VAR_PKTLEN 0x40
88
240
#define PGM_OPT_PARITY 0x80
89
90
/* option types */
91
205
#define PGM_OPT_LENGTH 0x00
92
1.60k
#define PGM_OPT_END 0x80
93
25
#define PGM_OPT_FRAGMENT 0x01
94
31
#define PGM_OPT_NAK_LIST 0x02
95
18
#define PGM_OPT_JOIN 0x03
96
401
#define PGM_OPT_REDIRECT 0x07
97
#define PGM_OPT_SYN 0x0D
98
#define PGM_OPT_FIN 0x0E
99
#define PGM_OPT_RST 0x0F
100
116
#define PGM_OPT_PARITY_PRM 0x08
101
37
#define PGM_OPT_PARITY_GRP 0x09
102
#define PGM_OPT_CURR_TGSIZE 0x0A
103
26
#define PGM_OPT_PGMCC_DATA  0x12
104
44
#define PGM_OPT_PGMCC_FEEDBACK  0x13
105
175
#define PGM_OPT_NAK_BO_IVL 0x04
106
391
#define PGM_OPT_NAK_BO_RNG 0x05
107
108
/* POLL subtypes */
109
#define PGM_POLL_GENERAL 0x0
110
#define PGM_POLL_DLR 0x1
111
112
/* OPX bit values */
113
#define PGM_OPX_IGNORE  0x00
114
#define PGM_OPX_INVAL 0x01
115
#define PGM_OPX_DISCARD 0x10
116
117
27
#define PGM_OPT_NAK_LIST_SIZE 4
118
119
/*
120
 * To squeeze the whole option into 255 bytes, we
121
 * can only have 62 in the list
122
 */
123
#define PGM_MAX_NAK_LIST_SZ (62)
124
125
11
#define PGM_OPT_JOIN_SIZE 8
126
125
#define PGM_OPT_PARITY_PRM_SIZE 8
127
128
/* OPT_PARITY_PRM P and O bits */
129
95
#define PGM_OPT_PARITY_PRM_PRO 0x2
130
95
#define PGM_OPT_PARITY_PRM_OND 0x1
131
132
37
#define PGM_OPT_PARITY_GRP_SIZE 8
133
#define PGM_OPT_CURR_TGSIZE_SIZE 8
134
26
#define PGM_OPT_PGMCC_DATA_SIZE 16
135
44
#define PGM_OPT_PGMCC_FEEDBACK_SIZE 16
136
323
#define PGM_OPT_NAK_BO_IVL_SIZE 12
137
721
#define PGM_OPT_NAK_BO_RNG_SIZE 12
138
747
#define PGM_OPT_REDIRECT_SIZE 12
139
27
#define PGM_OPT_FRAGMENT_SIZE 16
140
141
static int proto_pgm;
142
static int ett_pgm;
143
static int ett_pgm_optbits;
144
static int ett_pgm_opts;
145
static int ett_pgm_spm;
146
static int ett_pgm_data;
147
static int ett_pgm_nak;
148
static int ett_pgm_poll;
149
static int ett_pgm_polr;
150
static int ett_pgm_ack;
151
static int ett_pgm_opts_join;
152
static int ett_pgm_opts_parityprm;
153
static int ett_pgm_opts_paritygrp;
154
static int ett_pgm_opts_naklist;
155
static int ett_pgm_opts_ccdata;
156
static int ett_pgm_opts_nak_bo_ivl;
157
static int ett_pgm_opts_nak_bo_rng;
158
static int ett_pgm_opts_redirect;
159
static int ett_pgm_opts_fragment;
160
161
static int hf_pgm_main_sport;
162
static int hf_pgm_main_dport;
163
static int hf_pgm_port;
164
static int hf_pgm_main_type;
165
static int hf_pgm_main_opts;
166
static int hf_pgm_main_opts_opt;
167
static int hf_pgm_main_opts_netsig;
168
static int hf_pgm_main_opts_varlen;
169
static int hf_pgm_main_opts_parity;
170
static int hf_pgm_main_cksum;
171
static int hf_pgm_main_cksum_status;
172
static int hf_pgm_main_gsi;
173
static int hf_pgm_main_tsdulen;
174
static int hf_pgm_spm_sqn;
175
static int hf_pgm_spm_lead;
176
static int hf_pgm_spm_trail;
177
static int hf_pgm_spm_pathafi;
178
static int hf_pgm_spm_res;
179
static int hf_pgm_spm_path;
180
static int hf_pgm_spm_path6;
181
/* static int hf_pgm_data_sqn; */
182
/* static int hf_pgm_data_trail; */
183
static int hf_pgm_nak_sqn;
184
static int hf_pgm_nak_srcafi;
185
static int hf_pgm_nak_srcres;
186
static int hf_pgm_nak_src;
187
static int hf_pgm_nak_src6;
188
static int hf_pgm_nak_grpafi;
189
static int hf_pgm_nak_grpres;
190
static int hf_pgm_nak_grp;
191
static int hf_pgm_nak_grp6;
192
static int hf_pgm_poll_sqn;
193
static int hf_pgm_poll_round;
194
static int hf_pgm_poll_subtype;
195
static int hf_pgm_poll_pathafi;
196
static int hf_pgm_poll_res;
197
static int hf_pgm_poll_path;
198
static int hf_pgm_poll_path6;
199
static int hf_pgm_poll_backoff_ivl;
200
static int hf_pgm_poll_rand_str;
201
static int hf_pgm_poll_matching_bmask;
202
static int hf_pgm_polr_sqn;
203
static int hf_pgm_polr_round;
204
static int hf_pgm_polr_res;
205
static int hf_pgm_ack_sqn;
206
static int hf_pgm_ack_bitmap;
207
208
static int hf_pgm_opt_type;
209
static int hf_pgm_opt_len;
210
static int hf_pgm_opt_tlen;
211
212
static int hf_pgm_genopt_end;
213
static int hf_pgm_genopt_type;
214
static int hf_pgm_genopt_len;
215
static int hf_pgm_genopt_opx;
216
217
static int hf_pgm_opt_join_res;
218
static int hf_pgm_opt_join_minjoin;
219
220
static int hf_pgm_opt_parity_prm_po;
221
static int hf_pgm_opt_parity_prm_prmtgsz;
222
223
static int hf_pgm_opt_parity_grp_res;
224
static int hf_pgm_opt_parity_grp_prmgrp;
225
226
static int hf_pgm_opt_nak_res;
227
static int hf_pgm_opt_nak_list;
228
229
static int hf_pgm_opt_ccdata_res;
230
static int hf_pgm_opt_ccdata_tsp;
231
static int hf_pgm_opt_ccdata_afi;
232
static int hf_pgm_opt_ccdata_res2;
233
static int hf_pgm_opt_ccdata_acker;
234
static int hf_pgm_opt_ccdata_acker6;
235
236
static int hf_pgm_opt_ccfeedbk_res;
237
static int hf_pgm_opt_ccfeedbk_tsp;
238
static int hf_pgm_opt_ccfeedbk_afi;
239
static int hf_pgm_opt_ccfeedbk_lossrate;
240
static int hf_pgm_opt_ccfeedbk_acker;
241
static int hf_pgm_opt_ccfeedbk_acker6;
242
243
static int hf_pgm_opt_nak_bo_ivl_res;
244
static int hf_pgm_opt_nak_bo_ivl_bo_ivl;
245
static int hf_pgm_opt_nak_bo_ivl_bo_ivl_sqn;
246
247
static int hf_pgm_opt_nak_bo_rng_res;
248
static int hf_pgm_opt_nak_bo_rng_min_bo_ivl;
249
static int hf_pgm_opt_nak_bo_rng_max_bo_ivl;
250
251
static int hf_pgm_opt_redirect_res;
252
static int hf_pgm_opt_redirect_afi;
253
static int hf_pgm_opt_redirect_res2;
254
static int hf_pgm_opt_redirect_dlr;
255
static int hf_pgm_opt_redirect_dlr6;
256
257
static int hf_pgm_opt_fragment_res;
258
static int hf_pgm_opt_fragment_first_sqn;
259
static int hf_pgm_opt_fragment_offset;
260
static int hf_pgm_opt_fragment_total_length;
261
262
static expert_field ei_pgm_genopt_len;
263
static expert_field ei_pgm_opt_tlen;
264
static expert_field ei_pgm_opt_type;
265
static expert_field ei_address_format_invalid;
266
static expert_field ei_pgm_main_cksum;
267
268
static dissector_table_t subdissector_table;
269
static heur_dissector_list_t heur_subdissector_list;
270
271
272
static const char *
273
optsstr(wmem_allocator_t *pool, uint8_t opts)
274
246
{
275
246
  char *msg;
276
246
  int   returned_length, idx = 0;
277
246
  const int MAX_STR_LEN = 256;
278
279
246
  if (opts == 0)
280
20
    return "";
281
282
226
  msg=(char *)wmem_alloc(pool, MAX_STR_LEN);
283
226
  if (opts & PGM_OPT){
284
192
    returned_length = snprintf(&msg[idx], MAX_STR_LEN-idx, "Present");
285
192
    idx += MIN(returned_length, MAX_STR_LEN-idx);
286
192
  }
287
226
  if (opts & PGM_OPT_NETSIG){
288
139
    returned_length = snprintf(&msg[idx], MAX_STR_LEN-idx, "%sNetSig", (!idx)?"":",");
289
139
    idx += MIN(returned_length, MAX_STR_LEN-idx);
290
139
  }
291
226
  if (opts & PGM_OPT_VAR_PKTLEN){
292
121
    returned_length = snprintf(&msg[idx], MAX_STR_LEN-idx, "%sVarLen", (!idx)?"":",");
293
121
    idx += MIN(returned_length, MAX_STR_LEN-idx);
294
121
  }
295
226
  if (opts & PGM_OPT_PARITY){
296
90
    returned_length = snprintf(&msg[idx], MAX_STR_LEN-idx, "%sParity", (!idx)?"":",");
297
90
    idx += MIN(returned_length, MAX_STR_LEN-idx);
298
90
  }
299
226
  if (!idx) {
300
5
    snprintf(&msg[idx], MAX_STR_LEN-idx, "0x%x", opts);
301
5
  }
302
226
  return msg;
303
246
}
304
static const char *
305
paritystr(wmem_allocator_t *pool, uint8_t parity)
306
100
{
307
100
  char *msg;
308
100
  int returned_length, idx = 0;
309
100
  const int MAX_STR_LEN = 256;
310
311
100
  if (parity == 0)
312
5
    return "";
313
314
95
  msg=(char *)wmem_alloc(pool, MAX_STR_LEN);
315
95
  if (parity & PGM_OPT_PARITY_PRM_PRO){
316
19
    returned_length = snprintf(&msg[idx], MAX_STR_LEN-idx, "Pro-active");
317
19
    idx += MIN(returned_length, MAX_STR_LEN-idx);
318
19
  }
319
95
  if (parity & PGM_OPT_PARITY_PRM_OND){
320
27
    returned_length = snprintf(&msg[idx], MAX_STR_LEN-idx, "%sOn-demand", (!idx)?"":",");
321
27
    idx += MIN(returned_length, MAX_STR_LEN-idx);
322
27
  }
323
95
  if (!idx) {
324
64
    snprintf(&msg[idx], MAX_STR_LEN-idx, "0x%x", parity);
325
64
  }
326
95
  return msg;
327
100
}
328
329
static const value_string opt_vals[] = {
330
  { PGM_OPT_LENGTH,   "Length" },
331
  { PGM_OPT_END,      "End" },
332
  { PGM_OPT_FRAGMENT,   "Fragment" },
333
  { PGM_OPT_NAK_LIST,   "NakList" },
334
  { PGM_OPT_JOIN,     "Join" },
335
  { PGM_OPT_REDIRECT,   "ReDirect" },
336
  { PGM_OPT_SYN,      "Syn" },
337
  { PGM_OPT_FIN,      "Fin" },
338
  { PGM_OPT_RST,      "Rst" },
339
  { PGM_OPT_PARITY_PRM,   "ParityPrm" },
340
  { PGM_OPT_PARITY_GRP,   "ParityGrp" },
341
  { PGM_OPT_CURR_TGSIZE,    "CurrTgsiz" },
342
  { PGM_OPT_PGMCC_DATA,   "CcData" },
343
  { PGM_OPT_PGMCC_FEEDBACK, "CcFeedBack" },
344
  { PGM_OPT_NAK_BO_IVL,   "NakBackOffIvl" },
345
  { PGM_OPT_NAK_BO_RNG,   "NakBackOffRng" },
346
  { 0,                   NULL }
347
};
348
349
static const value_string opx_vals[] = {
350
  { PGM_OPX_IGNORE,  "Ignore" },
351
  { PGM_OPX_INVAL,   "Inval" },
352
  { PGM_OPX_DISCARD, "DisCard" },
353
  { 0,               NULL }
354
};
355
356
#define TLV_CHECK(ett) \
357
1.52k
  opt_tree = proto_tree_add_subtree_format(opts_tree, tvb, ptvcursor_current_offset(cursor), genopts_len, \
358
1.52k
            ett, &tf, "Option: %s, Length: %u", \
359
1.52k
            val_to_str(pinfo->pool, genopts_type, opt_vals, "Unknown (0x%02x)"), genopts_len); \
360
1.52k
  if (genopts_len < 4) { \
361
53
    expert_add_info_format(pinfo, tf, &ei_pgm_genopt_len, \
362
53
          "Length %u invalid, must be >= 4", genopts_len); \
363
53
    return; \
364
53
  } \
365
1.52k
  if (opts_total_len < genopts_len) { \
366
18
    expert_add_info_format(pinfo, tf, &ei_pgm_genopt_len, \
367
18
          "Length %u > remaining total options length", genopts_len); \
368
18
    return; \
369
18
  } \
370
371
372
static void
373
dissect_pgmopts(ptvcursor_t* cursor, packet_info *pinfo, const char *pktname)
374
182
{
375
182
  proto_item *tf, *ti, *ti_len;
376
182
  proto_tree *opts_tree = NULL;
377
182
  proto_tree *opt_tree  = NULL;
378
182
  tvbuff_t   *tvb       = ptvcursor_tvbuff(cursor);
379
380
182
  bool theend = false;
381
382
182
  uint16_t opts_total_len;
383
182
  uint8_t genopts_type;
384
182
  uint8_t genopts_len;
385
182
  uint8_t opts_type;
386
387
182
  opts_tree = proto_tree_add_subtree_format(ptvcursor_tree(cursor), tvb, ptvcursor_current_offset(cursor), -1,
388
182
    ett_pgm_opts, &tf, "%s Options", pktname);
389
182
  ptvcursor_set_tree(cursor, opts_tree);
390
182
  opts_type = tvb_get_uint8(tvb, ptvcursor_current_offset(cursor));
391
182
  ti = ptvcursor_add(cursor, hf_pgm_opt_type, 1, ENC_BIG_ENDIAN);
392
182
  if (opts_type != PGM_OPT_LENGTH) {
393
23
    expert_add_info_format(pinfo, ti, &ei_pgm_opt_type,
394
23
        "%s Options - initial option is %s, should be %s",
395
23
        pktname,
396
23
        val_to_str(pinfo->pool, opts_type, opt_vals, "Unknown (0x%02x)"),
397
23
        val_to_str(pinfo->pool, PGM_OPT_LENGTH, opt_vals, "Unknown (0x%02x)"));
398
23
    return;
399
23
  }
400
159
  ptvcursor_add(cursor, hf_pgm_opt_len, 1, ENC_BIG_ENDIAN);
401
159
  opts_total_len = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor));
402
159
  proto_item_append_text(tf, " (Total Length %d)", opts_total_len);
403
159
  proto_item_set_len(tf, opts_total_len);
404
159
  ti_len = ptvcursor_add(cursor, hf_pgm_opt_tlen, 2, ENC_BIG_ENDIAN);
405
159
  if (opts_total_len < 4) {
406
4
    expert_add_info_format(pinfo, ti_len, &ei_pgm_opt_tlen,
407
4
      "%s Options (Total Length %u - invalid, must be >= 4)",
408
4
      pktname, opts_total_len);
409
4
    return;
410
4
  }
411
412
1.59k
  for (opts_total_len -= 4; !theend && opts_total_len != 0;){
413
1.55k
    if (opts_total_len < 4) {
414
2
      expert_add_info_format(pinfo, ti_len, &ei_pgm_opt_tlen,
415
2
        "Remaining total options length doesn't have enough for an options header");
416
2
      break;
417
2
    }
418
419
1.55k
    genopts_type = tvb_get_uint8(tvb, ptvcursor_current_offset(cursor));
420
1.55k
    genopts_len = tvb_get_uint8(tvb, ptvcursor_current_offset(cursor)+1);
421
422
1.55k
    if (genopts_type & PGM_OPT_END)  {
423
46
      genopts_type &= ~PGM_OPT_END;
424
46
      theend = true;
425
46
    }
426
427
1.55k
    switch(genopts_type) {
428
18
    case PGM_OPT_JOIN:{
429
18
      TLV_CHECK(ett_pgm_opts_join);
430
10
      ptvcursor_set_tree(cursor, opt_tree);
431
432
10
      ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN);
433
10
      ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN);
434
435
10
      if (genopts_len < PGM_OPT_JOIN_SIZE) {
436
1
        proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb,
437
1
          ptvcursor_current_offset(cursor), 1, genopts_len,
438
1
          "%u (bogus, must be >= %u)",
439
1
          genopts_len, PGM_OPT_JOIN_SIZE);
440
1
        break;
441
1
      }
442
9
      ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN);
443
9
      ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN);
444
9
      ptvcursor_add(cursor, hf_pgm_opt_join_res, 1, ENC_BIG_ENDIAN);
445
9
      ptvcursor_add(cursor, hf_pgm_opt_join_minjoin, 4, ENC_BIG_ENDIAN);
446
447
9
      break;
448
10
    }
449
116
    case PGM_OPT_PARITY_PRM:{
450
116
      uint8_t optdata_po;
451
452
116
      TLV_CHECK(ett_pgm_opts_parityprm);
453
113
      ptvcursor_set_tree(cursor, opt_tree);
454
455
113
      ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN);
456
113
      ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN);
457
458
459
113
      if (genopts_len < PGM_OPT_PARITY_PRM_SIZE) {
460
12
        proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, ptvcursor_tvbuff(cursor),
461
12
          ptvcursor_current_offset(cursor), 1, genopts_len,
462
12
          "%u (bogus, must be >= %u)",
463
12
          genopts_len, PGM_OPT_PARITY_PRM_SIZE);
464
12
        break;
465
12
      }
466
101
      ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN);
467
101
      ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN);
468
101
      optdata_po = tvb_get_uint8(tvb, ptvcursor_current_offset(cursor));
469
101
      proto_tree_add_uint_format_value(opt_tree, hf_pgm_opt_parity_prm_po, tvb,
470
101
        ptvcursor_current_offset(cursor), 1, optdata_po, "%s (0x%x)",
471
101
        paritystr(pinfo->pool, optdata_po), optdata_po);
472
101
      ptvcursor_advance(cursor, 1);
473
474
101
      ptvcursor_add(cursor, hf_pgm_opt_parity_prm_prmtgsz, 4, ENC_BIG_ENDIAN);
475
476
101
      break;
477
113
    }
478
37
    case PGM_OPT_PARITY_GRP:{
479
37
      TLV_CHECK(ett_pgm_opts_paritygrp);
480
35
      ptvcursor_set_tree(cursor, opt_tree);
481
482
35
      ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN);
483
35
      ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN);
484
485
35
      if (genopts_len < PGM_OPT_PARITY_GRP_SIZE) {
486
2
        proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb,
487
2
          ptvcursor_current_offset(cursor), 1, genopts_len,
488
2
          "%u (bogus, must be >= %u)",
489
2
          genopts_len, PGM_OPT_PARITY_GRP_SIZE);
490
2
        break;
491
2
      }
492
33
      ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN);
493
33
      ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN);
494
33
      ptvcursor_add(cursor, hf_pgm_opt_parity_grp_res, 1, ENC_BIG_ENDIAN);
495
33
      ptvcursor_add(cursor, hf_pgm_opt_parity_grp_prmgrp, 4, ENC_BIG_ENDIAN);
496
497
33
      break;
498
35
    }
499
31
    case PGM_OPT_NAK_LIST:{
500
31
      uint8_t optdata_len;
501
31
      uint32_t naklist[PGM_MAX_NAK_LIST_SZ+1];
502
31
      wmem_strbuf_t *nakbuf;
503
31
      bool firsttime;
504
31
      int i, j, naks;
505
506
31
      TLV_CHECK(ett_pgm_opts_naklist);
507
27
      ptvcursor_set_tree(cursor, opt_tree);
508
509
27
      ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN);
510
27
      ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN);
511
512
27
      optdata_len = tvb_get_uint8(tvb, ptvcursor_current_offset(cursor));
513
27
      ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN);
514
27
      ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN);
515
27
      ptvcursor_add(cursor, hf_pgm_opt_nak_res, 1, ENC_BIG_ENDIAN);
516
517
27
      optdata_len -= PGM_OPT_NAK_LIST_SIZE;
518
27
      tvb_memcpy(tvb, (uint8_t *)naklist, ptvcursor_current_offset(cursor), optdata_len);
519
27
      firsttime = true;
520
27
      naks = (int)(optdata_len/sizeof(uint32_t));
521
27
      nakbuf = wmem_strbuf_new_sized(pinfo->pool, 64);
522
27
      j = 0;
523
      /*
524
       * Print out 8 per line
525
       */
526
421
      for (i=0; i < naks; i++) {
527
394
        wmem_strbuf_append_printf(nakbuf, "0x%x ", g_ntohl(naklist[i]));
528
394
        if ((++j % 8) == 0) {
529
41
          if (firsttime) {
530
15
            proto_tree_add_bytes_format(opt_tree,
531
15
              hf_pgm_opt_nak_list, tvb, ptvcursor_current_offset(cursor), j*4,
532
15
              NULL, "List(%d): %s", naks, wmem_strbuf_get_str(nakbuf));
533
15
            firsttime = false;
534
26
          } else {
535
26
            proto_tree_add_bytes_format_value(opt_tree,
536
26
              hf_pgm_opt_nak_list, tvb, ptvcursor_current_offset(cursor), j*4,
537
26
              NULL, "%s", wmem_strbuf_get_str(nakbuf));
538
26
          }
539
41
          wmem_strbuf_truncate(nakbuf, 0);
540
41
          ptvcursor_advance(cursor, j*4);
541
41
          j = 0;
542
41
        }
543
394
      }
544
27
      if (j) {
545
20
        if (firsttime) {
546
8
          proto_tree_add_bytes_format(opt_tree,
547
8
            hf_pgm_opt_nak_list, tvb, ptvcursor_current_offset(cursor), j*4,
548
8
            NULL, "List(%d): %s", naks, wmem_strbuf_get_str(nakbuf));
549
12
        } else {
550
12
          proto_tree_add_bytes_format_value(opt_tree,
551
12
            hf_pgm_opt_nak_list, tvb, ptvcursor_current_offset(cursor), j*4,
552
12
            NULL, "%s", wmem_strbuf_get_str(nakbuf));
553
12
        }
554
20
        ptvcursor_advance(cursor, j*4);
555
20
      }
556
27
      wmem_strbuf_destroy(nakbuf);
557
27
      break;
558
28
    }
559
26
    case PGM_OPT_PGMCC_DATA:{
560
26
      uint16_t optdata_afi;
561
562
26
      TLV_CHECK(ett_pgm_opts_ccdata);
563
25
      ptvcursor_set_tree(cursor, opt_tree);
564
565
25
      ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN);
566
25
      ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN);
567
568
25
      if (genopts_len < PGM_OPT_PGMCC_DATA_SIZE) {
569
1
        proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb,
570
1
          ptvcursor_current_offset(cursor), 1, genopts_len,
571
1
          "%u (bogus, must be >= %u)",
572
1
          genopts_len, PGM_OPT_PGMCC_DATA_SIZE);
573
1
        break;
574
1
      }
575
24
      ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN);
576
24
      ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN);
577
24
      ptvcursor_add(cursor, hf_pgm_opt_ccdata_res, 1, ENC_BIG_ENDIAN);
578
24
      ptvcursor_add(cursor, hf_pgm_opt_ccdata_tsp, 4, ENC_BIG_ENDIAN);
579
24
      optdata_afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor));
580
24
      ti = ptvcursor_add(cursor, hf_pgm_opt_ccdata_afi, 2, ENC_BIG_ENDIAN);
581
24
      ptvcursor_add(cursor, hf_pgm_opt_ccdata_res2, 2, ENC_BIG_ENDIAN);
582
583
24
      switch (optdata_afi) {
584
585
0
      case AFNUM_IP:
586
0
        ptvcursor_add(cursor, hf_pgm_opt_ccdata_acker, 4, ENC_BIG_ENDIAN);
587
0
        break;
588
589
0
      case AFNUM_IP6:
590
0
        ptvcursor_add(cursor, hf_pgm_opt_ccdata_acker6, 16, ENC_NA);
591
0
        break;
592
593
24
      default:
594
24
        expert_add_info(pinfo, ti, &ei_address_format_invalid);
595
24
        break;
596
24
      }
597
598
24
      break;
599
24
    }
600
44
    case PGM_OPT_PGMCC_FEEDBACK:{
601
44
      uint16_t optdata_afi;
602
603
44
      TLV_CHECK(ett_pgm_opts_ccdata);
604
43
      ptvcursor_set_tree(cursor, opt_tree);
605
606
43
      ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN);
607
43
      ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN);
608
609
43
      if (genopts_len < PGM_OPT_PGMCC_FEEDBACK_SIZE) {
610
1
        proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb,
611
1
          ptvcursor_current_offset(cursor), 1, genopts_len,
612
1
          "%u (bogus, must be >= %u)",
613
1
          genopts_len, PGM_OPT_PGMCC_FEEDBACK_SIZE);
614
1
        break;
615
1
      }
616
42
      ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN);
617
42
      ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN);
618
42
      ptvcursor_add(cursor, hf_pgm_opt_ccfeedbk_res, 1, ENC_BIG_ENDIAN);
619
42
      ptvcursor_add(cursor, hf_pgm_opt_ccfeedbk_tsp, 4, ENC_BIG_ENDIAN);
620
42
      optdata_afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor));
621
42
      ti = ptvcursor_add(cursor, hf_pgm_opt_ccfeedbk_afi, 2, ENC_BIG_ENDIAN);
622
42
      ptvcursor_add(cursor, hf_pgm_opt_ccfeedbk_lossrate, 2, ENC_BIG_ENDIAN);
623
624
42
      switch (optdata_afi) {
625
626
0
      case AFNUM_IP:
627
0
        ptvcursor_add(cursor, hf_pgm_opt_ccfeedbk_acker, 4, ENC_BIG_ENDIAN);
628
0
        break;
629
630
0
      case AFNUM_IP6:
631
0
        ptvcursor_add(cursor, hf_pgm_opt_ccfeedbk_acker6, 16, ENC_NA);
632
0
        break;
633
634
42
      default:
635
42
        expert_add_info(pinfo, ti, &ei_address_format_invalid);
636
42
        break;
637
42
      }
638
639
42
      break;
640
42
    }
641
175
    case PGM_OPT_NAK_BO_IVL:{
642
175
      TLV_CHECK(ett_pgm_opts_nak_bo_ivl);
643
171
      ptvcursor_set_tree(cursor, opt_tree);
644
645
171
      ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN);
646
171
      ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN);
647
648
171
      if (genopts_len < PGM_OPT_NAK_BO_IVL_SIZE) {
649
152
        proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb,
650
152
          ptvcursor_current_offset(cursor), 1, genopts_len,
651
152
          "%u (bogus, must be >= %u)",
652
152
          genopts_len, PGM_OPT_NAK_BO_IVL_SIZE);
653
152
        break;
654
152
      }
655
19
      ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN);
656
19
      ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN);
657
19
      ptvcursor_add(cursor, hf_pgm_opt_nak_bo_ivl_res, 1, ENC_BIG_ENDIAN);
658
19
      ptvcursor_add(cursor, hf_pgm_opt_nak_bo_ivl_bo_ivl, 4, ENC_BIG_ENDIAN);
659
19
      ptvcursor_add(cursor, hf_pgm_opt_nak_bo_ivl_bo_ivl_sqn, 4, ENC_BIG_ENDIAN);
660
661
19
      break;
662
171
    }
663
391
    case PGM_OPT_NAK_BO_RNG:{
664
391
      TLV_CHECK(ett_pgm_opts_nak_bo_rng);
665
387
      ptvcursor_set_tree(cursor, opt_tree);
666
667
387
      ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN);
668
387
      ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN);
669
670
387
      if (genopts_len < PGM_OPT_NAK_BO_RNG_SIZE) {
671
334
        proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb,
672
334
          ptvcursor_current_offset(cursor), 1, genopts_len,
673
334
          "%u (bogus, must be >= %u)",
674
334
          genopts_len, PGM_OPT_NAK_BO_RNG_SIZE);
675
334
        break;
676
334
      }
677
53
      ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN);
678
53
      ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN);
679
53
      ptvcursor_add(cursor, hf_pgm_opt_nak_bo_rng_res, 1, ENC_BIG_ENDIAN);
680
53
      ptvcursor_add(cursor, hf_pgm_opt_nak_bo_rng_min_bo_ivl, 4, ENC_BIG_ENDIAN);
681
53
      ptvcursor_add(cursor, hf_pgm_opt_nak_bo_rng_max_bo_ivl, 4, ENC_BIG_ENDIAN);
682
683
53
      break;
684
387
    }
685
401
    case PGM_OPT_REDIRECT:{
686
401
      uint16_t optdata_afi;
687
688
401
      TLV_CHECK(ett_pgm_opts_redirect);
689
398
      ptvcursor_set_tree(cursor, opt_tree);
690
691
398
      ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN);
692
398
      ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN);
693
694
398
      if (genopts_len < PGM_OPT_REDIRECT_SIZE) {
695
349
        proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb,
696
349
          ptvcursor_current_offset(cursor), 1, genopts_len,
697
349
          "%u (bogus, must be >= %u)",
698
349
          genopts_len, PGM_OPT_REDIRECT_SIZE);
699
349
        break;
700
349
      }
701
49
      ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN);
702
49
      ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN);
703
49
      ptvcursor_add(cursor, hf_pgm_opt_redirect_res, 1, ENC_BIG_ENDIAN);
704
49
      optdata_afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor));
705
49
      ti = ptvcursor_add(cursor, hf_pgm_opt_redirect_afi, 2, ENC_BIG_ENDIAN);
706
49
      ptvcursor_add(cursor, hf_pgm_opt_redirect_res2, 2, ENC_BIG_ENDIAN);
707
708
49
      switch (optdata_afi) {
709
710
0
      case AFNUM_IP:
711
0
        ptvcursor_add(cursor, hf_pgm_opt_redirect_dlr, 4, ENC_BIG_ENDIAN);
712
0
        break;
713
714
4
      case AFNUM_IP6:
715
4
        ptvcursor_add(cursor, hf_pgm_opt_redirect_dlr6, 16, ENC_NA);
716
4
        break;
717
718
43
      default:
719
43
        expert_add_info(pinfo, ti, &ei_address_format_invalid);
720
43
        break;
721
49
      }
722
723
47
      break;
724
49
    }
725
47
    case PGM_OPT_FRAGMENT:{
726
25
      TLV_CHECK(ett_pgm_opts_fragment);
727
20
      ptvcursor_set_tree(cursor, opt_tree);
728
729
20
      ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN);
730
20
      ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN);
731
732
20
      if (genopts_len < PGM_OPT_FRAGMENT_SIZE) {
733
7
        proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb,
734
7
          ptvcursor_current_offset(cursor), 1, genopts_len,
735
7
          "%u (bogus, must be >= %u)",
736
7
          genopts_len, PGM_OPT_FRAGMENT_SIZE);
737
7
        break;
738
7
      }
739
13
      ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN);
740
13
      ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN);
741
13
      ptvcursor_add(cursor, hf_pgm_opt_fragment_res, 1, ENC_BIG_ENDIAN);
742
13
      ptvcursor_add(cursor, hf_pgm_opt_fragment_first_sqn, 4, ENC_BIG_ENDIAN);
743
13
      ptvcursor_add(cursor, hf_pgm_opt_fragment_offset, 4, ENC_BIG_ENDIAN);
744
13
      ptvcursor_add(cursor, hf_pgm_opt_fragment_total_length, 4, ENC_BIG_ENDIAN);
745
746
13
      break;
747
20
    }
748
260
    default:{
749
260
      TLV_CHECK(ett_pgm_opts);
750
224
      ptvcursor_advance(cursor, genopts_len);
751
224
      break;
752
233
    }
753
1.55k
    }
754
755
1.43k
    opts_total_len -= genopts_len;
756
1.43k
  }
757
37
  return;
758
155
}
759
760
static const value_string type_vals[] = {
761
  { PGM_SPM_PCKT,   "SPM" },
762
  { PGM_RDATA_PCKT, "RDATA" },
763
  { PGM_ODATA_PCKT, "ODATA" },
764
  { PGM_NAK_PCKT,   "NAK" },
765
  { PGM_NNAK_PCKT,  "NNAK" },
766
  { PGM_NCF_PCKT,   "NCF" },
767
  { PGM_POLL_PCKT,  "POLL" },
768
  { PGM_POLR_PCKT,  "POLR" },
769
  { PGM_ACK_PCKT,   "ACK" },
770
  { PGM_ACK2_PCKT,  "ACK" },
771
  { 0,              NULL }
772
};
773
774
static const value_string poll_subtype_vals[] = {
775
  { PGM_POLL_GENERAL,   "General" },
776
  { PGM_POLL_DLR,       "DLR" },
777
  { 0,                  NULL }
778
};
779
780
/* Determine if there is a sub-dissector and call it.  This has been */
781
/* separated into a stand alone routine to other protocol dissectors */
782
/* can call to it, ie. socks  */
783
784
static void
785
decode_pgm_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,
786
     proto_tree *tree, uint16_t pgmhdr_sport, uint16_t pgmhdr_dport)
787
13
{
788
13
  tvbuff_t *next_tvb;
789
13
  int       found = 0;
790
13
  heur_dtbl_entry_t *hdtbl_entry;
791
792
13
  next_tvb = tvb_new_subset_remaining(tvb, offset);
793
794
  /* do lookup with the subdissector table */
795
13
  found = dissector_try_uint(subdissector_table, pgmhdr_sport,
796
13
           next_tvb, pinfo, tree);
797
13
  if (found)
798
0
    return;
799
800
13
  found = dissector_try_uint(subdissector_table, pgmhdr_dport,
801
13
           next_tvb, pinfo, tree);
802
13
  if (found)
803
0
    return;
804
805
  /* do lookup with the heuristic subdissector table */
806
13
  if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree, &hdtbl_entry, NULL))
807
0
    return;
808
809
  /* Oh, well, we don't know this; dissect it as data. */
810
13
  call_data_dissector(next_tvb, pinfo, tree);
811
13
}
812
813
/*
814
 * dissect_pgm - The dissector for Pragmatic General Multicast
815
 */
816
static int
817
dissect_pgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
818
302
{
819
302
  uint32_t pgmhdr_sport;
820
302
  uint32_t pgmhdr_dport;
821
302
  uint32_t pgmhdr_type;
822
302
  uint8_t pgmhdr_opts;
823
302
  uint16_t pgmhdr_cksum;
824
302
  uint32_t pgmhdr_tsdulen;
825
302
  uint32_t sqn;
826
302
  uint16_t afi;
827
828
302
  proto_tree *pgm_tree = NULL;
829
302
  proto_tree *opt_tree = NULL;
830
302
  proto_tree *type_tree = NULL;
831
302
  proto_item *tf, *hidden_item;
832
302
  ptvcursor_t* cursor;
833
834
302
  unsigned    plen   = 0;
835
302
  proto_item *ti;
836
302
  const char *pktname;
837
302
  char       *gsi;
838
302
  bool        isdata = false;
839
302
  unsigned    pgmlen, reportedlen;
840
841
302
  if (tvb_reported_length_remaining(tvb, 0) < 18)
842
56
    return 0;
843
844
246
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "PGM");
845
246
  col_clear(pinfo->cinfo, COL_INFO);
846
847
246
  ti = proto_tree_add_protocol_format(tree, proto_pgm, tvb, 0, -1,
848
246
    "Pragmatic General Multicast");
849
246
  pgm_tree = proto_item_add_subtree(ti, ett_pgm);
850
851
246
  cursor = ptvcursor_new(pinfo->pool, pgm_tree, tvb, 0);
852
853
246
  hidden_item = proto_tree_add_item(pgm_tree, hf_pgm_port, tvb, 0, 2, ENC_BIG_ENDIAN);
854
246
  proto_item_set_hidden(hidden_item);
855
246
  hidden_item = proto_tree_add_item(pgm_tree, hf_pgm_port, tvb, 2, 2, ENC_BIG_ENDIAN);
856
246
  proto_item_set_hidden(hidden_item);
857
246
  ptvcursor_add_ret_uint(cursor, hf_pgm_main_sport, 2, ENC_BIG_ENDIAN, &pgmhdr_sport);
858
246
  pinfo->srcport = pgmhdr_sport;
859
246
  ptvcursor_add_ret_uint(cursor, hf_pgm_main_dport, 2, ENC_BIG_ENDIAN, &pgmhdr_dport);
860
246
  pinfo->destport = pgmhdr_dport;
861
246
  ptvcursor_add_ret_uint(cursor, hf_pgm_main_type, 1, ENC_BIG_ENDIAN, &pgmhdr_type);
862
246
  pktname = val_to_str(pinfo->pool, pgmhdr_type, type_vals, "Unknown (0x%02x)");
863
246
  proto_item_append_text(ti, ": Type %s Src Port %u, Dst Port %u",
864
246
                         pktname, pgmhdr_sport, pgmhdr_dport);
865
246
  col_append_fstr(pinfo->cinfo, COL_INFO, "%-5s", pktname);
866
867
246
  pgmhdr_opts = tvb_get_uint8(tvb, 5);
868
246
  tf = proto_tree_add_uint_format_value(pgm_tree, hf_pgm_main_opts, tvb,
869
246
    ptvcursor_current_offset(cursor), 1, pgmhdr_opts, "%s (0x%x)",
870
246
    optsstr(pinfo->pool, pgmhdr_opts), pgmhdr_opts);
871
246
  opt_tree = proto_item_add_subtree(tf, ett_pgm_optbits);
872
246
  ptvcursor_set_tree(cursor, opt_tree);
873
874
246
  ptvcursor_add_no_advance(cursor, hf_pgm_main_opts_opt, 1, ENC_BIG_ENDIAN);
875
246
  ptvcursor_add_no_advance(cursor, hf_pgm_main_opts_netsig, 1, ENC_BIG_ENDIAN);
876
246
  ptvcursor_add_no_advance(cursor, hf_pgm_main_opts_varlen, 1, ENC_BIG_ENDIAN);
877
246
  ptvcursor_add(cursor, hf_pgm_main_opts_parity, 1, ENC_BIG_ENDIAN);
878
246
  ptvcursor_set_tree(cursor, pgm_tree);
879
880
  /* Checksum may be 0 (not available), but not for DATA packets */
881
246
  pgmhdr_cksum = tvb_get_ntohs(tvb, 6);
882
246
  if ((pgmhdr_type != PGM_RDATA_PCKT) && (pgmhdr_type != PGM_ODATA_PCKT) &&
883
228
      (pgmhdr_cksum == 0))
884
33
  {
885
33
    proto_tree_add_checksum(pgm_tree, tvb, ptvcursor_current_offset(cursor), hf_pgm_main_cksum, hf_pgm_main_cksum_status, &ei_pgm_main_cksum,
886
33
                pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NOT_PRESENT);
887
213
  } else {
888
213
    reportedlen = tvb_reported_length(tvb);
889
213
    pgmlen = tvb_captured_length(tvb);
890
213
    if (pgm_check_checksum && pgmlen >= reportedlen) {
891
213
      vec_t cksum_vec[1];
892
893
213
      SET_CKSUM_VEC_TVB(cksum_vec[0], tvb, 0, pgmlen);
894
213
      proto_tree_add_checksum(pgm_tree, tvb, ptvcursor_current_offset(cursor), hf_pgm_main_cksum_status, hf_pgm_main_cksum_status, &ei_pgm_main_cksum,
895
213
                  pinfo, in_cksum(&cksum_vec[0], 1), ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY|PROTO_CHECKSUM_IN_CKSUM);
896
213
    } else {
897
0
      proto_tree_add_checksum(pgm_tree, tvb, ptvcursor_current_offset(cursor), hf_pgm_main_cksum, hf_pgm_main_cksum_status, &ei_pgm_main_cksum,
898
0
                  pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
899
0
    }
900
213
  }
901
246
  ptvcursor_advance(cursor, 2);
902
903
246
  gsi = tvb_bytes_to_str(pinfo->pool, tvb, 8, 6);
904
246
  ptvcursor_add(cursor, hf_pgm_main_gsi, 6, ENC_NA);
905
246
  proto_item_append_text(ti, ", GSI %s", gsi);
906
246
  ptvcursor_add_ret_uint(cursor, hf_pgm_main_tsdulen, 2, ENC_BIG_ENDIAN, &pgmhdr_tsdulen);
907
246
  sqn = tvb_get_ntohl(tvb, 16);
908
246
  col_append_fstr(pinfo->cinfo, COL_INFO,
909
246
         " sqn 0x%x gsi %s", sqn, gsi);
910
911
246
  switch(pgmhdr_type) {
912
19
  case PGM_SPM_PCKT:
913
19
    type_tree = proto_tree_add_subtree_format(pgm_tree, tvb, ptvcursor_current_offset(cursor), plen,
914
19
                      ett_pgm_spm, NULL, "%s Packet", pktname);
915
19
    ptvcursor_set_tree(cursor, type_tree);
916
917
19
    ptvcursor_add(cursor, hf_pgm_spm_sqn, 4, ENC_BIG_ENDIAN);
918
19
    ptvcursor_add(cursor, hf_pgm_spm_trail, 4, ENC_BIG_ENDIAN);
919
19
    ptvcursor_add(cursor, hf_pgm_spm_lead, 4, ENC_BIG_ENDIAN);
920
19
    afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor));
921
19
    ti = ptvcursor_add(cursor, hf_pgm_spm_pathafi, 2, ENC_BIG_ENDIAN);
922
19
    ptvcursor_add(cursor, hf_pgm_spm_res, 2, ENC_BIG_ENDIAN);
923
924
19
    switch (afi) {
925
2
    case AFNUM_IP:
926
2
      ptvcursor_add(cursor, hf_pgm_spm_path, 4, ENC_BIG_ENDIAN);
927
2
      break;
928
929
1
    case AFNUM_IP6:
930
1
      ptvcursor_add(cursor, hf_pgm_spm_path6, 16, ENC_NA);
931
1
      break;
932
933
12
    default:
934
12
      expert_add_info(pinfo, ti, &ei_address_format_invalid);
935
12
      ptvcursor_free(cursor);
936
12
      return tvb_captured_length(tvb);
937
19
    }
938
1
    break;
939
14
  case PGM_RDATA_PCKT:
940
18
  case PGM_ODATA_PCKT:
941
18
    isdata = true;
942
18
    type_tree = proto_tree_add_subtree_format(pgm_tree, tvb, ptvcursor_current_offset(cursor), plen,
943
18
                      ett_pgm_data, NULL, "%s Packet", pktname);
944
18
    ptvcursor_set_tree(cursor, type_tree);
945
18
    col_append_fstr(pinfo->cinfo, COL_INFO,
946
18
          " tsdulen %d", pgmhdr_tsdulen);
947
948
18
    ptvcursor_add(cursor, hf_pgm_spm_sqn, 4, ENC_BIG_ENDIAN);
949
18
    ptvcursor_add(cursor, hf_pgm_spm_trail, 4, ENC_BIG_ENDIAN);
950
18
    break;
951
4
  case PGM_NAK_PCKT:
952
7
  case PGM_NNAK_PCKT:
953
10
  case PGM_NCF_PCKT:
954
10
    type_tree = proto_tree_add_subtree_format(pgm_tree, tvb, ptvcursor_current_offset(cursor), plen,
955
10
                      ett_pgm_nak, NULL, "%s Packet", pktname);
956
10
    ptvcursor_set_tree(cursor, type_tree);
957
958
10
    ptvcursor_add(cursor, hf_pgm_nak_sqn, 4, ENC_BIG_ENDIAN);
959
10
    afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor));
960
10
    ti = ptvcursor_add(cursor, hf_pgm_nak_srcafi, 2, ENC_BIG_ENDIAN);
961
10
    ptvcursor_add(cursor, hf_pgm_nak_srcres, 2, ENC_BIG_ENDIAN);
962
963
10
    switch (afi) {
964
1
    case AFNUM_IP:
965
1
      ptvcursor_add(cursor, hf_pgm_nak_src, 4, ENC_BIG_ENDIAN);
966
1
      break;
967
968
1
    case AFNUM_IP6:
969
1
      ptvcursor_add(cursor, hf_pgm_nak_src6, 16, ENC_NA);
970
1
      break;
971
972
6
    default:
973
6
      expert_add_info(pinfo, ti, &ei_address_format_invalid);
974
6
      break;
975
10
    }
976
977
8
    afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor));
978
8
    ti = ptvcursor_add(cursor, hf_pgm_nak_grpafi, 2, ENC_BIG_ENDIAN);
979
8
    ptvcursor_add(cursor, hf_pgm_nak_grpres, 2, ENC_BIG_ENDIAN);
980
981
8
    switch (afi) {
982
1
    case AFNUM_IP:
983
1
      ptvcursor_add(cursor, hf_pgm_nak_grp, 4, ENC_BIG_ENDIAN);
984
1
      break;
985
986
2
    case AFNUM_IP6:
987
2
      ptvcursor_add(cursor, hf_pgm_nak_grp6, 16, ENC_NA);
988
2
      break;
989
990
5
    default:
991
5
      expert_add_info(pinfo, ti, &ei_address_format_invalid);
992
5
      ptvcursor_free(cursor);
993
5
      return tvb_captured_length(tvb);
994
8
    }
995
2
    break;
996
12
  case PGM_POLL_PCKT: {
997
12
    uint32_t poll_stype;
998
999
12
    type_tree = proto_tree_add_subtree_format(pgm_tree, tvb, ptvcursor_current_offset(cursor), plen,
1000
12
                      ett_pgm_poll, NULL, "%s Packet", pktname);
1001
12
    ptvcursor_set_tree(cursor, type_tree);
1002
1003
12
    ptvcursor_add(cursor, hf_pgm_poll_sqn, 4, ENC_BIG_ENDIAN);
1004
12
    ptvcursor_add(cursor, hf_pgm_poll_round, 2, ENC_BIG_ENDIAN);
1005
12
    ptvcursor_add_ret_uint(cursor, hf_pgm_poll_subtype, 2, ENC_BIG_ENDIAN, &poll_stype);
1006
12
    col_append_fstr(pinfo->cinfo, COL_INFO,
1007
12
        " subtype %s",
1008
12
        val_to_str(pinfo->pool, poll_stype, poll_subtype_vals, "Unknown (0x%02x)"));
1009
12
    afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor));
1010
12
    ti = ptvcursor_add(cursor, hf_pgm_poll_pathafi, 2, ENC_BIG_ENDIAN);
1011
12
    ptvcursor_add(cursor, hf_pgm_poll_res, 2, ENC_BIG_ENDIAN);
1012
1013
12
    switch (afi) {
1014
1
    case AFNUM_IP:
1015
1
      ptvcursor_add(cursor, hf_pgm_poll_path, 4, ENC_BIG_ENDIAN);
1016
1
      break;
1017
1018
1
    case AFNUM_IP6:
1019
1
      ptvcursor_add(cursor, hf_pgm_poll_path6, 16, ENC_NA);
1020
1
      break;
1021
1022
8
    default:
1023
8
      expert_add_info(pinfo, ti, &ei_address_format_invalid);
1024
8
      break;
1025
12
    }
1026
1027
10
    ptvcursor_add(cursor, hf_pgm_poll_backoff_ivl, 4, ENC_BIG_ENDIAN);
1028
10
    ptvcursor_add(cursor, hf_pgm_poll_rand_str, 4, ENC_BIG_ENDIAN);
1029
10
    ptvcursor_add(cursor, hf_pgm_poll_matching_bmask, 4, ENC_BIG_ENDIAN);
1030
10
    break;
1031
12
  }
1032
8
  case PGM_POLR_PCKT:
1033
8
    type_tree = proto_tree_add_subtree_format(pgm_tree, tvb, ptvcursor_current_offset(cursor), plen,
1034
8
                      ett_pgm_polr, NULL, "%s Packet", pktname);
1035
8
    ptvcursor_set_tree(cursor, type_tree);
1036
1037
8
    ptvcursor_add(cursor, hf_pgm_polr_sqn, 4, ENC_BIG_ENDIAN);
1038
8
    ptvcursor_add(cursor, hf_pgm_polr_round, 2, ENC_BIG_ENDIAN);
1039
8
    ptvcursor_add(cursor, hf_pgm_polr_res, 2, ENC_BIG_ENDIAN);
1040
8
    break;
1041
2
  case PGM_ACK_PCKT:
1042
4
  case PGM_ACK2_PCKT:
1043
4
    type_tree = proto_tree_add_subtree_format(pgm_tree, tvb, ptvcursor_current_offset(cursor), plen,
1044
4
                      ett_pgm_ack, NULL, "%s Packet", pktname);
1045
4
    ptvcursor_set_tree(cursor, type_tree);
1046
1047
4
    ptvcursor_add(cursor, hf_pgm_ack_sqn, 4, ENC_BIG_ENDIAN);
1048
4
    ptvcursor_add(cursor, hf_pgm_ack_bitmap, 4, ENC_BIG_ENDIAN);
1049
4
    break;
1050
246
  }
1051
1052
212
  if (pgmhdr_opts & PGM_OPT)
1053
182
    dissect_pgmopts(cursor, pinfo, pktname);
1054
1055
212
  if (isdata)
1056
13
    decode_pgm_ports(tvb, ptvcursor_current_offset(cursor), pinfo, tree, pgmhdr_sport, pgmhdr_dport);
1057
1058
212
  ptvcursor_free(cursor);
1059
212
  return tvb_captured_length(tvb);
1060
246
}
1061
1062
/* Register all the bits needed with the filtering engine */
1063
void
1064
proto_register_pgm(void)
1065
14
{
1066
14
  static hf_register_info hf[] = {
1067
14
    { &hf_pgm_main_sport,
1068
14
      { "Source Port", "pgm.hdr.sport", FT_UINT16, BASE_DEC,
1069
14
        NULL, 0x0, NULL, HFILL }},
1070
14
    { &hf_pgm_main_dport,
1071
14
      { "Destination Port", "pgm.hdr.dport", FT_UINT16, BASE_DEC,
1072
14
        NULL, 0x0, NULL, HFILL }},
1073
14
    { &hf_pgm_port,
1074
14
      { "Port", "pgm.port", FT_UINT16, BASE_DEC,
1075
14
        NULL, 0x0, NULL, HFILL }},
1076
14
    { &hf_pgm_main_type,
1077
14
      { "Type", "pgm.hdr.type", FT_UINT8, BASE_HEX,
1078
14
        VALS(type_vals), 0x0, NULL, HFILL }},
1079
14
    { &hf_pgm_main_opts,
1080
14
      { "Options", "pgm.hdr.opts", FT_UINT8, BASE_HEX,
1081
14
        NULL, 0x0, NULL, HFILL }},
1082
14
    { &hf_pgm_main_opts_opt,
1083
14
      { "Options", "pgm.hdr.opts.opt", FT_BOOLEAN, 8,
1084
14
        TFS(&tfs_present_not_present), PGM_OPT, NULL, HFILL }},
1085
14
    { &hf_pgm_main_opts_netsig,
1086
14
      { "Network Significant Options", "pgm.hdr.opts.netsig",
1087
14
        FT_BOOLEAN, 8,
1088
14
        TFS(&tfs_present_not_present), PGM_OPT_NETSIG, NULL, HFILL }},
1089
14
    { &hf_pgm_main_opts_varlen,
1090
14
      { "Variable length Parity Packet Option", "pgm.hdr.opts.varlen",
1091
14
        FT_BOOLEAN, 8,
1092
14
        TFS(&tfs_present_not_present), PGM_OPT_VAR_PKTLEN, NULL, HFILL }},
1093
14
    { &hf_pgm_main_opts_parity,
1094
14
      { "Parity", "pgm.hdr.opts.parity", FT_BOOLEAN, 8,
1095
14
        TFS(&tfs_present_not_present), PGM_OPT_PARITY, NULL, HFILL }},
1096
14
    { &hf_pgm_main_cksum,
1097
14
      { "Checksum", "pgm.hdr.cksum", FT_UINT16, BASE_HEX,
1098
14
        NULL, 0x0, NULL, HFILL }},
1099
14
    { &hf_pgm_main_cksum_status,
1100
14
      { "Checksum Status", "pgm.hdr.cksum.status", FT_UINT8, BASE_NONE,
1101
14
        VALS(proto_checksum_vals), 0x0, NULL, HFILL }},
1102
14
    { &hf_pgm_main_gsi,
1103
14
      { "Global Source Identifier", "pgm.hdr.gsi", FT_BYTES, BASE_NONE,
1104
14
        NULL, 0x0, NULL, HFILL }},
1105
14
    { &hf_pgm_main_tsdulen,
1106
14
      { "Transport Service Data Unit Length", "pgm.hdr.tsdulen", FT_UINT16,
1107
14
        BASE_DEC, NULL, 0x0, NULL, HFILL }},
1108
14
    { &hf_pgm_spm_sqn,
1109
14
      { "Sequence number", "pgm.spm.sqn", FT_UINT32, BASE_HEX,
1110
14
        NULL, 0x0, NULL, HFILL }},
1111
14
    { &hf_pgm_spm_trail,
1112
14
      { "Trailing Edge Sequence Number", "pgm.spm.trail", FT_UINT32, BASE_HEX,
1113
14
        NULL, 0x0, NULL, HFILL }},
1114
14
    { &hf_pgm_spm_lead,
1115
14
      { "Leading Edge Sequence Number", "pgm.spm.lead", FT_UINT32, BASE_HEX,
1116
14
        NULL, 0x0, NULL, HFILL }},
1117
14
    { &hf_pgm_spm_pathafi,
1118
14
      { "Path NLA AFI", "pgm.spm.pathafi", FT_UINT16, BASE_DEC,
1119
14
        VALS(afn_vals), 0x0, NULL, HFILL }},
1120
14
    { &hf_pgm_spm_res,
1121
14
      { "Reserved", "pgm.spm.res", FT_UINT16, BASE_HEX,
1122
14
        NULL, 0x0, NULL, HFILL }},
1123
14
    { &hf_pgm_spm_path,
1124
14
      { "Path NLA", "pgm.spm.path.ipv4", FT_IPv4, BASE_NONE,
1125
14
        NULL, 0x0, NULL, HFILL }},
1126
14
    { &hf_pgm_spm_path6,
1127
14
      { "Path NLA", "pgm.spm.path.ipv6", FT_IPv6, BASE_NONE,
1128
14
        NULL, 0x0, NULL, HFILL }},
1129
#if 0
1130
    { &hf_pgm_data_sqn,
1131
      { "Data Packet Sequence Number", "pgm.data.sqn", FT_UINT32, BASE_HEX,
1132
        NULL, 0x0, NULL, HFILL }},
1133
#endif
1134
#if 0
1135
    { &hf_pgm_data_trail,
1136
      { "Trailing Edge Sequence Number", "pgm.data.trail", FT_UINT32, BASE_HEX,
1137
        NULL, 0x0, NULL, HFILL }},
1138
#endif
1139
14
    { &hf_pgm_nak_sqn,
1140
14
      { "Requested Sequence Number", "pgm.nak.sqn", FT_UINT32, BASE_HEX,
1141
14
        NULL, 0x0, NULL, HFILL }},
1142
14
    { &hf_pgm_nak_srcafi,
1143
14
      { "Source NLA AFI", "pgm.nak.srcafi", FT_UINT16, BASE_DEC,
1144
14
        VALS(afn_vals), 0x0, NULL, HFILL }},
1145
14
    { &hf_pgm_nak_srcres,
1146
14
      { "Reserved", "pgm.nak.srcres", FT_UINT16, BASE_HEX,
1147
14
        NULL, 0x0, NULL, HFILL }},
1148
14
    { &hf_pgm_nak_src,
1149
14
      { "Source NLA", "pgm.nak.src.ipv4", FT_IPv4, BASE_NONE,
1150
14
        NULL, 0x0, NULL, HFILL }},
1151
14
    { &hf_pgm_nak_src6,
1152
14
      { "Source NLA", "pgm.nak.src.ipv6", FT_IPv6, BASE_NONE,
1153
14
        NULL, 0x0, NULL, HFILL }},
1154
14
    { &hf_pgm_nak_grpafi,
1155
14
      { "Multicast Group AFI", "pgm.nak.grpafi", FT_UINT16, BASE_DEC,
1156
14
        VALS(afn_vals), 0x0, NULL, HFILL }},
1157
14
    { &hf_pgm_nak_grpres,
1158
14
      { "Reserved", "pgm.nak.grpres", FT_UINT16, BASE_HEX,
1159
14
        NULL, 0x0, NULL, HFILL }},
1160
14
    { &hf_pgm_nak_grp,
1161
14
      { "Multicast Group NLA", "pgm.nak.grp.ipv4", FT_IPv4, BASE_NONE,
1162
14
        NULL, 0x0, NULL, HFILL }},
1163
14
    { &hf_pgm_nak_grp6,
1164
14
      { "Multicast Group NLA", "pgm.nak.grp.ipv6", FT_IPv6, BASE_NONE,
1165
14
        NULL, 0x0, NULL, HFILL }},
1166
14
    { &hf_pgm_poll_sqn,
1167
14
      { "Sequence Number", "pgm.poll.sqn", FT_UINT32, BASE_HEX,
1168
14
        NULL, 0x0, NULL, HFILL }},
1169
14
    { &hf_pgm_poll_round,
1170
14
      { "Round", "pgm.poll.round", FT_UINT16, BASE_DEC,
1171
14
        NULL, 0x0, NULL, HFILL }},
1172
14
    { &hf_pgm_poll_subtype,
1173
14
      { "Subtype", "pgm.poll.subtype", FT_UINT16, BASE_HEX,
1174
14
        VALS(poll_subtype_vals), 0x0, NULL, HFILL }},
1175
14
    { &hf_pgm_poll_pathafi,
1176
14
      { "Path NLA AFI", "pgm.poll.pathafi", FT_UINT16, BASE_DEC,
1177
14
        VALS(afn_vals), 0x0, NULL, HFILL }},
1178
14
    { &hf_pgm_poll_res,
1179
14
      { "Reserved", "pgm.poll.res", FT_UINT16, BASE_HEX,
1180
14
        NULL, 0x0, NULL, HFILL }},
1181
14
    { &hf_pgm_poll_path,
1182
14
      { "Path NLA", "pgm.poll.path.ipv4", FT_IPv4, BASE_NONE,
1183
14
        NULL, 0x0, NULL, HFILL }},
1184
14
    { &hf_pgm_poll_path6,
1185
14
      { "Path NLA", "pgm.poll.path.ipv6", FT_IPv6, BASE_NONE,
1186
14
        NULL, 0x0, NULL, HFILL }},
1187
14
    { &hf_pgm_poll_backoff_ivl,
1188
14
      { "Back-off Interval", "pgm.poll.backoff_ivl", FT_UINT32, BASE_DEC,
1189
14
        NULL, 0x0, NULL, HFILL }},
1190
14
    { &hf_pgm_poll_rand_str,
1191
14
      { "Random String", "pgm.poll.rand_str", FT_UINT32, BASE_HEX,
1192
14
        NULL, 0x0, NULL, HFILL }},
1193
14
    { &hf_pgm_poll_matching_bmask,
1194
14
      { "Matching Bitmask", "pgm.poll.matching_bmask", FT_UINT32, BASE_HEX,
1195
14
        NULL, 0x0, NULL, HFILL }},
1196
14
    { &hf_pgm_polr_sqn,
1197
14
      { "Sequence Number", "pgm.polr.sqn", FT_UINT32, BASE_HEX,
1198
14
        NULL, 0x0, NULL, HFILL }},
1199
14
    { &hf_pgm_polr_round,
1200
14
      { "Round", "pgm.polr.round", FT_UINT16, BASE_DEC,
1201
14
        NULL, 0x0, NULL, HFILL }},
1202
14
    { &hf_pgm_polr_res,
1203
14
      { "Reserved", "pgm.polr.res", FT_UINT16, BASE_HEX,
1204
14
        NULL, 0x0, NULL, HFILL }},
1205
14
    { &hf_pgm_ack_sqn,
1206
14
      { "Maximum Received Sequence Number", "pgm.ack.maxsqn", FT_UINT32,
1207
14
        BASE_HEX, NULL, 0x0, NULL, HFILL }},
1208
14
    { &hf_pgm_ack_bitmap,
1209
14
      { "Packet Bitmap", "pgm.ack.bitmap", FT_UINT32, BASE_HEX,
1210
14
        NULL, 0x0, NULL, HFILL }},
1211
14
    { &hf_pgm_opt_type,
1212
14
      { "Type", "pgm.opts.type", FT_UINT8, BASE_HEX,
1213
14
        VALS(opt_vals), 0x0, NULL, HFILL }},
1214
14
    { &hf_pgm_opt_len,
1215
14
      { "Length", "pgm.opts.len", FT_UINT8, BASE_DEC,
1216
14
        NULL, 0x0, NULL, HFILL }},
1217
14
    { &hf_pgm_opt_tlen,
1218
14
      { "Total Length", "pgm.opts.tlen", FT_UINT16, BASE_DEC,
1219
14
        NULL, 0x0, NULL, HFILL }},
1220
14
    { &hf_pgm_genopt_end,
1221
14
      { "Option end", "pgm.genopts.end", FT_BOOLEAN, 8,
1222
14
        TFS(&tfs_yes_no), 0x80, NULL, HFILL }},
1223
14
    { &hf_pgm_genopt_type,
1224
14
      { "Type", "pgm.genopts.type", FT_UINT8, BASE_HEX,
1225
14
        VALS(opt_vals), 0x7f, NULL, HFILL }},
1226
14
    { &hf_pgm_genopt_len,
1227
14
      { "Length", "pgm.genopts.len", FT_UINT8, BASE_DEC,
1228
14
        NULL, 0x0, NULL, HFILL }},
1229
14
    { &hf_pgm_genopt_opx,
1230
14
      { "Option Extensibility Bits", "pgm.genopts.opx", FT_UINT8, BASE_HEX,
1231
14
        VALS(opx_vals), 0x0, NULL, HFILL }},
1232
14
    { &hf_pgm_opt_parity_prm_po,
1233
14
      { "Parity Parameters", "pgm.opts.parity_prm.op", FT_UINT8, BASE_HEX,
1234
14
        NULL, 0x0, NULL, HFILL }},
1235
14
    { &hf_pgm_opt_parity_prm_prmtgsz,
1236
14
      { "Transmission Group Size", "pgm.opts.parity_prm.prm_grp",
1237
14
        FT_UINT32, BASE_HEX,
1238
14
        NULL, 0x0, NULL, HFILL }},
1239
14
    { &hf_pgm_opt_join_res,
1240
14
      { "Reserved", "pgm.opts.join.res", FT_UINT8, BASE_HEX,
1241
14
        NULL, 0x0, NULL, HFILL }},
1242
14
    { &hf_pgm_opt_join_minjoin,
1243
14
      { "Minimum Sequence Number", "pgm.opts.join.min_join",
1244
14
        FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1245
14
    { &hf_pgm_opt_parity_grp_res,
1246
14
      { "Reserved", "pgm.opts.parity_prm.reserved", FT_UINT8, BASE_HEX,
1247
14
        NULL, 0x0, NULL, HFILL }},
1248
14
    { &hf_pgm_opt_parity_grp_prmgrp,
1249
14
      { "Transmission Group Size", "pgm.opts.parity_prm.prm_grp",
1250
14
        FT_UINT32, BASE_HEX,
1251
14
        NULL, 0x0, NULL, HFILL }},
1252
14
    { &hf_pgm_opt_nak_res,
1253
14
      { "Reserved", "pgm.opts.nak.op", FT_UINT8, BASE_HEX,
1254
14
        NULL, 0x0, NULL, HFILL }},
1255
14
    { &hf_pgm_opt_nak_list,
1256
14
      { "List", "pgm.opts.nak.list", FT_BYTES, BASE_NONE,
1257
14
        NULL, 0x0, NULL, HFILL }},
1258
14
    { &hf_pgm_opt_ccdata_res,
1259
14
      { "Reserved", "pgm.opts.ccdata.res", FT_UINT8, BASE_DEC,
1260
14
        NULL, 0x0, NULL, HFILL }},
1261
14
    { &hf_pgm_opt_ccdata_tsp,
1262
14
      { "Time Stamp", "pgm.opts.ccdata.tstamp", FT_UINT16, BASE_HEX,
1263
14
        NULL, 0x0, NULL, HFILL }},
1264
14
    { &hf_pgm_opt_ccdata_afi,
1265
14
      { "Acker AFI", "pgm.opts.ccdata.afi", FT_UINT16, BASE_DEC,
1266
14
        VALS(afn_vals), 0x0, NULL, HFILL }},
1267
14
    { &hf_pgm_opt_ccdata_res2,
1268
14
      { "Reserved", "pgm.opts.ccdata.res2", FT_UINT16, BASE_DEC,
1269
14
        NULL, 0x0, NULL, HFILL }},
1270
14
    { &hf_pgm_opt_ccdata_acker,
1271
14
      { "Acker", "pgm.opts.ccdata.acker.ipv4", FT_IPv4, BASE_NONE,
1272
14
        NULL, 0x0, NULL, HFILL }},
1273
14
    { &hf_pgm_opt_ccdata_acker6,
1274
14
      { "Acker", "pgm.opts.ccdata.acker.ipv6", FT_IPv6, BASE_NONE,
1275
14
        NULL, 0x0, NULL, HFILL }},
1276
14
    { &hf_pgm_opt_ccfeedbk_res,
1277
14
      { "Reserved", "pgm.opts.ccdata.res", FT_UINT8, BASE_DEC,
1278
14
        NULL, 0x0, NULL, HFILL }},
1279
14
    { &hf_pgm_opt_ccfeedbk_tsp,
1280
14
      { "Time Stamp", "pgm.opts.ccdata.tstamp", FT_UINT16, BASE_HEX,
1281
14
        NULL, 0x0, NULL, HFILL }},
1282
14
    { &hf_pgm_opt_ccfeedbk_afi,
1283
14
      { "Acker AFI", "pgm.opts.ccdata.afi", FT_UINT16, BASE_DEC,
1284
14
        VALS(afn_vals), 0x0, NULL, HFILL }},
1285
14
    { &hf_pgm_opt_ccfeedbk_lossrate,
1286
14
      { "Loss Rate", "pgm.opts.ccdata.lossrate", FT_UINT16, BASE_HEX,
1287
14
        NULL, 0x0, NULL, HFILL }},
1288
14
    { &hf_pgm_opt_ccfeedbk_acker,
1289
14
      { "Acker", "pgm.opts.ccdata.acker.ipv4", FT_IPv4, BASE_NONE,
1290
14
        NULL, 0x0, NULL, HFILL }},
1291
14
    { &hf_pgm_opt_ccfeedbk_acker6,
1292
14
      { "Acker", "pgm.opts.ccdata.acker.ipv6", FT_IPv6, BASE_NONE,
1293
14
        NULL, 0x0, NULL, HFILL }},
1294
14
    { &hf_pgm_opt_nak_bo_ivl_res,
1295
14
      { "Reserved", "pgm.opts.nak_bo_ivl.res", FT_UINT8, BASE_HEX,
1296
14
        NULL, 0x0, NULL, HFILL }},
1297
14
    { &hf_pgm_opt_nak_bo_ivl_bo_ivl,
1298
14
      { "Back-off Interval", "pgm.opts.nak_bo_ivl.bo_ivl", FT_UINT32, BASE_DEC,
1299
14
        NULL, 0x0, NULL, HFILL }},
1300
14
    { &hf_pgm_opt_nak_bo_ivl_bo_ivl_sqn,
1301
14
      { "Back-off Interval Sequence Number", "pgm.opts.nak_bo_ivl.bo_ivl_sqn", FT_UINT32, BASE_HEX,
1302
14
        NULL, 0x0, NULL, HFILL }},
1303
14
    { &hf_pgm_opt_nak_bo_rng_res,
1304
14
      { "Reserved", "pgm.opts.nak_bo_rng.res", FT_UINT8, BASE_HEX,
1305
14
        NULL, 0x0, NULL, HFILL }},
1306
14
    { &hf_pgm_opt_nak_bo_rng_min_bo_ivl,
1307
14
      { "Min Back-off Interval", "pgm.opts.nak_bo_rng.min_bo_ivl", FT_UINT32, BASE_DEC,
1308
14
        NULL, 0x0, NULL, HFILL }},
1309
14
    { &hf_pgm_opt_nak_bo_rng_max_bo_ivl,
1310
14
      { "Max Back-off Interval", "pgm.opts.nak_bo_rng.max_bo_ivl", FT_UINT32, BASE_DEC,
1311
14
        NULL, 0x0, NULL, HFILL }},
1312
14
    { &hf_pgm_opt_redirect_res,
1313
14
      { "Reserved", "pgm.opts.redirect.res", FT_UINT8, BASE_DEC,
1314
14
        NULL, 0x0, NULL, HFILL }},
1315
14
    { &hf_pgm_opt_redirect_afi,
1316
14
      { "DLR AFI", "pgm.opts.redirect.afi", FT_UINT16, BASE_DEC,
1317
14
        VALS(afn_vals), 0x0, NULL, HFILL }},
1318
14
    { &hf_pgm_opt_redirect_res2,
1319
14
      { "Reserved", "pgm.opts.redirect.res2", FT_UINT16, BASE_HEX,
1320
14
        NULL, 0x0, NULL, HFILL }},
1321
14
    { &hf_pgm_opt_redirect_dlr,
1322
14
      { "DLR", "pgm.opts.redirect.dlr.ipv4", FT_IPv4, BASE_NONE,
1323
14
        NULL, 0x0, NULL, HFILL }},
1324
14
    { &hf_pgm_opt_redirect_dlr6,
1325
14
      { "DLR", "pgm.opts.redirect.dlr.ipv6", FT_IPv6, BASE_NONE,
1326
14
        NULL, 0x0, NULL, HFILL }},
1327
14
    { &hf_pgm_opt_fragment_res,
1328
14
      { "Reserved", "pgm.opts.fragment.res", FT_UINT8, BASE_HEX,
1329
14
        NULL, 0x0, NULL, HFILL }},
1330
14
    { &hf_pgm_opt_fragment_first_sqn,
1331
14
      { "First Sequence Number", "pgm.opts.fragment.first_sqn", FT_UINT32, BASE_HEX,
1332
14
        NULL, 0x0, NULL, HFILL }},
1333
14
    { &hf_pgm_opt_fragment_offset,
1334
14
      { "Fragment Offset", "pgm.opts.fragment.fragment_offset", FT_UINT32, BASE_DEC,
1335
14
        NULL, 0x0, NULL, HFILL }},
1336
14
    { &hf_pgm_opt_fragment_total_length,
1337
14
      { "Total Length", "pgm.opts.fragment.total_length", FT_UINT32, BASE_DEC,
1338
14
        NULL, 0x0, NULL, HFILL }}
1339
14
  };
1340
14
  static int *ett[] = {
1341
14
    &ett_pgm,
1342
14
    &ett_pgm_optbits,
1343
14
    &ett_pgm_spm,
1344
14
    &ett_pgm_data,
1345
14
    &ett_pgm_nak,
1346
14
    &ett_pgm_poll,
1347
14
    &ett_pgm_polr,
1348
14
    &ett_pgm_ack,
1349
14
    &ett_pgm_opts,
1350
14
    &ett_pgm_opts_join,
1351
14
    &ett_pgm_opts_parityprm,
1352
14
    &ett_pgm_opts_paritygrp,
1353
14
    &ett_pgm_opts_naklist,
1354
14
    &ett_pgm_opts_ccdata,
1355
14
    &ett_pgm_opts_nak_bo_ivl,
1356
14
    &ett_pgm_opts_nak_bo_rng,
1357
14
    &ett_pgm_opts_redirect,
1358
14
    &ett_pgm_opts_fragment
1359
14
  };
1360
14
  static ei_register_info ei[] = {
1361
14
    { &ei_pgm_opt_type, { "pgm.opts.type.invalid", PI_PROTOCOL, PI_WARN, "Invalid option", EXPFILL }},
1362
14
    { &ei_pgm_opt_tlen, { "pgm.opts.tlen.invalid", PI_PROTOCOL, PI_WARN, "Total Length invalid", EXPFILL }},
1363
14
    { &ei_pgm_genopt_len, { "pgm.genopts.len.invalid", PI_PROTOCOL, PI_WARN, "Option length invalid", EXPFILL }},
1364
14
    { &ei_address_format_invalid, { "pgm.address_format_invalid", PI_PROTOCOL, PI_WARN, "Can't handle this address format", EXPFILL }},
1365
14
    { &ei_pgm_main_cksum, { "pgm.bad_checksum", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }},
1366
14
  };
1367
1368
14
  module_t *pgm_module;
1369
14
  expert_module_t* expert_pgm;
1370
1371
14
  proto_pgm = proto_register_protocol("Pragmatic General Multicast", "PGM", "pgm");
1372
1373
14
  proto_register_field_array(proto_pgm, hf, array_length(hf));
1374
14
  proto_register_subtree_array(ett, array_length(ett));
1375
14
  expert_pgm = expert_register_protocol(proto_pgm);
1376
14
  expert_register_field_array(expert_pgm, ei, array_length(ei));
1377
1378
  /* subdissector code */
1379
14
  pgm_handle = register_dissector("pgm", dissect_pgm, proto_pgm);
1380
14
  subdissector_table = register_dissector_table("pgm.port",
1381
14
                  "PGM port", proto_pgm, FT_UINT16, BASE_DEC);
1382
14
  heur_subdissector_list = register_heur_dissector_list_with_description("pgm", "PGM data fallback", proto_pgm);
1383
1384
  /*
1385
   * Register configuration preferences for UDP encapsulation
1386
   * (Note: Initially the ports are set to zero and the ports
1387
   *        are not registered so the dissecting of PGM
1388
   *        encapsulated in UDP packets is off by default;
1389
   *        dissector_add_for_decode_as is called so that pgm
1390
   *        is available for 'decode-as'
1391
   */
1392
14
  pgm_module = prefs_register_protocol(proto_pgm, NULL);
1393
1394
14
  prefs_register_bool_preference(pgm_module, "check_checksum",
1395
14
               "Check the validity of the PGM checksum when possible",
1396
14
               "Whether to check the validity of the PGM checksum",
1397
14
               &pgm_check_checksum);
1398
14
}
1399
1400
/* The registration hand-off routine */
1401
/*
1402
 * Set up PGM Encap dissecting, which is off by default for UDP
1403
 */
1404
1405
void
1406
proto_reg_handoff_pgm(void)
1407
14
{
1408
14
  dissector_add_uint_range_with_preference("udp.port", "", pgm_handle);
1409
14
  dissector_add_uint("ip.proto", IP_PROTO_PGM, pgm_handle);
1410
14
}
1411
1412
/*
1413
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1414
 *
1415
 * Local variables:
1416
 * c-basic-offset: 8
1417
 * tab-width: 8
1418
 * indent-tabs-mode: t
1419
 * End:
1420
 *
1421
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1422
 * :indentSize=8:tabSize=8:noTabs=false:
1423
 */