2 * Routines for PGM packet disassembly, RFC 3208
4 * Copyright (c) 2000 by Talarian Corp
5 * Rewritten by Jaap Keuter
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1999 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
16 #include <epan/packet.h>
18 #include <epan/ipproto.h>
19 #include <epan/in_cksum.h>
20 #include <epan/prefs.h>
21 #include <epan/ptvcursor.h>
22 #include <epan/expert.h>
24 #include <wsutil/array.h>
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.
36 * Luigi Rizzo's PGMCC code for FreeBSD, at
38 * https://web.archive.org/web/20020302084503/http://info.iet.unipi.it/~luigi/pgm-code/
40 * uses 0x0b (11) for ACK, as does tcpdump's dissector.
42 * A capture file attached to
44 * https://gitlab.com/wireshark/wireshark/-/issues/4798
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,
51 * We use *both*, treating *either one* as a PGMCC ACK, pending
52 * more information, such as an answer to
54 * https://github.com/steve-o/openpgm/issues/75.
57 void proto_register_pgm(void);
58 void proto_reg_handoff_pgm(void);
60 static dissector_handle_t pgm_handle
;
63 * Flag to control whether to check the PGM checksum.
65 static bool pgm_check_checksum
= true;
67 /* constants for hdr types */
68 #define PGM_SPM_PCKT 0x00
69 #define PGM_ODATA_PCKT 0x04
70 #define PGM_RDATA_PCKT 0x05
71 #define PGM_NAK_PCKT 0x08
72 #define PGM_NNAK_PCKT 0x09
73 #define PGM_NCF_PCKT 0x0A
74 #define PGM_POLL_PCKT 0x01
75 #define PGM_POLR_PCKT 0x02
78 * See above comment for why there are two values for the PGMCC
79 * ACK packet's packet type.
81 #define PGM_ACK_PCKT 0x0B
82 #define PGM_ACK2_PCKT 0x0D
84 /* option flags (main PGM header) */
86 #define PGM_OPT_NETSIG 0x02
87 #define PGM_OPT_VAR_PKTLEN 0x40
88 #define PGM_OPT_PARITY 0x80
91 #define PGM_OPT_LENGTH 0x00
92 #define PGM_OPT_END 0x80
93 #define PGM_OPT_FRAGMENT 0x01
94 #define PGM_OPT_NAK_LIST 0x02
95 #define PGM_OPT_JOIN 0x03
96 #define PGM_OPT_REDIRECT 0x07
97 #define PGM_OPT_SYN 0x0D
98 #define PGM_OPT_FIN 0x0E
99 #define PGM_OPT_RST 0x0F
100 #define PGM_OPT_PARITY_PRM 0x08
101 #define PGM_OPT_PARITY_GRP 0x09
102 #define PGM_OPT_CURR_TGSIZE 0x0A
103 #define PGM_OPT_PGMCC_DATA 0x12
104 #define PGM_OPT_PGMCC_FEEDBACK 0x13
105 #define PGM_OPT_NAK_BO_IVL 0x04
106 #define PGM_OPT_NAK_BO_RNG 0x05
109 #define PGM_POLL_GENERAL 0x0
110 #define PGM_POLL_DLR 0x1
113 #define PGM_OPX_IGNORE 0x00
114 #define PGM_OPX_INVAL 0x01
115 #define PGM_OPX_DISCARD 0x10
117 #define PGM_OPT_NAK_LIST_SIZE 4
120 * To squeeze the whole option into 255 bytes, we
121 * can only have 62 in the list
123 #define PGM_MAX_NAK_LIST_SZ (62)
125 #define PGM_OPT_JOIN_SIZE 8
126 #define PGM_OPT_PARITY_PRM_SIZE 8
128 /* OPT_PARITY_PRM P and O bits */
129 #define PGM_OPT_PARITY_PRM_PRO 0x2
130 #define PGM_OPT_PARITY_PRM_OND 0x1
132 #define PGM_OPT_PARITY_GRP_SIZE 8
133 #define PGM_OPT_CURR_TGSIZE_SIZE 8
134 #define PGM_OPT_PGMCC_DATA_SIZE 16
135 #define PGM_OPT_PGMCC_FEEDBACK_SIZE 16
136 #define PGM_OPT_NAK_BO_IVL_SIZE 12
137 #define PGM_OPT_NAK_BO_RNG_SIZE 12
138 #define PGM_OPT_REDIRECT_SIZE 12
139 #define PGM_OPT_FRAGMENT_SIZE 16
141 static int proto_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
;
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
;
208 static int hf_pgm_opt_type
;
209 static int hf_pgm_opt_len
;
210 static int hf_pgm_opt_tlen
;
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
;
217 static int hf_pgm_opt_join_res
;
218 static int hf_pgm_opt_join_minjoin
;
220 static int hf_pgm_opt_parity_prm_po
;
221 static int hf_pgm_opt_parity_prm_prmtgsz
;
223 static int hf_pgm_opt_parity_grp_res
;
224 static int hf_pgm_opt_parity_grp_prmgrp
;
226 static int hf_pgm_opt_nak_res
;
227 static int hf_pgm_opt_nak_list
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
268 static dissector_table_t subdissector_table
;
269 static heur_dissector_list_t heur_subdissector_list
;
273 optsstr(wmem_allocator_t
*pool
, uint8_t opts
)
276 int returned_length
, idx
= 0;
277 const int MAX_STR_LEN
= 256;
282 msg
=(char *)wmem_alloc(pool
, MAX_STR_LEN
);
284 returned_length
= snprintf(&msg
[idx
], MAX_STR_LEN
-idx
, "Present");
285 idx
+= MIN(returned_length
, MAX_STR_LEN
-idx
);
287 if (opts
& PGM_OPT_NETSIG
){
288 returned_length
= snprintf(&msg
[idx
], MAX_STR_LEN
-idx
, "%sNetSig", (!idx
)?"":",");
289 idx
+= MIN(returned_length
, MAX_STR_LEN
-idx
);
291 if (opts
& PGM_OPT_VAR_PKTLEN
){
292 returned_length
= snprintf(&msg
[idx
], MAX_STR_LEN
-idx
, "%sVarLen", (!idx
)?"":",");
293 idx
+= MIN(returned_length
, MAX_STR_LEN
-idx
);
295 if (opts
& PGM_OPT_PARITY
){
296 returned_length
= snprintf(&msg
[idx
], MAX_STR_LEN
-idx
, "%sParity", (!idx
)?"":",");
297 idx
+= MIN(returned_length
, MAX_STR_LEN
-idx
);
300 snprintf(&msg
[idx
], MAX_STR_LEN
-idx
, "0x%x", opts
);
305 paritystr(wmem_allocator_t
*pool
, uint8_t parity
)
308 int returned_length
, idx
= 0;
309 const int MAX_STR_LEN
= 256;
314 msg
=(char *)wmem_alloc(pool
, MAX_STR_LEN
);
315 if (parity
& PGM_OPT_PARITY_PRM_PRO
){
316 returned_length
= snprintf(&msg
[idx
], MAX_STR_LEN
-idx
, "Pro-active");
317 idx
+= MIN(returned_length
, MAX_STR_LEN
-idx
);
319 if (parity
& PGM_OPT_PARITY_PRM_OND
){
320 returned_length
= snprintf(&msg
[idx
], MAX_STR_LEN
-idx
, "%sOn-demand", (!idx
)?"":",");
321 idx
+= MIN(returned_length
, MAX_STR_LEN
-idx
);
324 snprintf(&msg
[idx
], MAX_STR_LEN
-idx
, "0x%x", parity
);
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" },
349 static const value_string opx_vals
[] = {
350 { PGM_OPX_IGNORE
, "Ignore" },
351 { PGM_OPX_INVAL
, "Inval" },
352 { PGM_OPX_DISCARD
, "DisCard" },
356 #define TLV_CHECK(ett) \
357 opt_tree = proto_tree_add_subtree_format(opts_tree, tvb, ptvcursor_current_offset(cursor), genopts_len, \
358 ett, &tf, "Option: %s, Length: %u", \
359 val_to_str(genopts_type, opt_vals, "Unknown (0x%02x)"), genopts_len); \
360 if (genopts_len < 4) { \
361 expert_add_info_format(pinfo, tf, &ei_pgm_genopt_len, \
362 "Length %u invalid, must be >= 4", genopts_len); \
365 if (opts_total_len < genopts_len) { \
366 expert_add_info_format(pinfo, tf, &ei_pgm_genopt_len, \
367 "Length %u > remaining total options length", genopts_len); \
373 dissect_pgmopts(ptvcursor_t
* cursor
, packet_info
*pinfo
, const char *pktname
)
375 proto_item
*tf
, *ti
, *ti_len
;
376 proto_tree
*opts_tree
= NULL
;
377 proto_tree
*opt_tree
= NULL
;
378 tvbuff_t
*tvb
= ptvcursor_tvbuff(cursor
);
382 uint16_t opts_total_len
;
383 uint8_t genopts_type
;
387 opts_tree
= proto_tree_add_subtree_format(ptvcursor_tree(cursor
), tvb
, ptvcursor_current_offset(cursor
), -1,
388 ett_pgm_opts
, &tf
, "%s Options", pktname
);
389 ptvcursor_set_tree(cursor
, opts_tree
);
390 opts_type
= tvb_get_uint8(tvb
, ptvcursor_current_offset(cursor
));
391 ti
= ptvcursor_add(cursor
, hf_pgm_opt_type
, 1, ENC_BIG_ENDIAN
);
392 if (opts_type
!= PGM_OPT_LENGTH
) {
393 expert_add_info_format(pinfo
, ti
, &ei_pgm_opt_type
,
394 "%s Options - initial option is %s, should be %s",
396 val_to_str(opts_type
, opt_vals
, "Unknown (0x%02x)"),
397 val_to_str(PGM_OPT_LENGTH
, opt_vals
, "Unknown (0x%02x)"));
400 ptvcursor_add(cursor
, hf_pgm_opt_len
, 1, ENC_BIG_ENDIAN
);
401 opts_total_len
= tvb_get_ntohs(tvb
, ptvcursor_current_offset(cursor
));
402 proto_item_append_text(tf
, " (Total Length %d)", opts_total_len
);
403 proto_item_set_len(tf
, opts_total_len
);
404 ti_len
= ptvcursor_add(cursor
, hf_pgm_opt_tlen
, 2, ENC_BIG_ENDIAN
);
405 if (opts_total_len
< 4) {
406 expert_add_info_format(pinfo
, ti_len
, &ei_pgm_opt_tlen
,
407 "%s Options (Total Length %u - invalid, must be >= 4)",
408 pktname
, opts_total_len
);
412 for (opts_total_len
-= 4; !theend
&& opts_total_len
!= 0;){
413 if (opts_total_len
< 4) {
414 expert_add_info_format(pinfo
, ti_len
, &ei_pgm_opt_tlen
,
415 "Remaining total options length doesn't have enough for an options header");
419 genopts_type
= tvb_get_uint8(tvb
, ptvcursor_current_offset(cursor
));
420 genopts_len
= tvb_get_uint8(tvb
, ptvcursor_current_offset(cursor
)+1);
422 if (genopts_type
& PGM_OPT_END
) {
423 genopts_type
&= ~PGM_OPT_END
;
427 switch(genopts_type
) {
429 TLV_CHECK(ett_pgm_opts_join
);
430 ptvcursor_set_tree(cursor
, opt_tree
);
432 ptvcursor_add_no_advance(cursor
, hf_pgm_genopt_end
, 1, ENC_BIG_ENDIAN
);
433 ptvcursor_add(cursor
, hf_pgm_genopt_type
, 1, ENC_BIG_ENDIAN
);
435 if (genopts_len
< PGM_OPT_JOIN_SIZE
) {
436 proto_tree_add_uint_format_value(opt_tree
, hf_pgm_genopt_len
, tvb
,
437 ptvcursor_current_offset(cursor
), 1, genopts_len
,
438 "%u (bogus, must be >= %u)",
439 genopts_len
, PGM_OPT_JOIN_SIZE
);
442 ptvcursor_add(cursor
, hf_pgm_genopt_len
, 1, ENC_BIG_ENDIAN
);
443 ptvcursor_add(cursor
, hf_pgm_genopt_opx
, 1, ENC_BIG_ENDIAN
);
444 ptvcursor_add(cursor
, hf_pgm_opt_join_res
, 1, ENC_BIG_ENDIAN
);
445 ptvcursor_add(cursor
, hf_pgm_opt_join_minjoin
, 4, ENC_BIG_ENDIAN
);
449 case PGM_OPT_PARITY_PRM
:{
452 TLV_CHECK(ett_pgm_opts_parityprm
);
453 ptvcursor_set_tree(cursor
, opt_tree
);
455 ptvcursor_add_no_advance(cursor
, hf_pgm_genopt_end
, 1, ENC_BIG_ENDIAN
);
456 ptvcursor_add(cursor
, hf_pgm_genopt_type
, 1, ENC_BIG_ENDIAN
);
459 if (genopts_len
< PGM_OPT_PARITY_PRM_SIZE
) {
460 proto_tree_add_uint_format_value(opt_tree
, hf_pgm_genopt_len
, ptvcursor_tvbuff(cursor
),
461 ptvcursor_current_offset(cursor
), 1, genopts_len
,
462 "%u (bogus, must be >= %u)",
463 genopts_len
, PGM_OPT_PARITY_PRM_SIZE
);
466 ptvcursor_add(cursor
, hf_pgm_genopt_len
, 1, ENC_BIG_ENDIAN
);
467 ptvcursor_add(cursor
, hf_pgm_genopt_opx
, 1, ENC_BIG_ENDIAN
);
468 optdata_po
= tvb_get_uint8(tvb
, ptvcursor_current_offset(cursor
));
469 proto_tree_add_uint_format_value(opt_tree
, hf_pgm_opt_parity_prm_po
, tvb
,
470 ptvcursor_current_offset(cursor
), 1, optdata_po
, "%s (0x%x)",
471 paritystr(pinfo
->pool
, optdata_po
), optdata_po
);
472 ptvcursor_advance(cursor
, 1);
474 ptvcursor_add(cursor
, hf_pgm_opt_parity_prm_prmtgsz
, 4, ENC_BIG_ENDIAN
);
478 case PGM_OPT_PARITY_GRP
:{
479 TLV_CHECK(ett_pgm_opts_paritygrp
);
480 ptvcursor_set_tree(cursor
, opt_tree
);
482 ptvcursor_add_no_advance(cursor
, hf_pgm_genopt_end
, 1, ENC_BIG_ENDIAN
);
483 ptvcursor_add(cursor
, hf_pgm_genopt_type
, 1, ENC_BIG_ENDIAN
);
485 if (genopts_len
< PGM_OPT_PARITY_GRP_SIZE
) {
486 proto_tree_add_uint_format_value(opt_tree
, hf_pgm_genopt_len
, tvb
,
487 ptvcursor_current_offset(cursor
), 1, genopts_len
,
488 "%u (bogus, must be >= %u)",
489 genopts_len
, PGM_OPT_PARITY_GRP_SIZE
);
492 ptvcursor_add(cursor
, hf_pgm_genopt_len
, 1, ENC_BIG_ENDIAN
);
493 ptvcursor_add(cursor
, hf_pgm_genopt_opx
, 1, ENC_BIG_ENDIAN
);
494 ptvcursor_add(cursor
, hf_pgm_opt_parity_grp_res
, 1, ENC_BIG_ENDIAN
);
495 ptvcursor_add(cursor
, hf_pgm_opt_parity_grp_prmgrp
, 4, ENC_BIG_ENDIAN
);
499 case PGM_OPT_NAK_LIST
:{
501 uint32_t naklist
[PGM_MAX_NAK_LIST_SZ
+1];
502 unsigned char *nakbuf
;
504 int i
, j
, naks
, soffset
;
506 TLV_CHECK(ett_pgm_opts_naklist
);
507 ptvcursor_set_tree(cursor
, opt_tree
);
509 ptvcursor_add_no_advance(cursor
, hf_pgm_genopt_end
, 1, ENC_BIG_ENDIAN
);
510 ptvcursor_add(cursor
, hf_pgm_genopt_type
, 1, ENC_BIG_ENDIAN
);
512 optdata_len
= tvb_get_uint8(tvb
, ptvcursor_current_offset(cursor
));
513 ptvcursor_add(cursor
, hf_pgm_genopt_len
, 1, ENC_BIG_ENDIAN
);
514 ptvcursor_add(cursor
, hf_pgm_genopt_opx
, 1, ENC_BIG_ENDIAN
);
515 ptvcursor_add(cursor
, hf_pgm_opt_nak_res
, 1, ENC_BIG_ENDIAN
);
517 optdata_len
-= PGM_OPT_NAK_LIST_SIZE
;
518 tvb_memcpy(tvb
, (uint8_t *)naklist
, ptvcursor_current_offset(cursor
), optdata_len
);
521 naks
= (int)(optdata_len
/sizeof(uint32_t));
522 nakbuf
= (unsigned char *)wmem_alloc(pinfo
->pool
, 8192);
525 * Print out 8 per line
527 for (i
=0; i
< naks
; i
++) {
528 soffset
+= MIN(8192-soffset
,
529 snprintf(nakbuf
+soffset
, 8192-soffset
, "0x%lx ",
530 (unsigned long)g_ntohl(naklist
[i
])));
531 if ((++j
% 8) == 0) {
533 proto_tree_add_bytes_format(opt_tree
,
534 hf_pgm_opt_nak_list
, tvb
, ptvcursor_current_offset(cursor
), j
*4,
535 nakbuf
, "List(%d): %s", naks
, nakbuf
);
539 proto_tree_add_bytes_format_value(opt_tree
,
540 hf_pgm_opt_nak_list
, tvb
, ptvcursor_current_offset(cursor
), j
*4,
541 nakbuf
, "%s", nakbuf
);
544 ptvcursor_advance(cursor
, j
*4);
550 proto_tree_add_bytes_format(opt_tree
,
551 hf_pgm_opt_nak_list
, tvb
, ptvcursor_current_offset(cursor
), j
*4,
552 nakbuf
, "List(%d): %s", naks
, nakbuf
);
554 proto_tree_add_bytes_format_value(opt_tree
,
555 hf_pgm_opt_nak_list
, tvb
, ptvcursor_current_offset(cursor
), j
*4,
556 nakbuf
, "%s", nakbuf
);
558 ptvcursor_advance(cursor
, j
*4);
562 case PGM_OPT_PGMCC_DATA
:{
563 uint16_t optdata_afi
;
565 TLV_CHECK(ett_pgm_opts_ccdata
);
566 ptvcursor_set_tree(cursor
, opt_tree
);
568 ptvcursor_add_no_advance(cursor
, hf_pgm_genopt_end
, 1, ENC_BIG_ENDIAN
);
569 ptvcursor_add(cursor
, hf_pgm_genopt_type
, 1, ENC_BIG_ENDIAN
);
571 if (genopts_len
< PGM_OPT_PGMCC_DATA_SIZE
) {
572 proto_tree_add_uint_format_value(opt_tree
, hf_pgm_genopt_len
, tvb
,
573 ptvcursor_current_offset(cursor
), 1, genopts_len
,
574 "%u (bogus, must be >= %u)",
575 genopts_len
, PGM_OPT_PGMCC_DATA_SIZE
);
578 ptvcursor_add(cursor
, hf_pgm_genopt_len
, 1, ENC_BIG_ENDIAN
);
579 ptvcursor_add(cursor
, hf_pgm_genopt_opx
, 1, ENC_BIG_ENDIAN
);
580 ptvcursor_add(cursor
, hf_pgm_opt_ccdata_res
, 1, ENC_BIG_ENDIAN
);
581 ptvcursor_add(cursor
, hf_pgm_opt_ccdata_tsp
, 4, ENC_BIG_ENDIAN
);
582 optdata_afi
= tvb_get_ntohs(tvb
, ptvcursor_current_offset(cursor
));
583 ti
= ptvcursor_add(cursor
, hf_pgm_opt_ccdata_afi
, 2, ENC_BIG_ENDIAN
);
584 ptvcursor_add(cursor
, hf_pgm_opt_ccdata_res2
, 2, ENC_BIG_ENDIAN
);
586 switch (optdata_afi
) {
589 ptvcursor_add(cursor
, hf_pgm_opt_ccdata_acker
, 4, ENC_BIG_ENDIAN
);
593 ptvcursor_add(cursor
, hf_pgm_opt_ccdata_acker6
, 16, ENC_NA
);
597 expert_add_info(pinfo
, ti
, &ei_address_format_invalid
);
603 case PGM_OPT_PGMCC_FEEDBACK
:{
604 uint16_t optdata_afi
;
606 TLV_CHECK(ett_pgm_opts_ccdata
);
607 ptvcursor_set_tree(cursor
, opt_tree
);
609 ptvcursor_add_no_advance(cursor
, hf_pgm_genopt_end
, 1, ENC_BIG_ENDIAN
);
610 ptvcursor_add(cursor
, hf_pgm_genopt_type
, 1, ENC_BIG_ENDIAN
);
612 if (genopts_len
< PGM_OPT_PGMCC_FEEDBACK_SIZE
) {
613 proto_tree_add_uint_format_value(opt_tree
, hf_pgm_genopt_len
, tvb
,
614 ptvcursor_current_offset(cursor
), 1, genopts_len
,
615 "%u (bogus, must be >= %u)",
616 genopts_len
, PGM_OPT_PGMCC_FEEDBACK_SIZE
);
619 ptvcursor_add(cursor
, hf_pgm_genopt_len
, 1, ENC_BIG_ENDIAN
);
620 ptvcursor_add(cursor
, hf_pgm_genopt_opx
, 1, ENC_BIG_ENDIAN
);
621 ptvcursor_add(cursor
, hf_pgm_opt_ccfeedbk_res
, 1, ENC_BIG_ENDIAN
);
622 ptvcursor_add(cursor
, hf_pgm_opt_ccfeedbk_tsp
, 4, ENC_BIG_ENDIAN
);
623 optdata_afi
= tvb_get_ntohs(tvb
, ptvcursor_current_offset(cursor
));
624 ti
= ptvcursor_add(cursor
, hf_pgm_opt_ccfeedbk_afi
, 2, ENC_BIG_ENDIAN
);
625 ptvcursor_add(cursor
, hf_pgm_opt_ccfeedbk_lossrate
, 2, ENC_BIG_ENDIAN
);
627 switch (optdata_afi
) {
630 ptvcursor_add(cursor
, hf_pgm_opt_ccfeedbk_acker
, 4, ENC_BIG_ENDIAN
);
634 ptvcursor_add(cursor
, hf_pgm_opt_ccfeedbk_acker6
, 16, ENC_NA
);
638 expert_add_info(pinfo
, ti
, &ei_address_format_invalid
);
644 case PGM_OPT_NAK_BO_IVL
:{
645 TLV_CHECK(ett_pgm_opts_nak_bo_ivl
);
646 ptvcursor_set_tree(cursor
, opt_tree
);
648 ptvcursor_add_no_advance(cursor
, hf_pgm_genopt_end
, 1, ENC_BIG_ENDIAN
);
649 ptvcursor_add(cursor
, hf_pgm_genopt_type
, 1, ENC_BIG_ENDIAN
);
651 if (genopts_len
< PGM_OPT_NAK_BO_IVL_SIZE
) {
652 proto_tree_add_uint_format_value(opt_tree
, hf_pgm_genopt_len
, tvb
,
653 ptvcursor_current_offset(cursor
), 1, genopts_len
,
654 "%u (bogus, must be >= %u)",
655 genopts_len
, PGM_OPT_NAK_BO_IVL_SIZE
);
658 ptvcursor_add(cursor
, hf_pgm_genopt_len
, 1, ENC_BIG_ENDIAN
);
659 ptvcursor_add(cursor
, hf_pgm_genopt_opx
, 1, ENC_BIG_ENDIAN
);
660 ptvcursor_add(cursor
, hf_pgm_opt_nak_bo_ivl_res
, 1, ENC_BIG_ENDIAN
);
661 ptvcursor_add(cursor
, hf_pgm_opt_nak_bo_ivl_bo_ivl
, 4, ENC_BIG_ENDIAN
);
662 ptvcursor_add(cursor
, hf_pgm_opt_nak_bo_ivl_bo_ivl_sqn
, 4, ENC_BIG_ENDIAN
);
666 case PGM_OPT_NAK_BO_RNG
:{
667 TLV_CHECK(ett_pgm_opts_nak_bo_rng
);
668 ptvcursor_set_tree(cursor
, opt_tree
);
670 ptvcursor_add_no_advance(cursor
, hf_pgm_genopt_end
, 1, ENC_BIG_ENDIAN
);
671 ptvcursor_add(cursor
, hf_pgm_genopt_type
, 1, ENC_BIG_ENDIAN
);
673 if (genopts_len
< PGM_OPT_NAK_BO_RNG_SIZE
) {
674 proto_tree_add_uint_format_value(opt_tree
, hf_pgm_genopt_len
, tvb
,
675 ptvcursor_current_offset(cursor
), 1, genopts_len
,
676 "%u (bogus, must be >= %u)",
677 genopts_len
, PGM_OPT_NAK_BO_RNG_SIZE
);
680 ptvcursor_add(cursor
, hf_pgm_genopt_len
, 1, ENC_BIG_ENDIAN
);
681 ptvcursor_add(cursor
, hf_pgm_genopt_opx
, 1, ENC_BIG_ENDIAN
);
682 ptvcursor_add(cursor
, hf_pgm_opt_nak_bo_rng_res
, 1, ENC_BIG_ENDIAN
);
683 ptvcursor_add(cursor
, hf_pgm_opt_nak_bo_rng_min_bo_ivl
, 4, ENC_BIG_ENDIAN
);
684 ptvcursor_add(cursor
, hf_pgm_opt_nak_bo_rng_max_bo_ivl
, 4, ENC_BIG_ENDIAN
);
688 case PGM_OPT_REDIRECT
:{
689 uint16_t optdata_afi
;
691 TLV_CHECK(ett_pgm_opts_redirect
);
692 ptvcursor_set_tree(cursor
, opt_tree
);
694 ptvcursor_add_no_advance(cursor
, hf_pgm_genopt_end
, 1, ENC_BIG_ENDIAN
);
695 ptvcursor_add(cursor
, hf_pgm_genopt_type
, 1, ENC_BIG_ENDIAN
);
697 if (genopts_len
< PGM_OPT_REDIRECT_SIZE
) {
698 proto_tree_add_uint_format_value(opt_tree
, hf_pgm_genopt_len
, tvb
,
699 ptvcursor_current_offset(cursor
), 1, genopts_len
,
700 "%u (bogus, must be >= %u)",
701 genopts_len
, PGM_OPT_REDIRECT_SIZE
);
704 ptvcursor_add(cursor
, hf_pgm_genopt_len
, 1, ENC_BIG_ENDIAN
);
705 ptvcursor_add(cursor
, hf_pgm_genopt_opx
, 1, ENC_BIG_ENDIAN
);
706 ptvcursor_add(cursor
, hf_pgm_opt_redirect_res
, 1, ENC_BIG_ENDIAN
);
707 optdata_afi
= tvb_get_ntohs(tvb
, ptvcursor_current_offset(cursor
));
708 ti
= ptvcursor_add(cursor
, hf_pgm_opt_redirect_afi
, 2, ENC_BIG_ENDIAN
);
709 ptvcursor_add(cursor
, hf_pgm_opt_redirect_res2
, 2, ENC_BIG_ENDIAN
);
711 switch (optdata_afi
) {
714 ptvcursor_add(cursor
, hf_pgm_opt_redirect_dlr
, 4, ENC_BIG_ENDIAN
);
718 ptvcursor_add(cursor
, hf_pgm_opt_redirect_dlr6
, 16, ENC_NA
);
722 expert_add_info(pinfo
, ti
, &ei_address_format_invalid
);
728 case PGM_OPT_FRAGMENT
:{
729 TLV_CHECK(ett_pgm_opts_fragment
);
730 ptvcursor_set_tree(cursor
, opt_tree
);
732 ptvcursor_add_no_advance(cursor
, hf_pgm_genopt_end
, 1, ENC_BIG_ENDIAN
);
733 ptvcursor_add(cursor
, hf_pgm_genopt_type
, 1, ENC_BIG_ENDIAN
);
735 if (genopts_len
< PGM_OPT_FRAGMENT_SIZE
) {
736 proto_tree_add_uint_format_value(opt_tree
, hf_pgm_genopt_len
, tvb
,
737 ptvcursor_current_offset(cursor
), 1, genopts_len
,
738 "%u (bogus, must be >= %u)",
739 genopts_len
, PGM_OPT_FRAGMENT_SIZE
);
742 ptvcursor_add(cursor
, hf_pgm_genopt_len
, 1, ENC_BIG_ENDIAN
);
743 ptvcursor_add(cursor
, hf_pgm_genopt_opx
, 1, ENC_BIG_ENDIAN
);
744 ptvcursor_add(cursor
, hf_pgm_opt_fragment_res
, 1, ENC_BIG_ENDIAN
);
745 ptvcursor_add(cursor
, hf_pgm_opt_fragment_first_sqn
, 4, ENC_BIG_ENDIAN
);
746 ptvcursor_add(cursor
, hf_pgm_opt_fragment_offset
, 4, ENC_BIG_ENDIAN
);
747 ptvcursor_add(cursor
, hf_pgm_opt_fragment_total_length
, 4, ENC_BIG_ENDIAN
);
752 TLV_CHECK(ett_pgm_opts
);
753 ptvcursor_advance(cursor
, genopts_len
);
758 opts_total_len
-= genopts_len
;
763 static const value_string type_vals
[] = {
764 { PGM_SPM_PCKT
, "SPM" },
765 { PGM_RDATA_PCKT
, "RDATA" },
766 { PGM_ODATA_PCKT
, "ODATA" },
767 { PGM_NAK_PCKT
, "NAK" },
768 { PGM_NNAK_PCKT
, "NNAK" },
769 { PGM_NCF_PCKT
, "NCF" },
770 { PGM_POLL_PCKT
, "POLL" },
771 { PGM_POLR_PCKT
, "POLR" },
772 { PGM_ACK_PCKT
, "ACK" },
773 { PGM_ACK2_PCKT
, "ACK" },
777 static const value_string poll_subtype_vals
[] = {
778 { PGM_POLL_GENERAL
, "General" },
779 { PGM_POLL_DLR
, "DLR" },
783 /* Determine if there is a sub-dissector and call it. This has been */
784 /* separated into a stand alone routine to other protocol dissectors */
785 /* can call to it, ie. socks */
788 decode_pgm_ports(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
789 proto_tree
*tree
, uint16_t pgmhdr_sport
, uint16_t pgmhdr_dport
)
793 heur_dtbl_entry_t
*hdtbl_entry
;
795 next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
797 /* do lookup with the subdissector table */
798 found
= dissector_try_uint(subdissector_table
, pgmhdr_sport
,
799 next_tvb
, pinfo
, tree
);
803 found
= dissector_try_uint(subdissector_table
, pgmhdr_dport
,
804 next_tvb
, pinfo
, tree
);
808 /* do lookup with the heuristic subdissector table */
809 if (dissector_try_heuristic(heur_subdissector_list
, next_tvb
, pinfo
, tree
, &hdtbl_entry
, NULL
))
812 /* Oh, well, we don't know this; dissect it as data. */
813 call_data_dissector(next_tvb
, pinfo
, tree
);
817 * dissect_pgm - The dissector for Pragmatic General Multicast
820 dissect_pgm(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
822 uint32_t pgmhdr_sport
;
823 uint32_t pgmhdr_dport
;
824 uint32_t pgmhdr_type
;
826 uint16_t pgmhdr_cksum
;
827 uint32_t pgmhdr_tsdulen
;
831 proto_tree
*pgm_tree
= NULL
;
832 proto_tree
*opt_tree
= NULL
;
833 proto_tree
*type_tree
= NULL
;
834 proto_item
*tf
, *hidden_item
;
842 unsigned pgmlen
, reportedlen
;
844 if (tvb_reported_length_remaining(tvb
, 0) < 18)
847 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "PGM");
848 col_clear(pinfo
->cinfo
, COL_INFO
);
850 ti
= proto_tree_add_protocol_format(tree
, proto_pgm
, tvb
, 0, -1,
851 "Pragmatic General Multicast");
852 pgm_tree
= proto_item_add_subtree(ti
, ett_pgm
);
854 cursor
= ptvcursor_new(pinfo
->pool
, pgm_tree
, tvb
, 0);
856 hidden_item
= proto_tree_add_item(pgm_tree
, hf_pgm_port
, tvb
, 0, 2, ENC_BIG_ENDIAN
);
857 proto_item_set_hidden(hidden_item
);
858 hidden_item
= proto_tree_add_item(pgm_tree
, hf_pgm_port
, tvb
, 2, 2, ENC_BIG_ENDIAN
);
859 proto_item_set_hidden(hidden_item
);
860 ptvcursor_add_ret_uint(cursor
, hf_pgm_main_sport
, 2, ENC_BIG_ENDIAN
, &pgmhdr_sport
);
861 pinfo
->srcport
= pgmhdr_sport
;
862 ptvcursor_add_ret_uint(cursor
, hf_pgm_main_dport
, 2, ENC_BIG_ENDIAN
, &pgmhdr_dport
);
863 pinfo
->destport
= pgmhdr_dport
;
864 ptvcursor_add_ret_uint(cursor
, hf_pgm_main_type
, 1, ENC_BIG_ENDIAN
, &pgmhdr_type
);
865 pktname
= val_to_str(pgmhdr_type
, type_vals
, "Unknown (0x%02x)");
866 proto_item_append_text(ti
, ": Type %s Src Port %u, Dst Port %u",
867 pktname
, pgmhdr_sport
, pgmhdr_dport
);
868 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%-5s", pktname
);
870 pgmhdr_opts
= tvb_get_uint8(tvb
, 5);
871 tf
= proto_tree_add_uint_format_value(pgm_tree
, hf_pgm_main_opts
, tvb
,
872 ptvcursor_current_offset(cursor
), 1, pgmhdr_opts
, "%s (0x%x)",
873 optsstr(pinfo
->pool
, pgmhdr_opts
), pgmhdr_opts
);
874 opt_tree
= proto_item_add_subtree(tf
, ett_pgm_optbits
);
875 ptvcursor_set_tree(cursor
, opt_tree
);
877 ptvcursor_add_no_advance(cursor
, hf_pgm_main_opts_opt
, 1, ENC_BIG_ENDIAN
);
878 ptvcursor_add_no_advance(cursor
, hf_pgm_main_opts_netsig
, 1, ENC_BIG_ENDIAN
);
879 ptvcursor_add_no_advance(cursor
, hf_pgm_main_opts_varlen
, 1, ENC_BIG_ENDIAN
);
880 ptvcursor_add(cursor
, hf_pgm_main_opts_parity
, 1, ENC_BIG_ENDIAN
);
881 ptvcursor_set_tree(cursor
, pgm_tree
);
883 /* Checksum may be 0 (not available), but not for DATA packets */
884 pgmhdr_cksum
= tvb_get_ntohs(tvb
, 6);
885 if ((pgmhdr_type
!= PGM_RDATA_PCKT
) && (pgmhdr_type
!= PGM_ODATA_PCKT
) &&
888 proto_tree_add_checksum(pgm_tree
, tvb
, ptvcursor_current_offset(cursor
), hf_pgm_main_cksum
, hf_pgm_main_cksum_status
, &ei_pgm_main_cksum
,
889 pinfo
, 0, ENC_BIG_ENDIAN
, PROTO_CHECKSUM_NOT_PRESENT
);
891 reportedlen
= tvb_reported_length(tvb
);
892 pgmlen
= tvb_captured_length(tvb
);
893 if (pgm_check_checksum
&& pgmlen
>= reportedlen
) {
896 SET_CKSUM_VEC_TVB(cksum_vec
[0], tvb
, 0, pgmlen
);
897 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
,
898 pinfo
, in_cksum(&cksum_vec
[0], 1), ENC_BIG_ENDIAN
, PROTO_CHECKSUM_VERIFY
|PROTO_CHECKSUM_IN_CKSUM
);
900 proto_tree_add_checksum(pgm_tree
, tvb
, ptvcursor_current_offset(cursor
), hf_pgm_main_cksum
, hf_pgm_main_cksum_status
, &ei_pgm_main_cksum
,
901 pinfo
, 0, ENC_BIG_ENDIAN
, PROTO_CHECKSUM_NO_FLAGS
);
904 ptvcursor_advance(cursor
, 2);
906 gsi
= tvb_bytes_to_str(pinfo
->pool
, tvb
, 8, 6);
907 ptvcursor_add(cursor
, hf_pgm_main_gsi
, 6, ENC_NA
);
908 proto_item_append_text(ti
, ", GSI %s", gsi
);
909 ptvcursor_add_ret_uint(cursor
, hf_pgm_main_tsdulen
, 2, ENC_BIG_ENDIAN
, &pgmhdr_tsdulen
);
910 sqn
= tvb_get_ntohl(tvb
, 16);
911 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
912 " sqn 0x%x gsi %s", sqn
, gsi
);
914 switch(pgmhdr_type
) {
916 type_tree
= proto_tree_add_subtree_format(pgm_tree
, tvb
, ptvcursor_current_offset(cursor
), plen
,
917 ett_pgm_spm
, NULL
, "%s Packet", pktname
);
918 ptvcursor_set_tree(cursor
, type_tree
);
920 ptvcursor_add(cursor
, hf_pgm_spm_sqn
, 4, ENC_BIG_ENDIAN
);
921 ptvcursor_add(cursor
, hf_pgm_spm_trail
, 4, ENC_BIG_ENDIAN
);
922 ptvcursor_add(cursor
, hf_pgm_spm_lead
, 4, ENC_BIG_ENDIAN
);
923 afi
= tvb_get_ntohs(tvb
, ptvcursor_current_offset(cursor
));
924 ti
= ptvcursor_add(cursor
, hf_pgm_spm_pathafi
, 2, ENC_BIG_ENDIAN
);
925 ptvcursor_add(cursor
, hf_pgm_spm_res
, 2, ENC_BIG_ENDIAN
);
929 ptvcursor_add(cursor
, hf_pgm_spm_path
, 4, ENC_BIG_ENDIAN
);
933 ptvcursor_add(cursor
, hf_pgm_spm_path6
, 16, ENC_NA
);
937 expert_add_info(pinfo
, ti
, &ei_address_format_invalid
);
938 ptvcursor_free(cursor
);
939 return tvb_captured_length(tvb
);
945 type_tree
= proto_tree_add_subtree_format(pgm_tree
, tvb
, ptvcursor_current_offset(cursor
), plen
,
946 ett_pgm_data
, NULL
, "%s Packet", pktname
);
947 ptvcursor_set_tree(cursor
, type_tree
);
948 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
949 " tsdulen %d", pgmhdr_tsdulen
);
951 ptvcursor_add(cursor
, hf_pgm_spm_sqn
, 4, ENC_BIG_ENDIAN
);
952 ptvcursor_add(cursor
, hf_pgm_spm_trail
, 4, ENC_BIG_ENDIAN
);
957 type_tree
= proto_tree_add_subtree_format(pgm_tree
, tvb
, ptvcursor_current_offset(cursor
), plen
,
958 ett_pgm_nak
, NULL
, "%s Packet", pktname
);
959 ptvcursor_set_tree(cursor
, type_tree
);
961 ptvcursor_add(cursor
, hf_pgm_nak_sqn
, 4, ENC_BIG_ENDIAN
);
962 afi
= tvb_get_ntohs(tvb
, ptvcursor_current_offset(cursor
));
963 ti
= ptvcursor_add(cursor
, hf_pgm_nak_srcafi
, 2, ENC_BIG_ENDIAN
);
964 ptvcursor_add(cursor
, hf_pgm_nak_srcres
, 2, ENC_BIG_ENDIAN
);
968 ptvcursor_add(cursor
, hf_pgm_nak_src
, 4, ENC_BIG_ENDIAN
);
972 ptvcursor_add(cursor
, hf_pgm_nak_src6
, 16, ENC_NA
);
976 expert_add_info(pinfo
, ti
, &ei_address_format_invalid
);
980 afi
= tvb_get_ntohs(tvb
, ptvcursor_current_offset(cursor
));
981 ti
= ptvcursor_add(cursor
, hf_pgm_nak_grpafi
, 2, ENC_BIG_ENDIAN
);
982 ptvcursor_add(cursor
, hf_pgm_nak_grpres
, 2, ENC_BIG_ENDIAN
);
986 ptvcursor_add(cursor
, hf_pgm_nak_grp
, 4, ENC_BIG_ENDIAN
);
990 ptvcursor_add(cursor
, hf_pgm_nak_grp6
, 16, ENC_NA
);
994 expert_add_info(pinfo
, ti
, &ei_address_format_invalid
);
995 ptvcursor_free(cursor
);
996 return tvb_captured_length(tvb
);
999 case PGM_POLL_PCKT
: {
1000 uint32_t poll_stype
;
1002 type_tree
= proto_tree_add_subtree_format(pgm_tree
, tvb
, ptvcursor_current_offset(cursor
), plen
,
1003 ett_pgm_poll
, NULL
, "%s Packet", pktname
);
1004 ptvcursor_set_tree(cursor
, type_tree
);
1006 ptvcursor_add(cursor
, hf_pgm_poll_sqn
, 4, ENC_BIG_ENDIAN
);
1007 ptvcursor_add(cursor
, hf_pgm_poll_round
, 2, ENC_BIG_ENDIAN
);
1008 ptvcursor_add_ret_uint(cursor
, hf_pgm_poll_subtype
, 2, ENC_BIG_ENDIAN
, &poll_stype
);
1009 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
1011 val_to_str(poll_stype
, poll_subtype_vals
, "Unknown (0x%02x)"));
1012 afi
= tvb_get_ntohs(tvb
, ptvcursor_current_offset(cursor
));
1013 ti
= ptvcursor_add(cursor
, hf_pgm_poll_pathafi
, 2, ENC_BIG_ENDIAN
);
1014 ptvcursor_add(cursor
, hf_pgm_poll_res
, 2, ENC_BIG_ENDIAN
);
1018 ptvcursor_add(cursor
, hf_pgm_poll_path
, 4, ENC_BIG_ENDIAN
);
1022 ptvcursor_add(cursor
, hf_pgm_poll_path6
, 16, ENC_NA
);
1026 expert_add_info(pinfo
, ti
, &ei_address_format_invalid
);
1030 ptvcursor_add(cursor
, hf_pgm_poll_backoff_ivl
, 4, ENC_BIG_ENDIAN
);
1031 ptvcursor_add(cursor
, hf_pgm_poll_rand_str
, 4, ENC_BIG_ENDIAN
);
1032 ptvcursor_add(cursor
, hf_pgm_poll_matching_bmask
, 4, ENC_BIG_ENDIAN
);
1036 type_tree
= proto_tree_add_subtree_format(pgm_tree
, tvb
, ptvcursor_current_offset(cursor
), plen
,
1037 ett_pgm_polr
, NULL
, "%s Packet", pktname
);
1038 ptvcursor_set_tree(cursor
, type_tree
);
1040 ptvcursor_add(cursor
, hf_pgm_polr_sqn
, 4, ENC_BIG_ENDIAN
);
1041 ptvcursor_add(cursor
, hf_pgm_polr_round
, 2, ENC_BIG_ENDIAN
);
1042 ptvcursor_add(cursor
, hf_pgm_polr_res
, 2, ENC_BIG_ENDIAN
);
1046 type_tree
= proto_tree_add_subtree_format(pgm_tree
, tvb
, ptvcursor_current_offset(cursor
), plen
,
1047 ett_pgm_ack
, NULL
, "%s Packet", pktname
);
1048 ptvcursor_set_tree(cursor
, type_tree
);
1050 ptvcursor_add(cursor
, hf_pgm_ack_sqn
, 4, ENC_BIG_ENDIAN
);
1051 ptvcursor_add(cursor
, hf_pgm_ack_bitmap
, 4, ENC_BIG_ENDIAN
);
1055 if (pgmhdr_opts
& PGM_OPT
)
1056 dissect_pgmopts(cursor
, pinfo
, pktname
);
1059 decode_pgm_ports(tvb
, ptvcursor_current_offset(cursor
), pinfo
, tree
, pgmhdr_sport
, pgmhdr_dport
);
1061 ptvcursor_free(cursor
);
1062 return tvb_captured_length(tvb
);
1065 /* Register all the bits needed with the filtering engine */
1067 proto_register_pgm(void)
1069 static hf_register_info hf
[] = {
1070 { &hf_pgm_main_sport
,
1071 { "Source Port", "pgm.hdr.sport", FT_UINT16
, BASE_DEC
,
1072 NULL
, 0x0, NULL
, HFILL
}},
1073 { &hf_pgm_main_dport
,
1074 { "Destination Port", "pgm.hdr.dport", FT_UINT16
, BASE_DEC
,
1075 NULL
, 0x0, NULL
, HFILL
}},
1077 { "Port", "pgm.port", FT_UINT16
, BASE_DEC
,
1078 NULL
, 0x0, NULL
, HFILL
}},
1079 { &hf_pgm_main_type
,
1080 { "Type", "pgm.hdr.type", FT_UINT8
, BASE_HEX
,
1081 VALS(type_vals
), 0x0, NULL
, HFILL
}},
1082 { &hf_pgm_main_opts
,
1083 { "Options", "pgm.hdr.opts", FT_UINT8
, BASE_HEX
,
1084 NULL
, 0x0, NULL
, HFILL
}},
1085 { &hf_pgm_main_opts_opt
,
1086 { "Options", "pgm.hdr.opts.opt", FT_BOOLEAN
, 8,
1087 TFS(&tfs_present_not_present
), PGM_OPT
, NULL
, HFILL
}},
1088 { &hf_pgm_main_opts_netsig
,
1089 { "Network Significant Options", "pgm.hdr.opts.netsig",
1091 TFS(&tfs_present_not_present
), PGM_OPT_NETSIG
, NULL
, HFILL
}},
1092 { &hf_pgm_main_opts_varlen
,
1093 { "Variable length Parity Packet Option", "pgm.hdr.opts.varlen",
1095 TFS(&tfs_present_not_present
), PGM_OPT_VAR_PKTLEN
, NULL
, HFILL
}},
1096 { &hf_pgm_main_opts_parity
,
1097 { "Parity", "pgm.hdr.opts.parity", FT_BOOLEAN
, 8,
1098 TFS(&tfs_present_not_present
), PGM_OPT_PARITY
, NULL
, HFILL
}},
1099 { &hf_pgm_main_cksum
,
1100 { "Checksum", "pgm.hdr.cksum", FT_UINT16
, BASE_HEX
,
1101 NULL
, 0x0, NULL
, HFILL
}},
1102 { &hf_pgm_main_cksum_status
,
1103 { "Checksum Status", "pgm.hdr.cksum.status", FT_UINT8
, BASE_NONE
,
1104 VALS(proto_checksum_vals
), 0x0, NULL
, HFILL
}},
1106 { "Global Source Identifier", "pgm.hdr.gsi", FT_BYTES
, BASE_NONE
,
1107 NULL
, 0x0, NULL
, HFILL
}},
1108 { &hf_pgm_main_tsdulen
,
1109 { "Transport Service Data Unit Length", "pgm.hdr.tsdulen", FT_UINT16
,
1110 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1112 { "Sequence number", "pgm.spm.sqn", FT_UINT32
, BASE_HEX
,
1113 NULL
, 0x0, NULL
, HFILL
}},
1114 { &hf_pgm_spm_trail
,
1115 { "Trailing Edge Sequence Number", "pgm.spm.trail", FT_UINT32
, BASE_HEX
,
1116 NULL
, 0x0, NULL
, HFILL
}},
1118 { "Leading Edge Sequence Number", "pgm.spm.lead", FT_UINT32
, BASE_HEX
,
1119 NULL
, 0x0, NULL
, HFILL
}},
1120 { &hf_pgm_spm_pathafi
,
1121 { "Path NLA AFI", "pgm.spm.pathafi", FT_UINT16
, BASE_DEC
,
1122 VALS(afn_vals
), 0x0, NULL
, HFILL
}},
1124 { "Reserved", "pgm.spm.res", FT_UINT16
, BASE_HEX
,
1125 NULL
, 0x0, NULL
, HFILL
}},
1127 { "Path NLA", "pgm.spm.path.ipv4", FT_IPv4
, BASE_NONE
,
1128 NULL
, 0x0, NULL
, HFILL
}},
1129 { &hf_pgm_spm_path6
,
1130 { "Path NLA", "pgm.spm.path.ipv6", FT_IPv6
, BASE_NONE
,
1131 NULL
, 0x0, NULL
, HFILL
}},
1134 { "Data Packet Sequence Number", "pgm.data.sqn", FT_UINT32
, BASE_HEX
,
1135 NULL
, 0x0, NULL
, HFILL
}},
1138 { &hf_pgm_data_trail
,
1139 { "Trailing Edge Sequence Number", "pgm.data.trail", FT_UINT32
, BASE_HEX
,
1140 NULL
, 0x0, NULL
, HFILL
}},
1143 { "Requested Sequence Number", "pgm.nak.sqn", FT_UINT32
, BASE_HEX
,
1144 NULL
, 0x0, NULL
, HFILL
}},
1145 { &hf_pgm_nak_srcafi
,
1146 { "Source NLA AFI", "pgm.nak.srcafi", FT_UINT16
, BASE_DEC
,
1147 VALS(afn_vals
), 0x0, NULL
, HFILL
}},
1148 { &hf_pgm_nak_srcres
,
1149 { "Reserved", "pgm.nak.srcres", FT_UINT16
, BASE_HEX
,
1150 NULL
, 0x0, NULL
, HFILL
}},
1152 { "Source NLA", "pgm.nak.src.ipv4", FT_IPv4
, BASE_NONE
,
1153 NULL
, 0x0, NULL
, HFILL
}},
1155 { "Source NLA", "pgm.nak.src.ipv6", FT_IPv6
, BASE_NONE
,
1156 NULL
, 0x0, NULL
, HFILL
}},
1157 { &hf_pgm_nak_grpafi
,
1158 { "Multicast Group AFI", "pgm.nak.grpafi", FT_UINT16
, BASE_DEC
,
1159 VALS(afn_vals
), 0x0, NULL
, HFILL
}},
1160 { &hf_pgm_nak_grpres
,
1161 { "Reserved", "pgm.nak.grpres", FT_UINT16
, BASE_HEX
,
1162 NULL
, 0x0, NULL
, HFILL
}},
1164 { "Multicast Group NLA", "pgm.nak.grp.ipv4", FT_IPv4
, BASE_NONE
,
1165 NULL
, 0x0, NULL
, HFILL
}},
1167 { "Multicast Group NLA", "pgm.nak.grp.ipv6", FT_IPv6
, BASE_NONE
,
1168 NULL
, 0x0, NULL
, HFILL
}},
1170 { "Sequence Number", "pgm.poll.sqn", FT_UINT32
, BASE_HEX
,
1171 NULL
, 0x0, NULL
, HFILL
}},
1172 { &hf_pgm_poll_round
,
1173 { "Round", "pgm.poll.round", FT_UINT16
, BASE_DEC
,
1174 NULL
, 0x0, NULL
, HFILL
}},
1175 { &hf_pgm_poll_subtype
,
1176 { "Subtype", "pgm.poll.subtype", FT_UINT16
, BASE_HEX
,
1177 VALS(poll_subtype_vals
), 0x0, NULL
, HFILL
}},
1178 { &hf_pgm_poll_pathafi
,
1179 { "Path NLA AFI", "pgm.poll.pathafi", FT_UINT16
, BASE_DEC
,
1180 VALS(afn_vals
), 0x0, NULL
, HFILL
}},
1182 { "Reserved", "pgm.poll.res", FT_UINT16
, BASE_HEX
,
1183 NULL
, 0x0, NULL
, HFILL
}},
1184 { &hf_pgm_poll_path
,
1185 { "Path NLA", "pgm.poll.path.ipv4", FT_IPv4
, BASE_NONE
,
1186 NULL
, 0x0, NULL
, HFILL
}},
1187 { &hf_pgm_poll_path6
,
1188 { "Path NLA", "pgm.poll.path.ipv6", FT_IPv6
, BASE_NONE
,
1189 NULL
, 0x0, NULL
, HFILL
}},
1190 { &hf_pgm_poll_backoff_ivl
,
1191 { "Back-off Interval", "pgm.poll.backoff_ivl", FT_UINT32
, BASE_DEC
,
1192 NULL
, 0x0, NULL
, HFILL
}},
1193 { &hf_pgm_poll_rand_str
,
1194 { "Random String", "pgm.poll.rand_str", FT_UINT32
, BASE_HEX
,
1195 NULL
, 0x0, NULL
, HFILL
}},
1196 { &hf_pgm_poll_matching_bmask
,
1197 { "Matching Bitmask", "pgm.poll.matching_bmask", FT_UINT32
, BASE_HEX
,
1198 NULL
, 0x0, NULL
, HFILL
}},
1200 { "Sequence Number", "pgm.polr.sqn", FT_UINT32
, BASE_HEX
,
1201 NULL
, 0x0, NULL
, HFILL
}},
1202 { &hf_pgm_polr_round
,
1203 { "Round", "pgm.polr.round", FT_UINT16
, BASE_DEC
,
1204 NULL
, 0x0, NULL
, HFILL
}},
1206 { "Reserved", "pgm.polr.res", FT_UINT16
, BASE_HEX
,
1207 NULL
, 0x0, NULL
, HFILL
}},
1209 { "Maximum Received Sequence Number", "pgm.ack.maxsqn", FT_UINT32
,
1210 BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1211 { &hf_pgm_ack_bitmap
,
1212 { "Packet Bitmap", "pgm.ack.bitmap", FT_UINT32
, BASE_HEX
,
1213 NULL
, 0x0, NULL
, HFILL
}},
1215 { "Type", "pgm.opts.type", FT_UINT8
, BASE_HEX
,
1216 VALS(opt_vals
), 0x0, NULL
, HFILL
}},
1218 { "Length", "pgm.opts.len", FT_UINT8
, BASE_DEC
,
1219 NULL
, 0x0, NULL
, HFILL
}},
1221 { "Total Length", "pgm.opts.tlen", FT_UINT16
, BASE_DEC
,
1222 NULL
, 0x0, NULL
, HFILL
}},
1223 { &hf_pgm_genopt_end
,
1224 { "Option end", "pgm.genopts.end", FT_BOOLEAN
, 8,
1225 TFS(&tfs_yes_no
), 0x80, NULL
, HFILL
}},
1226 { &hf_pgm_genopt_type
,
1227 { "Type", "pgm.genopts.type", FT_UINT8
, BASE_HEX
,
1228 VALS(opt_vals
), 0x7f, NULL
, HFILL
}},
1229 { &hf_pgm_genopt_len
,
1230 { "Length", "pgm.genopts.len", FT_UINT8
, BASE_DEC
,
1231 NULL
, 0x0, NULL
, HFILL
}},
1232 { &hf_pgm_genopt_opx
,
1233 { "Option Extensibility Bits", "pgm.genopts.opx", FT_UINT8
, BASE_HEX
,
1234 VALS(opx_vals
), 0x0, NULL
, HFILL
}},
1235 { &hf_pgm_opt_parity_prm_po
,
1236 { "Parity Parameters", "pgm.opts.parity_prm.op", FT_UINT8
, BASE_HEX
,
1237 NULL
, 0x0, NULL
, HFILL
}},
1238 { &hf_pgm_opt_parity_prm_prmtgsz
,
1239 { "Transmission Group Size", "pgm.opts.parity_prm.prm_grp",
1240 FT_UINT32
, BASE_HEX
,
1241 NULL
, 0x0, NULL
, HFILL
}},
1242 { &hf_pgm_opt_join_res
,
1243 { "Reserved", "pgm.opts.join.res", FT_UINT8
, BASE_HEX
,
1244 NULL
, 0x0, NULL
, HFILL
}},
1245 { &hf_pgm_opt_join_minjoin
,
1246 { "Minimum Sequence Number", "pgm.opts.join.min_join",
1247 FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1248 { &hf_pgm_opt_parity_grp_res
,
1249 { "Reserved", "pgm.opts.parity_prm.reserved", FT_UINT8
, BASE_HEX
,
1250 NULL
, 0x0, NULL
, HFILL
}},
1251 { &hf_pgm_opt_parity_grp_prmgrp
,
1252 { "Transmission Group Size", "pgm.opts.parity_prm.prm_grp",
1253 FT_UINT32
, BASE_HEX
,
1254 NULL
, 0x0, NULL
, HFILL
}},
1255 { &hf_pgm_opt_nak_res
,
1256 { "Reserved", "pgm.opts.nak.op", FT_UINT8
, BASE_HEX
,
1257 NULL
, 0x0, NULL
, HFILL
}},
1258 { &hf_pgm_opt_nak_list
,
1259 { "List", "pgm.opts.nak.list", FT_BYTES
, BASE_NONE
,
1260 NULL
, 0x0, NULL
, HFILL
}},
1261 { &hf_pgm_opt_ccdata_res
,
1262 { "Reserved", "pgm.opts.ccdata.res", FT_UINT8
, BASE_DEC
,
1263 NULL
, 0x0, NULL
, HFILL
}},
1264 { &hf_pgm_opt_ccdata_tsp
,
1265 { "Time Stamp", "pgm.opts.ccdata.tstamp", FT_UINT16
, BASE_HEX
,
1266 NULL
, 0x0, NULL
, HFILL
}},
1267 { &hf_pgm_opt_ccdata_afi
,
1268 { "Acker AFI", "pgm.opts.ccdata.afi", FT_UINT16
, BASE_DEC
,
1269 VALS(afn_vals
), 0x0, NULL
, HFILL
}},
1270 { &hf_pgm_opt_ccdata_res2
,
1271 { "Reserved", "pgm.opts.ccdata.res2", FT_UINT16
, BASE_DEC
,
1272 NULL
, 0x0, NULL
, HFILL
}},
1273 { &hf_pgm_opt_ccdata_acker
,
1274 { "Acker", "pgm.opts.ccdata.acker.ipv4", FT_IPv4
, BASE_NONE
,
1275 NULL
, 0x0, NULL
, HFILL
}},
1276 { &hf_pgm_opt_ccdata_acker6
,
1277 { "Acker", "pgm.opts.ccdata.acker.ipv6", FT_IPv6
, BASE_NONE
,
1278 NULL
, 0x0, NULL
, HFILL
}},
1279 { &hf_pgm_opt_ccfeedbk_res
,
1280 { "Reserved", "pgm.opts.ccdata.res", FT_UINT8
, BASE_DEC
,
1281 NULL
, 0x0, NULL
, HFILL
}},
1282 { &hf_pgm_opt_ccfeedbk_tsp
,
1283 { "Time Stamp", "pgm.opts.ccdata.tstamp", FT_UINT16
, BASE_HEX
,
1284 NULL
, 0x0, NULL
, HFILL
}},
1285 { &hf_pgm_opt_ccfeedbk_afi
,
1286 { "Acker AFI", "pgm.opts.ccdata.afi", FT_UINT16
, BASE_DEC
,
1287 VALS(afn_vals
), 0x0, NULL
, HFILL
}},
1288 { &hf_pgm_opt_ccfeedbk_lossrate
,
1289 { "Loss Rate", "pgm.opts.ccdata.lossrate", FT_UINT16
, BASE_HEX
,
1290 NULL
, 0x0, NULL
, HFILL
}},
1291 { &hf_pgm_opt_ccfeedbk_acker
,
1292 { "Acker", "pgm.opts.ccdata.acker.ipv4", FT_IPv4
, BASE_NONE
,
1293 NULL
, 0x0, NULL
, HFILL
}},
1294 { &hf_pgm_opt_ccfeedbk_acker6
,
1295 { "Acker", "pgm.opts.ccdata.acker.ipv6", FT_IPv6
, BASE_NONE
,
1296 NULL
, 0x0, NULL
, HFILL
}},
1297 { &hf_pgm_opt_nak_bo_ivl_res
,
1298 { "Reserved", "pgm.opts.nak_bo_ivl.res", FT_UINT8
, BASE_HEX
,
1299 NULL
, 0x0, NULL
, HFILL
}},
1300 { &hf_pgm_opt_nak_bo_ivl_bo_ivl
,
1301 { "Back-off Interval", "pgm.opts.nak_bo_ivl.bo_ivl", FT_UINT32
, BASE_DEC
,
1302 NULL
, 0x0, NULL
, HFILL
}},
1303 { &hf_pgm_opt_nak_bo_ivl_bo_ivl_sqn
,
1304 { "Back-off Interval Sequence Number", "pgm.opts.nak_bo_ivl.bo_ivl_sqn", FT_UINT32
, BASE_HEX
,
1305 NULL
, 0x0, NULL
, HFILL
}},
1306 { &hf_pgm_opt_nak_bo_rng_res
,
1307 { "Reserved", "pgm.opts.nak_bo_rng.res", FT_UINT8
, BASE_HEX
,
1308 NULL
, 0x0, NULL
, HFILL
}},
1309 { &hf_pgm_opt_nak_bo_rng_min_bo_ivl
,
1310 { "Min Back-off Interval", "pgm.opts.nak_bo_rng.min_bo_ivl", FT_UINT32
, BASE_DEC
,
1311 NULL
, 0x0, NULL
, HFILL
}},
1312 { &hf_pgm_opt_nak_bo_rng_max_bo_ivl
,
1313 { "Max Back-off Interval", "pgm.opts.nak_bo_rng.max_bo_ivl", FT_UINT32
, BASE_DEC
,
1314 NULL
, 0x0, NULL
, HFILL
}},
1315 { &hf_pgm_opt_redirect_res
,
1316 { "Reserved", "pgm.opts.redirect.res", FT_UINT8
, BASE_DEC
,
1317 NULL
, 0x0, NULL
, HFILL
}},
1318 { &hf_pgm_opt_redirect_afi
,
1319 { "DLR AFI", "pgm.opts.redirect.afi", FT_UINT16
, BASE_DEC
,
1320 VALS(afn_vals
), 0x0, NULL
, HFILL
}},
1321 { &hf_pgm_opt_redirect_res2
,
1322 { "Reserved", "pgm.opts.redirect.res2", FT_UINT16
, BASE_HEX
,
1323 NULL
, 0x0, NULL
, HFILL
}},
1324 { &hf_pgm_opt_redirect_dlr
,
1325 { "DLR", "pgm.opts.redirect.dlr.ipv4", FT_IPv4
, BASE_NONE
,
1326 NULL
, 0x0, NULL
, HFILL
}},
1327 { &hf_pgm_opt_redirect_dlr6
,
1328 { "DLR", "pgm.opts.redirect.dlr.ipv6", FT_IPv6
, BASE_NONE
,
1329 NULL
, 0x0, NULL
, HFILL
}},
1330 { &hf_pgm_opt_fragment_res
,
1331 { "Reserved", "pgm.opts.fragment.res", FT_UINT8
, BASE_HEX
,
1332 NULL
, 0x0, NULL
, HFILL
}},
1333 { &hf_pgm_opt_fragment_first_sqn
,
1334 { "First Sequence Number", "pgm.opts.fragment.first_sqn", FT_UINT32
, BASE_HEX
,
1335 NULL
, 0x0, NULL
, HFILL
}},
1336 { &hf_pgm_opt_fragment_offset
,
1337 { "Fragment Offset", "pgm.opts.fragment.fragment_offset", FT_UINT32
, BASE_DEC
,
1338 NULL
, 0x0, NULL
, HFILL
}},
1339 { &hf_pgm_opt_fragment_total_length
,
1340 { "Total Length", "pgm.opts.fragment.total_length", FT_UINT32
, BASE_DEC
,
1341 NULL
, 0x0, NULL
, HFILL
}}
1343 static int *ett
[] = {
1354 &ett_pgm_opts_parityprm
,
1355 &ett_pgm_opts_paritygrp
,
1356 &ett_pgm_opts_naklist
,
1357 &ett_pgm_opts_ccdata
,
1358 &ett_pgm_opts_nak_bo_ivl
,
1359 &ett_pgm_opts_nak_bo_rng
,
1360 &ett_pgm_opts_redirect
,
1361 &ett_pgm_opts_fragment
1363 static ei_register_info ei
[] = {
1364 { &ei_pgm_opt_type
, { "pgm.opts.type.invalid", PI_PROTOCOL
, PI_WARN
, "Invalid option", EXPFILL
}},
1365 { &ei_pgm_opt_tlen
, { "pgm.opts.tlen.invalid", PI_PROTOCOL
, PI_WARN
, "Total Length invalid", EXPFILL
}},
1366 { &ei_pgm_genopt_len
, { "pgm.genopts.len.invalid", PI_PROTOCOL
, PI_WARN
, "Option length invalid", EXPFILL
}},
1367 { &ei_address_format_invalid
, { "pgm.address_format_invalid", PI_PROTOCOL
, PI_WARN
, "Can't handle this address format", EXPFILL
}},
1368 { &ei_pgm_main_cksum
, { "pgm.bad_checksum", PI_CHECKSUM
, PI_ERROR
, "Bad checksum", EXPFILL
}},
1371 module_t
*pgm_module
;
1372 expert_module_t
* expert_pgm
;
1374 proto_pgm
= proto_register_protocol("Pragmatic General Multicast", "PGM", "pgm");
1376 proto_register_field_array(proto_pgm
, hf
, array_length(hf
));
1377 proto_register_subtree_array(ett
, array_length(ett
));
1378 expert_pgm
= expert_register_protocol(proto_pgm
);
1379 expert_register_field_array(expert_pgm
, ei
, array_length(ei
));
1381 /* subdissector code */
1382 pgm_handle
= register_dissector("pgm", dissect_pgm
, proto_pgm
);
1383 subdissector_table
= register_dissector_table("pgm.port",
1384 "PGM port", proto_pgm
, FT_UINT16
, BASE_DEC
);
1385 heur_subdissector_list
= register_heur_dissector_list_with_description("pgm", "PGM data fallback", proto_pgm
);
1388 * Register configuration preferences for UDP encapsulation
1389 * (Note: Initially the ports are set to zero and the ports
1390 * are not registered so the dissecting of PGM
1391 * encapsulated in UDP packets is off by default;
1392 * dissector_add_for_decode_as is called so that pgm
1393 * is available for 'decode-as'
1395 pgm_module
= prefs_register_protocol(proto_pgm
, NULL
);
1397 prefs_register_bool_preference(pgm_module
, "check_checksum",
1398 "Check the validity of the PGM checksum when possible",
1399 "Whether to check the validity of the PGM checksum",
1400 &pgm_check_checksum
);
1403 /* The registration hand-off routine */
1405 * Set up PGM Encap dissecting, which is off by default for UDP
1409 proto_reg_handoff_pgm(void)
1411 dissector_add_uint_range_with_preference("udp.port", "", pgm_handle
);
1412 dissector_add_uint("ip.proto", IP_PROTO_PGM
, pgm_handle
);
1416 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1421 * indent-tabs-mode: t
1424 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1425 * :indentSize=8:tabSize=8:noTabs=false: