2 * Routines for PGM packet disassembly, RFC 3208
6 * Copyright (c) 2000 by Talarian Corp
7 * Rewritten by Jaap Keuter
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1999 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <epan/packet.h>
32 #include <epan/ipproto.h>
33 #include <epan/in_cksum.h>
34 #include <epan/addr_resolv.h>
35 #include <epan/strutil.h>
36 #include <epan/prefs.h>
37 #include <epan/wmem/wmem.h>
38 #include <epan/ptvcursor.h>
41 * Flag to control whether to check the PGM checksum.
43 static gboolean pgm_check_checksum
= TRUE
;
45 void proto_reg_handoff_pgm(void);
47 /* constants for hdr types */
48 #define PGM_SPM_PCKT 0x00
49 #define PGM_ODATA_PCKT 0x04
50 #define PGM_RDATA_PCKT 0x05
51 #define PGM_NAK_PCKT 0x08
52 #define PGM_NNAK_PCKT 0x09
53 #define PGM_NCF_PCKT 0x0A
54 #define PGM_POLL_PCKT 0x01
55 #define PGM_POLR_PCKT 0x02
56 #define PGM_ACK_PCKT 0x0D
58 /* option flags (main PGM header) */
60 #define PGM_OPT_NETSIG 0x02
61 #define PGM_OPT_VAR_PKTLEN 0x40
62 #define PGM_OPT_PARITY 0x80
65 #define PGM_OPT_LENGTH 0x00
66 #define PGM_OPT_END 0x80
67 #define PGM_OPT_FRAGMENT 0x01
68 #define PGM_OPT_NAK_LIST 0x02
69 #define PGM_OPT_JOIN 0x03
70 #define PGM_OPT_REDIRECT 0x07
71 #define PGM_OPT_SYN 0x0D
72 #define PGM_OPT_FIN 0x0E
73 #define PGM_OPT_RST 0x0F
74 #define PGM_OPT_PARITY_PRM 0x08
75 #define PGM_OPT_PARITY_GRP 0x09
76 #define PGM_OPT_CURR_TGSIZE 0x0A
77 #define PGM_OPT_PGMCC_DATA 0x12
78 #define PGM_OPT_PGMCC_FEEDBACK 0x13
79 #define PGM_OPT_NAK_BO_IVL 0x04
80 #define PGM_OPT_NAK_BO_RNG 0x05
83 #define PGM_POLL_GENERAL 0x0
84 #define PGM_POLL_DLR 0x1
87 #define PGM_OPX_IGNORE 0x00
88 #define PGM_OPX_INVAL 0x01
89 #define PGM_OPX_DISCARD 0x10
91 #define PGM_OPT_NAK_LIST_SIZE 4
94 * To squeeze the whole option into 255 bytes, we
95 * can only have 62 in the list
97 #define PGM_MAX_NAK_LIST_SZ (62)
99 #define PGM_OPT_JOIN_SIZE 8
100 #define PGM_OPT_PARITY_PRM_SIZE 8
102 /* OPT_PARITY_PRM P and O bits */
103 #define PGM_OPT_PARITY_PRM_PRO 0x2
104 #define PGM_OPT_PARITY_PRM_OND 0x1
106 #define PGM_OPT_PARITY_GRP_SIZE 8
107 #define PGM_OPT_CURR_TGSIZE_SIZE 8
108 #define PGM_OPT_PGMCC_DATA_SIZE 16
109 #define PGM_OPT_PGMCC_FEEDBACK_SIZE 16
110 #define PGM_OPT_NAK_BO_IVL_SIZE 12
111 #define PGM_OPT_NAK_BO_RNG_SIZE 12
112 #define PGM_OPT_REDIRECT_SIZE 12
113 #define PGM_OPT_FRAGMENT_SIZE 16
116 * Udp port for UDP encapsulation
118 #define DEFAULT_UDP_ENCAP_UCAST_PORT 3055
119 #define DEFAULT_UDP_ENCAP_MCAST_PORT 3056
121 static guint udp_encap_ucast_port
= 0;
122 static guint udp_encap_mcast_port
= 0;
124 static int proto_pgm
= -1;
125 static int ett_pgm
= -1;
126 static int ett_pgm_optbits
= -1;
127 static int ett_pgm_opts
= -1;
128 static int ett_pgm_spm
= -1;
129 static int ett_pgm_data
= -1;
130 static int ett_pgm_nak
= -1;
131 static int ett_pgm_poll
= -1;
132 static int ett_pgm_polr
= -1;
133 static int ett_pgm_ack
= -1;
134 static int ett_pgm_opts_join
= -1;
135 static int ett_pgm_opts_parityprm
= -1;
136 static int ett_pgm_opts_paritygrp
= -1;
137 static int ett_pgm_opts_naklist
= -1;
138 static int ett_pgm_opts_ccdata
= -1;
139 static int ett_pgm_opts_nak_bo_ivl
= -1;
140 static int ett_pgm_opts_nak_bo_rng
= -1;
141 static int ett_pgm_opts_redirect
= -1;
142 static int ett_pgm_opts_fragment
= -1;
144 static int hf_pgm_main_sport
= -1;
145 static int hf_pgm_main_dport
= -1;
146 static int hf_pgm_port
= -1;
147 static int hf_pgm_main_type
= -1;
148 static int hf_pgm_main_opts
= -1;
149 static int hf_pgm_main_opts_opt
= -1;
150 static int hf_pgm_main_opts_netsig
= -1;
151 static int hf_pgm_main_opts_varlen
= -1;
152 static int hf_pgm_main_opts_parity
= -1;
153 static int hf_pgm_main_cksum
= -1;
154 static int hf_pgm_main_cksum_bad
= -1;
155 static int hf_pgm_main_gsi
= -1;
156 static int hf_pgm_main_tsdulen
= -1;
157 static int hf_pgm_spm_sqn
= -1;
158 static int hf_pgm_spm_lead
= -1;
159 static int hf_pgm_spm_trail
= -1;
160 static int hf_pgm_spm_pathafi
= -1;
161 static int hf_pgm_spm_res
= -1;
162 static int hf_pgm_spm_path
= -1;
163 static int hf_pgm_spm_path6
= -1;
164 /* static int hf_pgm_data_sqn = -1; */
165 /* static int hf_pgm_data_trail = -1; */
166 static int hf_pgm_nak_sqn
= -1;
167 static int hf_pgm_nak_srcafi
= -1;
168 static int hf_pgm_nak_srcres
= -1;
169 static int hf_pgm_nak_src
= -1;
170 static int hf_pgm_nak_src6
= -1;
171 static int hf_pgm_nak_grpafi
= -1;
172 static int hf_pgm_nak_grpres
= -1;
173 static int hf_pgm_nak_grp
= -1;
174 static int hf_pgm_nak_grp6
= -1;
175 static int hf_pgm_poll_sqn
= -1;
176 static int hf_pgm_poll_round
= -1;
177 static int hf_pgm_poll_subtype
= -1;
178 static int hf_pgm_poll_pathafi
= -1;
179 static int hf_pgm_poll_res
= -1;
180 static int hf_pgm_poll_path
= -1;
181 static int hf_pgm_poll_path6
= -1;
182 static int hf_pgm_poll_backoff_ivl
= -1;
183 static int hf_pgm_poll_rand_str
= -1;
184 static int hf_pgm_poll_matching_bmask
= -1;
185 static int hf_pgm_polr_sqn
= -1;
186 static int hf_pgm_polr_round
= -1;
187 static int hf_pgm_polr_res
= -1;
188 static int hf_pgm_ack_sqn
= -1;
189 static int hf_pgm_ack_bitmap
= -1;
191 static int hf_pgm_opt_type
= -1;
192 static int hf_pgm_opt_len
= -1;
193 static int hf_pgm_opt_tlen
= -1;
195 static int hf_pgm_genopt_end
= -1;
196 static int hf_pgm_genopt_type
= -1;
197 static int hf_pgm_genopt_len
= -1;
198 static int hf_pgm_genopt_opx
= -1;
200 static int hf_pgm_opt_join_res
= -1;
201 static int hf_pgm_opt_join_minjoin
= -1;
203 static int hf_pgm_opt_parity_prm_po
= -1;
204 static int hf_pgm_opt_parity_prm_prmtgsz
= -1;
206 static int hf_pgm_opt_parity_grp_res
= -1;
207 static int hf_pgm_opt_parity_grp_prmgrp
= -1;
209 static int hf_pgm_opt_nak_res
= -1;
210 static int hf_pgm_opt_nak_list
= -1;
212 static int hf_pgm_opt_ccdata_res
= -1;
213 static int hf_pgm_opt_ccdata_tsp
= -1;
214 static int hf_pgm_opt_ccdata_afi
= -1;
215 static int hf_pgm_opt_ccdata_res2
= -1;
216 static int hf_pgm_opt_ccdata_acker
= -1;
217 static int hf_pgm_opt_ccdata_acker6
= -1;
219 static int hf_pgm_opt_ccfeedbk_res
= -1;
220 static int hf_pgm_opt_ccfeedbk_tsp
= -1;
221 static int hf_pgm_opt_ccfeedbk_afi
= -1;
222 static int hf_pgm_opt_ccfeedbk_lossrate
= -1;
223 static int hf_pgm_opt_ccfeedbk_acker
= -1;
224 static int hf_pgm_opt_ccfeedbk_acker6
= -1;
226 static int hf_pgm_opt_nak_bo_ivl_res
= -1;
227 static int hf_pgm_opt_nak_bo_ivl_bo_ivl
= -1;
228 static int hf_pgm_opt_nak_bo_ivl_bo_ivl_sqn
= -1;
230 static int hf_pgm_opt_nak_bo_rng_res
= -1;
231 static int hf_pgm_opt_nak_bo_rng_min_bo_ivl
= -1;
232 static int hf_pgm_opt_nak_bo_rng_max_bo_ivl
= -1;
234 static int hf_pgm_opt_redirect_res
= -1;
235 static int hf_pgm_opt_redirect_afi
= -1;
236 static int hf_pgm_opt_redirect_res2
= -1;
237 static int hf_pgm_opt_redirect_dlr
= -1;
238 static int hf_pgm_opt_redirect_dlr6
= -1;
240 static int hf_pgm_opt_fragment_res
= -1;
241 static int hf_pgm_opt_fragment_first_sqn
= -1;
242 static int hf_pgm_opt_fragment_offset
= -1;
243 static int hf_pgm_opt_fragment_total_length
= -1;
245 static dissector_table_t subdissector_table
;
246 static heur_dissector_list_t heur_subdissector_list
;
247 static dissector_handle_t data_handle
;
254 gint returned_length
, idx
= 0;
255 const int MAX_STR_LEN
= 256;
260 msg
=(char *)wmem_alloc(wmem_packet_scope(), MAX_STR_LEN
);
262 returned_length
= g_snprintf(&msg
[idx
], MAX_STR_LEN
-idx
, "Present");
263 idx
+= MIN(returned_length
, MAX_STR_LEN
-idx
);
265 if (opts
& PGM_OPT_NETSIG
){
266 returned_length
= g_snprintf(&msg
[idx
], MAX_STR_LEN
-idx
, "%sNetSig", (!idx
)?"":",");
267 idx
+= MIN(returned_length
, MAX_STR_LEN
-idx
);
269 if (opts
& PGM_OPT_VAR_PKTLEN
){
270 returned_length
= g_snprintf(&msg
[idx
], MAX_STR_LEN
-idx
, "%sVarLen", (!idx
)?"":",");
271 idx
+= MIN(returned_length
, MAX_STR_LEN
-idx
);
273 if (opts
& PGM_OPT_PARITY
){
274 returned_length
= g_snprintf(&msg
[idx
], MAX_STR_LEN
-idx
, "%sParity", (!idx
)?"":",");
275 idx
+= MIN(returned_length
, MAX_STR_LEN
-idx
);
278 g_snprintf(&msg
[idx
], MAX_STR_LEN
-idx
, "0x%x", opts
);
283 paritystr(guint8 parity
)
286 gint returned_length
, idx
= 0;
287 const int MAX_STR_LEN
= 256;
292 msg
=(char *)wmem_alloc(wmem_packet_scope(), MAX_STR_LEN
);
293 if (parity
& PGM_OPT_PARITY_PRM_PRO
){
294 returned_length
= g_snprintf(&msg
[idx
], MAX_STR_LEN
-idx
, "Pro-active");
295 idx
+= MIN(returned_length
, MAX_STR_LEN
-idx
);
297 if (parity
& PGM_OPT_PARITY_PRM_OND
){
298 returned_length
= g_snprintf(&msg
[idx
], MAX_STR_LEN
-idx
, "%sOn-demand", (!idx
)?"":",");
299 idx
+= MIN(returned_length
, MAX_STR_LEN
-idx
);
302 g_snprintf(&msg
[idx
], MAX_STR_LEN
-idx
, "0x%x", parity
);
307 static const value_string opt_vals
[] = {
308 { PGM_OPT_LENGTH
, "Length" },
309 { PGM_OPT_END
, "End" },
310 { PGM_OPT_FRAGMENT
, "Fragment" },
311 { PGM_OPT_NAK_LIST
, "NakList" },
312 { PGM_OPT_JOIN
, "Join" },
313 { PGM_OPT_REDIRECT
, "ReDirect" },
314 { PGM_OPT_SYN
, "Syn" },
315 { PGM_OPT_FIN
, "Fin" },
316 { PGM_OPT_RST
, "Rst" },
317 { PGM_OPT_PARITY_PRM
, "ParityPrm" },
318 { PGM_OPT_PARITY_GRP
, "ParityGrp" },
319 { PGM_OPT_CURR_TGSIZE
, "CurrTgsiz" },
320 { PGM_OPT_PGMCC_DATA
, "CcData" },
321 { PGM_OPT_PGMCC_FEEDBACK
, "CcFeedBack" },
322 { PGM_OPT_NAK_BO_IVL
, "NakBackOffIvl" },
323 { PGM_OPT_NAK_BO_RNG
, "NakBackOffRng" },
324 { PGM_OPT_FRAGMENT
, "Fragment" },
328 static const value_string opx_vals
[] = {
329 { PGM_OPX_IGNORE
, "Ignore" },
330 { PGM_OPX_INVAL
, "Inval" },
331 { PGM_OPX_DISCARD
, "DisCard" },
335 static const true_false_string opts_present
= {
341 dissect_pgmopts(ptvcursor_t
* cursor
, const char *pktname
)
344 proto_tree
*opts_tree
= NULL
;
345 proto_tree
*opt_tree
= NULL
;
346 tvbuff_t
*tvb
= ptvcursor_tvbuff(cursor
);
348 gboolean theend
= FALSE
;
350 guint16 opts_total_len
;
353 guint8 opts_type
= tvb_get_guint8(tvb
, ptvcursor_current_offset(cursor
));
355 if (opts_type
!= PGM_OPT_LENGTH
) {
356 proto_tree_add_text(ptvcursor_tree(cursor
), tvb
, ptvcursor_current_offset(cursor
), 1,
357 "%s Options - initial option is %s, should be %s",
359 val_to_str(opts_type
, opt_vals
, "Unknown (0x%02x)"),
360 val_to_str(PGM_OPT_LENGTH
, opt_vals
, "Unknown (0x%02x)"));
364 opts_total_len
= tvb_get_ntohs(tvb
, ptvcursor_current_offset(cursor
)+2);
366 if (opts_total_len
< 4) {
367 proto_tree_add_text(opts_tree
, tvb
, ptvcursor_current_offset(cursor
)+2, 2,
368 "%s Options (Total Length %u - invalid, must be >= 4)",
369 pktname
, opts_total_len
);
373 tf
= proto_tree_add_text(ptvcursor_tree(cursor
), tvb
, ptvcursor_current_offset(cursor
), opts_total_len
,
374 "%s Options (Total Length %d)", pktname
, opts_total_len
);
375 opts_tree
= proto_item_add_subtree(tf
, ett_pgm_opts
);
376 ptvcursor_set_tree(cursor
, opts_tree
);
377 ptvcursor_add(cursor
, hf_pgm_opt_type
, 1, ENC_BIG_ENDIAN
);
378 ptvcursor_add(cursor
, hf_pgm_opt_len
, 1, ENC_BIG_ENDIAN
);
379 ptvcursor_add(cursor
, hf_pgm_opt_tlen
, 2, ENC_BIG_ENDIAN
);
381 for (opts_total_len
-= 4; !theend
&& opts_total_len
!= 0;){
382 if (opts_total_len
< 4) {
383 proto_tree_add_text(opts_tree
, tvb
, ptvcursor_current_offset(cursor
), opts_total_len
,
384 "Remaining total options length doesn't have enough for an options header");
388 genopts_type
= tvb_get_guint8(tvb
, ptvcursor_current_offset(cursor
));
389 genopts_len
= tvb_get_guint8(tvb
, ptvcursor_current_offset(cursor
)+1);
391 if (genopts_type
& PGM_OPT_END
) {
392 genopts_type
&= ~PGM_OPT_END
;
395 if (genopts_len
< 4) {
396 proto_tree_add_text(opts_tree
, tvb
, ptvcursor_current_offset(cursor
), genopts_len
,
397 "Option: %s, Length: %u (invalid, must be >= 4)",
398 val_to_str(genopts_type
, opt_vals
, "Unknown (0x%02x)"),
402 if (opts_total_len
< genopts_len
) {
403 proto_tree_add_text(opts_tree
, tvb
, ptvcursor_current_offset(cursor
), genopts_len
,
404 "Option: %s, Length: %u (> remaining total options length)",
405 val_to_str(genopts_type
, opt_vals
, "Unknown (0x%02x)"),
409 tf
= proto_tree_add_text(opts_tree
, tvb
, ptvcursor_current_offset(cursor
), genopts_len
,
410 "Option: %s, Length: %u",
411 val_to_str(genopts_type
, opt_vals
, "Unknown (0x%02x)"),
414 switch(genopts_type
) {
416 opt_tree
= proto_item_add_subtree(tf
, ett_pgm_opts_join
);
417 ptvcursor_set_tree(cursor
, opt_tree
);
419 ptvcursor_add_no_advance(cursor
, hf_pgm_genopt_end
, 1, ENC_BIG_ENDIAN
);
420 ptvcursor_add(cursor
, hf_pgm_genopt_type
, 1, ENC_BIG_ENDIAN
);
422 if (genopts_len
< PGM_OPT_JOIN_SIZE
) {
423 proto_tree_add_uint_format_value(opt_tree
, hf_pgm_genopt_len
, tvb
,
424 ptvcursor_current_offset(cursor
), 1, genopts_len
,
425 "%u (bogus, must be >= %u)",
426 genopts_len
, PGM_OPT_JOIN_SIZE
);
429 ptvcursor_add(cursor
, hf_pgm_genopt_len
, 1, ENC_BIG_ENDIAN
);
430 ptvcursor_add(cursor
, hf_pgm_genopt_opx
, 1, ENC_BIG_ENDIAN
);
431 ptvcursor_add(cursor
, hf_pgm_opt_join_res
, 1, ENC_BIG_ENDIAN
);
432 ptvcursor_add(cursor
, hf_pgm_opt_join_minjoin
, 4, ENC_BIG_ENDIAN
);
436 case PGM_OPT_PARITY_PRM
:{
439 opt_tree
= proto_item_add_subtree(tf
, ett_pgm_opts_parityprm
);
440 ptvcursor_set_tree(cursor
, opt_tree
);
442 ptvcursor_add_no_advance(cursor
, hf_pgm_genopt_end
, 1, ENC_BIG_ENDIAN
);
443 ptvcursor_add(cursor
, hf_pgm_genopt_type
, 1, ENC_BIG_ENDIAN
);
446 if (genopts_len
< PGM_OPT_PARITY_PRM_SIZE
) {
447 proto_tree_add_uint_format_value(opt_tree
, hf_pgm_genopt_len
, ptvcursor_tvbuff(cursor
),
448 ptvcursor_current_offset(cursor
), 1, genopts_len
,
449 "%u (bogus, must be >= %u)",
450 genopts_len
, PGM_OPT_PARITY_PRM_SIZE
);
453 ptvcursor_add(cursor
, hf_pgm_genopt_len
, 1, ENC_BIG_ENDIAN
);
454 ptvcursor_add(cursor
, hf_pgm_genopt_opx
, 1, ENC_BIG_ENDIAN
);
455 optdata_po
= tvb_get_guint8(tvb
, ptvcursor_current_offset(cursor
));
456 proto_tree_add_uint_format_value(opt_tree
, hf_pgm_opt_parity_prm_po
, tvb
,
457 ptvcursor_current_offset(cursor
), 1, optdata_po
, "%s (0x%x)",
458 paritystr(optdata_po
), optdata_po
);
459 ptvcursor_advance(cursor
, 1);
461 ptvcursor_add(cursor
, hf_pgm_opt_parity_prm_prmtgsz
, 4, ENC_BIG_ENDIAN
);
465 case PGM_OPT_PARITY_GRP
:{
466 opt_tree
= proto_item_add_subtree(tf
, ett_pgm_opts_paritygrp
);
467 ptvcursor_set_tree(cursor
, opt_tree
);
469 ptvcursor_add_no_advance(cursor
, hf_pgm_genopt_end
, 1, ENC_BIG_ENDIAN
);
470 ptvcursor_add(cursor
, hf_pgm_genopt_type
, 1, ENC_BIG_ENDIAN
);
472 if (genopts_len
< PGM_OPT_PARITY_GRP_SIZE
) {
473 proto_tree_add_uint_format_value(opt_tree
, hf_pgm_genopt_len
, tvb
,
474 ptvcursor_current_offset(cursor
), 1, genopts_len
,
475 "%u (bogus, must be >= %u)",
476 genopts_len
, PGM_OPT_PARITY_GRP_SIZE
);
479 ptvcursor_add(cursor
, hf_pgm_genopt_len
, 1, ENC_BIG_ENDIAN
);
480 ptvcursor_add(cursor
, hf_pgm_genopt_opx
, 1, ENC_BIG_ENDIAN
);
481 ptvcursor_add(cursor
, hf_pgm_opt_parity_grp_res
, 1, ENC_BIG_ENDIAN
);
482 ptvcursor_add(cursor
, hf_pgm_opt_parity_grp_prmgrp
, 4, ENC_BIG_ENDIAN
);
486 case PGM_OPT_NAK_LIST
:{
488 guint32 naklist
[PGM_MAX_NAK_LIST_SZ
+1];
489 unsigned char *nakbuf
;
491 int i
, j
, naks
, soffset
;
493 opt_tree
= proto_item_add_subtree(tf
, ett_pgm_opts_naklist
);
494 ptvcursor_set_tree(cursor
, opt_tree
);
496 ptvcursor_add_no_advance(cursor
, hf_pgm_genopt_end
, 1, ENC_BIG_ENDIAN
);
497 ptvcursor_add(cursor
, hf_pgm_genopt_type
, 1, ENC_BIG_ENDIAN
);
499 optdata_len
= tvb_get_guint8(tvb
, ptvcursor_current_offset(cursor
));
500 ptvcursor_add(cursor
, hf_pgm_genopt_len
, 1, ENC_BIG_ENDIAN
);
501 ptvcursor_add(cursor
, hf_pgm_genopt_opx
, 1, ENC_BIG_ENDIAN
);
502 ptvcursor_add(cursor
, hf_pgm_opt_nak_res
, 1, ENC_BIG_ENDIAN
);
504 optdata_len
-= PGM_OPT_NAK_LIST_SIZE
;
505 tvb_memcpy(tvb
, (guint8
*)naklist
, ptvcursor_current_offset(cursor
), optdata_len
);
508 naks
= (int)(optdata_len
/sizeof(guint32
));
509 nakbuf
= (unsigned char *)wmem_alloc(wmem_packet_scope(), 8192);
512 * Print out 8 per line
514 for (i
=0; i
< naks
; i
++) {
515 soffset
+= MIN(8192-soffset
,
516 g_snprintf(nakbuf
+soffset
, 8192-soffset
, "0x%lx ",
517 (unsigned long)g_ntohl(naklist
[i
])));
518 if ((++j
% 8) == 0) {
520 proto_tree_add_bytes_format(opt_tree
,
521 hf_pgm_opt_nak_list
, tvb
, ptvcursor_current_offset(cursor
), j
*4,
522 nakbuf
, "List(%d): %s", naks
, nakbuf
);
526 proto_tree_add_bytes_format_value(opt_tree
,
527 hf_pgm_opt_nak_list
, tvb
, ptvcursor_current_offset(cursor
), j
*4,
528 nakbuf
, "%s", nakbuf
);
531 ptvcursor_advance(cursor
, j
*4);
537 proto_tree_add_bytes_format(opt_tree
,
538 hf_pgm_opt_nak_list
, tvb
, ptvcursor_current_offset(cursor
), j
*4,
539 nakbuf
, "List(%d): %s", naks
, nakbuf
);
541 proto_tree_add_bytes_format_value(opt_tree
,
542 hf_pgm_opt_nak_list
, tvb
, ptvcursor_current_offset(cursor
), j
*4,
543 nakbuf
, "%s", nakbuf
);
545 ptvcursor_advance(cursor
, j
*4);
549 case PGM_OPT_PGMCC_DATA
:{
552 opt_tree
= proto_item_add_subtree(tf
, ett_pgm_opts_ccdata
);
553 ptvcursor_set_tree(cursor
, opt_tree
);
555 ptvcursor_add_no_advance(cursor
, hf_pgm_genopt_end
, 1, ENC_BIG_ENDIAN
);
556 ptvcursor_add(cursor
, hf_pgm_genopt_type
, 1, ENC_BIG_ENDIAN
);
558 if (genopts_len
< PGM_OPT_PGMCC_DATA_SIZE
) {
559 proto_tree_add_uint_format_value(opt_tree
, hf_pgm_genopt_len
, tvb
,
560 ptvcursor_current_offset(cursor
), 1, genopts_len
,
561 "%u (bogus, must be >= %u)",
562 genopts_len
, PGM_OPT_PGMCC_DATA_SIZE
);
565 ptvcursor_add(cursor
, hf_pgm_genopt_len
, 1, ENC_BIG_ENDIAN
);
566 ptvcursor_add(cursor
, hf_pgm_genopt_opx
, 1, ENC_BIG_ENDIAN
);
567 ptvcursor_add(cursor
, hf_pgm_opt_ccdata_res
, 1, ENC_BIG_ENDIAN
);
568 ptvcursor_add(cursor
, hf_pgm_opt_ccdata_tsp
, 4, ENC_BIG_ENDIAN
);
569 optdata_afi
= tvb_get_ntohs(tvb
, ptvcursor_current_offset(cursor
));
570 ptvcursor_add(cursor
, hf_pgm_opt_ccdata_afi
, 2, ENC_BIG_ENDIAN
);
571 ptvcursor_add(cursor
, hf_pgm_opt_ccdata_res2
, 2, ENC_BIG_ENDIAN
);
573 switch (optdata_afi
) {
576 ptvcursor_add(cursor
, hf_pgm_opt_ccdata_acker
, 4, ENC_BIG_ENDIAN
);
580 ptvcursor_add(cursor
, hf_pgm_opt_ccdata_acker6
, 16, ENC_NA
);
584 proto_tree_add_text(opt_tree
, tvb
, ptvcursor_current_offset(cursor
), -1,
585 "Can't handle this address format");
591 case PGM_OPT_PGMCC_FEEDBACK
:{
594 opt_tree
= proto_item_add_subtree(tf
, ett_pgm_opts_ccdata
);
595 ptvcursor_set_tree(cursor
, opt_tree
);
597 ptvcursor_add_no_advance(cursor
, hf_pgm_genopt_end
, 1, ENC_BIG_ENDIAN
);
598 ptvcursor_add(cursor
, hf_pgm_genopt_type
, 1, ENC_BIG_ENDIAN
);
600 if (genopts_len
< PGM_OPT_PGMCC_FEEDBACK_SIZE
) {
601 proto_tree_add_uint_format_value(opt_tree
, hf_pgm_genopt_len
, tvb
,
602 ptvcursor_current_offset(cursor
), 1, genopts_len
,
603 "%u (bogus, must be >= %u)",
604 genopts_len
, PGM_OPT_PGMCC_FEEDBACK_SIZE
);
607 ptvcursor_add(cursor
, hf_pgm_genopt_len
, 1, ENC_BIG_ENDIAN
);
608 ptvcursor_add(cursor
, hf_pgm_genopt_opx
, 1, ENC_BIG_ENDIAN
);
609 ptvcursor_add(cursor
, hf_pgm_opt_ccfeedbk_res
, 1, ENC_BIG_ENDIAN
);
610 ptvcursor_add(cursor
, hf_pgm_opt_ccfeedbk_tsp
, 4, ENC_BIG_ENDIAN
);
611 optdata_afi
= tvb_get_ntohs(tvb
, ptvcursor_current_offset(cursor
));
612 ptvcursor_add(cursor
, hf_pgm_opt_ccfeedbk_afi
, 2, ENC_BIG_ENDIAN
);
613 ptvcursor_add(cursor
, hf_pgm_opt_ccfeedbk_lossrate
, 2, ENC_BIG_ENDIAN
);
615 switch (optdata_afi
) {
618 ptvcursor_add(cursor
, hf_pgm_opt_ccfeedbk_acker
, 4, ENC_BIG_ENDIAN
);
622 ptvcursor_add(cursor
, hf_pgm_opt_ccfeedbk_acker6
, 16, ENC_NA
);
626 proto_tree_add_text(opt_tree
, tvb
, ptvcursor_current_offset(cursor
), -1,
627 "Can't handle this address format");
633 case PGM_OPT_NAK_BO_IVL
:{
634 opt_tree
= proto_item_add_subtree(tf
, ett_pgm_opts_nak_bo_ivl
);
635 ptvcursor_set_tree(cursor
, opt_tree
);
637 ptvcursor_add_no_advance(cursor
, hf_pgm_genopt_end
, 1, ENC_BIG_ENDIAN
);
638 ptvcursor_add(cursor
, hf_pgm_genopt_type
, 1, ENC_BIG_ENDIAN
);
640 if (genopts_len
< PGM_OPT_NAK_BO_IVL_SIZE
) {
641 proto_tree_add_uint_format_value(opt_tree
, hf_pgm_genopt_len
, tvb
,
642 ptvcursor_current_offset(cursor
), 1, genopts_len
,
643 "%u (bogus, must be >= %u)",
644 genopts_len
, PGM_OPT_NAK_BO_IVL_SIZE
);
647 ptvcursor_add(cursor
, hf_pgm_genopt_len
, 1, ENC_BIG_ENDIAN
);
648 ptvcursor_add(cursor
, hf_pgm_genopt_opx
, 1, ENC_BIG_ENDIAN
);
649 ptvcursor_add(cursor
, hf_pgm_opt_nak_bo_ivl_res
, 1, ENC_BIG_ENDIAN
);
650 ptvcursor_add(cursor
, hf_pgm_opt_nak_bo_ivl_bo_ivl
, 4, ENC_BIG_ENDIAN
);
651 ptvcursor_add(cursor
, hf_pgm_opt_nak_bo_ivl_bo_ivl_sqn
, 4, ENC_BIG_ENDIAN
);
655 case PGM_OPT_NAK_BO_RNG
:{
656 opt_tree
= proto_item_add_subtree(tf
, ett_pgm_opts_nak_bo_rng
);
657 ptvcursor_set_tree(cursor
, opt_tree
);
659 ptvcursor_add_no_advance(cursor
, hf_pgm_genopt_end
, 1, ENC_BIG_ENDIAN
);
660 ptvcursor_add(cursor
, hf_pgm_genopt_type
, 1, ENC_BIG_ENDIAN
);
662 if (genopts_len
< PGM_OPT_NAK_BO_RNG_SIZE
) {
663 proto_tree_add_uint_format_value(opt_tree
, hf_pgm_genopt_len
, tvb
,
664 ptvcursor_current_offset(cursor
), 1, genopts_len
,
665 "%u (bogus, must be >= %u)",
666 genopts_len
, PGM_OPT_NAK_BO_RNG_SIZE
);
669 ptvcursor_add(cursor
, hf_pgm_genopt_len
, 1, ENC_BIG_ENDIAN
);
670 ptvcursor_add(cursor
, hf_pgm_genopt_opx
, 1, ENC_BIG_ENDIAN
);
671 ptvcursor_add(cursor
, hf_pgm_opt_nak_bo_rng_res
, 1, ENC_BIG_ENDIAN
);
672 ptvcursor_add(cursor
, hf_pgm_opt_nak_bo_rng_min_bo_ivl
, 4, ENC_BIG_ENDIAN
);
673 ptvcursor_add(cursor
, hf_pgm_opt_nak_bo_rng_max_bo_ivl
, 4, ENC_BIG_ENDIAN
);
677 case PGM_OPT_REDIRECT
:{
680 opt_tree
= proto_item_add_subtree(tf
, ett_pgm_opts_redirect
);
681 ptvcursor_set_tree(cursor
, opt_tree
);
683 ptvcursor_add_no_advance(cursor
, hf_pgm_genopt_end
, 1, ENC_BIG_ENDIAN
);
684 ptvcursor_add(cursor
, hf_pgm_genopt_type
, 1, ENC_BIG_ENDIAN
);
686 if (genopts_len
< PGM_OPT_REDIRECT_SIZE
) {
687 proto_tree_add_uint_format_value(opt_tree
, hf_pgm_genopt_len
, tvb
,
688 ptvcursor_current_offset(cursor
), 1, genopts_len
,
689 "%u (bogus, must be >= %u)",
690 genopts_len
, PGM_OPT_REDIRECT_SIZE
);
693 ptvcursor_add(cursor
, hf_pgm_genopt_len
, 1, ENC_BIG_ENDIAN
);
694 ptvcursor_add(cursor
, hf_pgm_genopt_opx
, 1, ENC_BIG_ENDIAN
);
695 ptvcursor_add(cursor
, hf_pgm_opt_redirect_res
, 1, ENC_BIG_ENDIAN
);
696 optdata_afi
= tvb_get_ntohs(tvb
, ptvcursor_current_offset(cursor
));
697 ptvcursor_add(cursor
, hf_pgm_opt_redirect_afi
, 2, ENC_BIG_ENDIAN
);
698 ptvcursor_add(cursor
, hf_pgm_opt_redirect_res2
, 2, ENC_BIG_ENDIAN
);
700 switch (optdata_afi
) {
703 ptvcursor_add(cursor
, hf_pgm_opt_redirect_dlr
, 4, ENC_BIG_ENDIAN
);
707 ptvcursor_add(cursor
, hf_pgm_opt_redirect_dlr6
, 16, ENC_NA
);
711 proto_tree_add_text(opt_tree
, tvb
, ptvcursor_current_offset(cursor
), -1,
712 "Can't handle this address format");
718 case PGM_OPT_FRAGMENT
:{
719 opt_tree
= proto_item_add_subtree(tf
, ett_pgm_opts_fragment
);
720 ptvcursor_set_tree(cursor
, opt_tree
);
722 ptvcursor_add_no_advance(cursor
, hf_pgm_genopt_end
, 1, ENC_BIG_ENDIAN
);
723 ptvcursor_add(cursor
, hf_pgm_genopt_type
, 1, ENC_BIG_ENDIAN
);
725 if (genopts_len
< PGM_OPT_FRAGMENT_SIZE
) {
726 proto_tree_add_uint_format_value(opt_tree
, hf_pgm_genopt_len
, tvb
,
727 ptvcursor_current_offset(cursor
), 1, genopts_len
,
728 "%u (bogus, must be >= %u)",
729 genopts_len
, PGM_OPT_FRAGMENT_SIZE
);
732 ptvcursor_add(cursor
, hf_pgm_genopt_len
, 1, ENC_BIG_ENDIAN
);
733 ptvcursor_add(cursor
, hf_pgm_genopt_opx
, 1, ENC_BIG_ENDIAN
);
734 ptvcursor_add(cursor
, hf_pgm_opt_fragment_res
, 1, ENC_BIG_ENDIAN
);
735 ptvcursor_add(cursor
, hf_pgm_opt_fragment_first_sqn
, 4, ENC_BIG_ENDIAN
);
736 ptvcursor_add(cursor
, hf_pgm_opt_fragment_offset
, 4, ENC_BIG_ENDIAN
);
737 ptvcursor_add(cursor
, hf_pgm_opt_fragment_total_length
, 4, ENC_BIG_ENDIAN
);
742 ptvcursor_advance(cursor
, genopts_len
);
747 opts_total_len
-= genopts_len
;
752 static const value_string type_vals
[] = {
753 { PGM_SPM_PCKT
, "SPM" },
754 { PGM_RDATA_PCKT
, "RDATA" },
755 { PGM_ODATA_PCKT
, "ODATA" },
756 { PGM_NAK_PCKT
, "NAK" },
757 { PGM_NNAK_PCKT
, "NNAK" },
758 { PGM_NCF_PCKT
, "NCF" },
759 { PGM_POLL_PCKT
, "POLL" },
760 { PGM_POLR_PCKT
, "POLR" },
761 { PGM_ACK_PCKT
, "ACK" },
765 static const value_string poll_subtype_vals
[] = {
766 { PGM_POLL_GENERAL
, "General" },
767 { PGM_POLL_DLR
, "DLR" },
771 /* Determine if there is a sub-dissector and call it. This has been */
772 /* separated into a stand alone routine to other protocol dissectors */
773 /* can call to it, ie. socks */
776 decode_pgm_ports(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
,
777 proto_tree
*tree
, guint16 pgmhdr_sport
, guint16 pgmhdr_dport
)
782 next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
784 /* do lookup with the subdissector table */
785 found
= dissector_try_uint(subdissector_table
, pgmhdr_sport
,
786 next_tvb
, pinfo
, tree
);
790 found
= dissector_try_uint(subdissector_table
, pgmhdr_dport
,
791 next_tvb
, pinfo
, tree
);
795 /* do lookup with the heuristic subdissector table */
796 if (dissector_try_heuristic(heur_subdissector_list
, next_tvb
, pinfo
, tree
, NULL
))
799 /* Oh, well, we don't know this; dissect it as data. */
800 call_dissector(data_handle
,next_tvb
, pinfo
, tree
);
804 * dissect_pgm - The dissector for Pragmatic General Multicast
807 dissect_pgm(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
809 guint16 pgmhdr_sport
;
810 guint16 pgmhdr_dport
;
813 guint16 pgmhdr_cksum
;
814 guint16 pgmhdr_tsdulen
;
821 const char *pollstname
;
823 gboolean isdata
= FALSE
;
824 guint pgmlen
, reportedlen
;
826 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "PGM");
828 col_clear(pinfo
->cinfo
, COL_INFO
);
829 if (tvb_reported_length_remaining(tvb
, 0) < 18) {
830 col_set_str(pinfo
->cinfo
, COL_INFO
,
835 pinfo
->srcport
= pgmhdr_sport
= tvb_get_ntohs(tvb
, 0);
836 pinfo
->destport
= pgmhdr_dport
= tvb_get_ntohs(tvb
, 2);
838 pgmhdr_type
= tvb_get_guint8(tvb
, 4);
839 pktname
= val_to_str(pgmhdr_type
, type_vals
, "Unknown (0x%02x)");
841 pgmhdr_opts
= tvb_get_guint8(tvb
, 5);
842 pgmhdr_cksum
= tvb_get_ntohs(tvb
, 6);
843 gsi
= tvb_bytes_to_str(tvb
, 8, 6);
844 pgmhdr_tsdulen
= tvb_get_ntohs(tvb
, 14);
845 sqn
= tvb_get_ntohl(tvb
, 16);
847 switch(pgmhdr_type
) {
854 col_add_fstr(pinfo
->cinfo
, COL_INFO
,
855 "%-5s sqn 0x%x gsi %s", pktname
, sqn
, gsi
);
859 col_add_fstr(pinfo
->cinfo
, COL_INFO
,
860 "%-5s sqn 0x%x gsi %s tsdulen %d", pktname
, sqn
, gsi
,
865 case PGM_POLL_PCKT
: {
866 guint16 poll_stype
= tvb_get_ntohs(tvb
, 22);
867 pollstname
= val_to_str(poll_stype
, poll_subtype_vals
, "Unknown (0x%02x)");
869 col_add_fstr(pinfo
->cinfo
, COL_INFO
,
870 "%-5s sqn 0x%x gsi %s subtype %s",
871 pktname
, sqn
, gsi
, pollstname
);
879 proto_tree
*pgm_tree
= NULL
;
880 proto_tree
*opt_tree
= NULL
;
881 proto_tree
*type_tree
= NULL
;
882 proto_item
*tf
, *hidden_item
;
885 ti
= proto_tree_add_protocol_format(tree
, proto_pgm
,
887 "Pragmatic General Multicast: Type %s"
888 " Src Port %u, Dst Port %u, GSI %s", pktname
,
889 pgmhdr_sport
, pgmhdr_dport
, gsi
);
891 pgm_tree
= proto_item_add_subtree(ti
, ett_pgm
);
893 cursor
= ptvcursor_new(pgm_tree
, tvb
, 0);
895 hidden_item
= proto_tree_add_item(pgm_tree
, hf_pgm_port
, tvb
, 0, 2, ENC_BIG_ENDIAN
);
896 PROTO_ITEM_SET_HIDDEN(hidden_item
);
897 hidden_item
= proto_tree_add_item(pgm_tree
, hf_pgm_port
, tvb
, 2, 2, ENC_BIG_ENDIAN
);
898 PROTO_ITEM_SET_HIDDEN(hidden_item
);
899 ptvcursor_add(cursor
, hf_pgm_main_sport
, 2, ENC_BIG_ENDIAN
);
900 ptvcursor_add(cursor
, hf_pgm_main_dport
, 2, ENC_BIG_ENDIAN
);
901 ptvcursor_add(cursor
, hf_pgm_main_type
, 1, ENC_BIG_ENDIAN
);
903 tf
= proto_tree_add_uint_format_value(pgm_tree
, hf_pgm_main_opts
, tvb
,
904 ptvcursor_current_offset(cursor
), 1, pgmhdr_opts
, "%s (0x%x)",
905 optsstr(pgmhdr_opts
), pgmhdr_opts
);
906 opt_tree
= proto_item_add_subtree(tf
, ett_pgm_optbits
);
907 ptvcursor_set_tree(cursor
, opt_tree
);
909 ptvcursor_add_no_advance(cursor
, hf_pgm_main_opts_opt
, 1, ENC_BIG_ENDIAN
);
910 ptvcursor_add_no_advance(cursor
, hf_pgm_main_opts_netsig
, 1, ENC_BIG_ENDIAN
);
911 ptvcursor_add_no_advance(cursor
, hf_pgm_main_opts_varlen
, 1, ENC_BIG_ENDIAN
);
912 ptvcursor_add(cursor
, hf_pgm_main_opts_parity
, 1, ENC_BIG_ENDIAN
);
913 ptvcursor_set_tree(cursor
, pgm_tree
);
915 /* Checksum may be 0 (not available), but not for DATA packets */
916 if ((pgmhdr_type
!= PGM_RDATA_PCKT
) && (pgmhdr_type
!= PGM_ODATA_PCKT
) &&
919 proto_tree_add_uint_format_value(pgm_tree
, hf_pgm_main_cksum
, tvb
,
920 ptvcursor_current_offset(cursor
), 2, pgmhdr_cksum
, "not available");
922 reportedlen
= tvb_reported_length(tvb
);
923 pgmlen
= tvb_length(tvb
);
924 if (pgm_check_checksum
&& pgmlen
>= reportedlen
) {
926 guint16 computed_cksum
;
928 cksum_vec
[0].ptr
= tvb_get_ptr(tvb
, 0, pgmlen
);
929 cksum_vec
[0].len
= pgmlen
;
930 computed_cksum
= in_cksum(&cksum_vec
[0], 1);
931 if (computed_cksum
== 0) {
932 proto_tree_add_uint_format_value(pgm_tree
, hf_pgm_main_cksum
, tvb
,
933 ptvcursor_current_offset(cursor
), 2, pgmhdr_cksum
, "0x%04x [correct]", pgmhdr_cksum
);
935 hidden_item
= proto_tree_add_boolean(pgm_tree
, hf_pgm_main_cksum_bad
, tvb
,
936 ptvcursor_current_offset(cursor
), 2, TRUE
);
937 PROTO_ITEM_SET_HIDDEN(hidden_item
);
938 proto_tree_add_uint_format_value(pgm_tree
, hf_pgm_main_cksum
, tvb
,
939 ptvcursor_current_offset(cursor
), 2, pgmhdr_cksum
, "0x%04x [incorrect, should be 0x%04x]",
940 pgmhdr_cksum
, in_cksum_shouldbe(pgmhdr_cksum
, computed_cksum
));
943 ptvcursor_add_no_advance(cursor
, hf_pgm_main_cksum
, 2, ENC_BIG_ENDIAN
);
946 ptvcursor_advance(cursor
, 2);
948 ptvcursor_add(cursor
, hf_pgm_main_gsi
, 6, ENC_NA
);
949 ptvcursor_add(cursor
, hf_pgm_main_tsdulen
, 2, ENC_BIG_ENDIAN
);
951 tf
= proto_tree_add_text(pgm_tree
, tvb
, ptvcursor_current_offset(cursor
), plen
, "%s Packet", pktname
);
952 switch(pgmhdr_type
) {
954 type_tree
= proto_item_add_subtree(tf
, ett_pgm_spm
);
955 ptvcursor_set_tree(cursor
, type_tree
);
957 ptvcursor_add(cursor
, hf_pgm_spm_sqn
, 4, ENC_BIG_ENDIAN
);
958 ptvcursor_add(cursor
, hf_pgm_spm_trail
, 4, ENC_BIG_ENDIAN
);
959 ptvcursor_add(cursor
, hf_pgm_spm_lead
, 4, ENC_BIG_ENDIAN
);
960 afi
= tvb_get_ntohs(tvb
, ptvcursor_current_offset(cursor
));
961 ptvcursor_add(cursor
, hf_pgm_spm_pathafi
, 2, ENC_BIG_ENDIAN
);
962 ptvcursor_add(cursor
, hf_pgm_spm_res
, 2, ENC_BIG_ENDIAN
);
966 ptvcursor_add(cursor
, hf_pgm_spm_path
, 4, ENC_BIG_ENDIAN
);
970 ptvcursor_add(cursor
, hf_pgm_spm_path6
, 16, ENC_NA
);
974 proto_tree_add_text(type_tree
, tvb
, ptvcursor_current_offset(cursor
), -1,
975 "Can't handle this address format");
981 type_tree
= proto_item_add_subtree(tf
, ett_pgm_data
);
982 ptvcursor_set_tree(cursor
, type_tree
);
984 ptvcursor_add(cursor
, hf_pgm_spm_sqn
, 4, ENC_BIG_ENDIAN
);
985 ptvcursor_add(cursor
, hf_pgm_spm_trail
, 4, ENC_BIG_ENDIAN
);
990 type_tree
= proto_item_add_subtree(tf
, ett_pgm_nak
);
991 ptvcursor_set_tree(cursor
, type_tree
);
993 ptvcursor_add(cursor
, hf_pgm_nak_sqn
, 4, ENC_BIG_ENDIAN
);
994 afi
= tvb_get_ntohs(tvb
, ptvcursor_current_offset(cursor
));
995 ptvcursor_add(cursor
, hf_pgm_nak_srcafi
, 2, ENC_BIG_ENDIAN
);
996 ptvcursor_add(cursor
, hf_pgm_nak_srcres
, 2, ENC_BIG_ENDIAN
);
1000 ptvcursor_add(cursor
, hf_pgm_nak_src
, 4, ENC_BIG_ENDIAN
);
1004 ptvcursor_add(cursor
, hf_pgm_nak_src6
, 16, ENC_NA
);
1008 proto_tree_add_text(type_tree
, tvb
, ptvcursor_current_offset(cursor
), -1,
1009 "Can't handle this address format");
1013 afi
= tvb_get_ntohs(tvb
, ptvcursor_current_offset(cursor
));
1014 ptvcursor_add(cursor
, hf_pgm_nak_grpafi
, 2, ENC_BIG_ENDIAN
);
1015 ptvcursor_add(cursor
, hf_pgm_nak_grpres
, 2, ENC_BIG_ENDIAN
);
1019 ptvcursor_add(cursor
, hf_pgm_nak_grp
, 4, ENC_BIG_ENDIAN
);
1023 ptvcursor_add(cursor
, hf_pgm_nak_grp6
, 16, ENC_NA
);
1027 proto_tree_add_text(type_tree
, tvb
, ptvcursor_current_offset(cursor
), -1,
1028 "Can't handle this address format");
1033 type_tree
= proto_item_add_subtree(tf
, ett_pgm_poll
);
1034 ptvcursor_set_tree(cursor
, type_tree
);
1036 ptvcursor_add(cursor
, hf_pgm_poll_sqn
, 4, ENC_BIG_ENDIAN
);
1037 ptvcursor_add(cursor
, hf_pgm_poll_round
, 2, ENC_BIG_ENDIAN
);
1038 ptvcursor_add(cursor
, hf_pgm_poll_subtype
, 2, ENC_BIG_ENDIAN
);
1039 afi
= tvb_get_ntohs(tvb
, ptvcursor_current_offset(cursor
));
1040 ptvcursor_add(cursor
, hf_pgm_poll_pathafi
, 2, ENC_BIG_ENDIAN
);
1041 ptvcursor_add(cursor
, hf_pgm_poll_res
, 2, ENC_BIG_ENDIAN
);
1045 ptvcursor_add(cursor
, hf_pgm_poll_path
, 4, ENC_BIG_ENDIAN
);
1049 ptvcursor_add(cursor
, hf_pgm_poll_path6
, 16, ENC_NA
);
1053 proto_tree_add_text(type_tree
, tvb
, ptvcursor_current_offset(cursor
), -1,
1054 "Can't handle this address format");
1058 ptvcursor_add(cursor
, hf_pgm_poll_backoff_ivl
, 4, ENC_BIG_ENDIAN
);
1059 ptvcursor_add(cursor
, hf_pgm_poll_rand_str
, 4, ENC_BIG_ENDIAN
);
1060 ptvcursor_add(cursor
, hf_pgm_poll_matching_bmask
, 4, ENC_BIG_ENDIAN
);
1063 type_tree
= proto_item_add_subtree(tf
, ett_pgm_polr
);
1064 ptvcursor_set_tree(cursor
, type_tree
);
1066 ptvcursor_add(cursor
, hf_pgm_polr_sqn
, 4, ENC_BIG_ENDIAN
);
1067 ptvcursor_add(cursor
, hf_pgm_polr_round
, 2, ENC_BIG_ENDIAN
);
1068 ptvcursor_add(cursor
, hf_pgm_polr_res
, 2, ENC_BIG_ENDIAN
);
1071 type_tree
= proto_item_add_subtree(tf
, ett_pgm_ack
);
1072 ptvcursor_set_tree(cursor
, type_tree
);
1074 ptvcursor_add(cursor
, hf_pgm_ack_sqn
, 4, ENC_BIG_ENDIAN
);
1075 ptvcursor_add(cursor
, hf_pgm_ack_bitmap
, 4, ENC_BIG_ENDIAN
);
1079 if (pgmhdr_opts
& PGM_OPT
)
1080 dissect_pgmopts(cursor
, pktname
);
1083 decode_pgm_ports(tvb
, ptvcursor_current_offset(cursor
), pinfo
, tree
, pgmhdr_sport
, pgmhdr_dport
);
1087 /* Register all the bits needed with the filtering engine */
1089 proto_register_pgm(void)
1091 static hf_register_info hf
[] = {
1092 { &hf_pgm_main_sport
,
1093 { "Source Port", "pgm.hdr.sport", FT_UINT16
, BASE_DEC
,
1094 NULL
, 0x0, NULL
, HFILL
}},
1095 { &hf_pgm_main_dport
,
1096 { "Destination Port", "pgm.hdr.dport", FT_UINT16
, BASE_DEC
,
1097 NULL
, 0x0, NULL
, HFILL
}},
1099 { "Port", "pgm.port", FT_UINT16
, BASE_DEC
,
1100 NULL
, 0x0, NULL
, HFILL
}},
1101 { &hf_pgm_main_type
,
1102 { "Type", "pgm.hdr.type", FT_UINT8
, BASE_HEX
,
1103 VALS(type_vals
), 0x0, NULL
, HFILL
}},
1104 { &hf_pgm_main_opts
,
1105 { "Options", "pgm.hdr.opts", FT_UINT8
, BASE_HEX
,
1106 NULL
, 0x0, NULL
, HFILL
}},
1107 { &hf_pgm_main_opts_opt
,
1108 { "Options", "pgm.hdr.opts.opt", FT_BOOLEAN
, 8,
1109 TFS(&opts_present
), PGM_OPT
, NULL
, HFILL
}},
1110 { &hf_pgm_main_opts_netsig
,
1111 { "Network Significant Options", "pgm.hdr.opts.netsig",
1113 TFS(&opts_present
), PGM_OPT_NETSIG
, NULL
, HFILL
}},
1114 { &hf_pgm_main_opts_varlen
,
1115 { "Variable length Parity Packet Option", "pgm.hdr.opts.varlen",
1117 TFS(&opts_present
), PGM_OPT_VAR_PKTLEN
, NULL
, HFILL
}},
1118 { &hf_pgm_main_opts_parity
,
1119 { "Parity", "pgm.hdr.opts.parity", FT_BOOLEAN
, 8,
1120 TFS(&opts_present
), PGM_OPT_PARITY
, NULL
, HFILL
}},
1121 { &hf_pgm_main_cksum
,
1122 { "Checksum", "pgm.hdr.cksum", FT_UINT16
, BASE_HEX
,
1123 NULL
, 0x0, NULL
, HFILL
}},
1124 { &hf_pgm_main_cksum_bad
,
1125 { "Bad Checksum", "pgm.hdr.cksum_bad", FT_BOOLEAN
, BASE_NONE
,
1126 NULL
, 0x0, NULL
, HFILL
}},
1128 { "Global Source Identifier", "pgm.hdr.gsi", FT_BYTES
, BASE_NONE
,
1129 NULL
, 0x0, NULL
, HFILL
}},
1130 { &hf_pgm_main_tsdulen
,
1131 { "Transport Service Data Unit Length", "pgm.hdr.tsdulen", FT_UINT16
,
1132 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1134 { "Sequence number", "pgm.spm.sqn", FT_UINT32
, BASE_HEX
,
1135 NULL
, 0x0, NULL
, HFILL
}},
1136 { &hf_pgm_spm_trail
,
1137 { "Trailing Edge Sequence Number", "pgm.spm.trail", FT_UINT32
, BASE_HEX
,
1138 NULL
, 0x0, NULL
, HFILL
}},
1140 { "Leading Edge Sequence Number", "pgm.spm.lead", FT_UINT32
, BASE_HEX
,
1141 NULL
, 0x0, NULL
, HFILL
}},
1142 { &hf_pgm_spm_pathafi
,
1143 { "Path NLA AFI", "pgm.spm.pathafi", FT_UINT16
, BASE_DEC
,
1144 VALS(afn_vals
), 0x0, NULL
, HFILL
}},
1146 { "Reserved", "pgm.spm.res", FT_UINT16
, BASE_HEX
,
1147 NULL
, 0x0, NULL
, HFILL
}},
1149 { "Path NLA", "pgm.spm.path", FT_IPv4
, BASE_NONE
,
1150 NULL
, 0x0, NULL
, HFILL
}},
1151 { &hf_pgm_spm_path6
,
1152 { "Path NLA", "pgm.spm.path", FT_IPv6
, BASE_NONE
,
1153 NULL
, 0x0, NULL
, HFILL
}},
1156 { "Data Packet Sequence Number", "pgm.data.sqn", FT_UINT32
, BASE_HEX
,
1157 NULL
, 0x0, NULL
, HFILL
}},
1160 { &hf_pgm_data_trail
,
1161 { "Trailing Edge Sequence Number", "pgm.data.trail", FT_UINT32
, BASE_HEX
,
1162 NULL
, 0x0, NULL
, HFILL
}},
1165 { "Requested Sequence Number", "pgm.nak.sqn", FT_UINT32
, BASE_HEX
,
1166 NULL
, 0x0, NULL
, HFILL
}},
1167 { &hf_pgm_nak_srcafi
,
1168 { "Source NLA AFI", "pgm.nak.srcafi", FT_UINT16
, BASE_DEC
,
1169 VALS(afn_vals
), 0x0, NULL
, HFILL
}},
1170 { &hf_pgm_nak_srcres
,
1171 { "Reserved", "pgm.nak.srcres", FT_UINT16
, BASE_HEX
,
1172 NULL
, 0x0, NULL
, HFILL
}},
1174 { "Source NLA", "pgm.nak.src", FT_IPv4
, BASE_NONE
,
1175 NULL
, 0x0, NULL
, HFILL
}},
1177 { "Source NLA", "pgm.nak.src", FT_IPv6
, BASE_NONE
,
1178 NULL
, 0x0, NULL
, HFILL
}},
1179 { &hf_pgm_nak_grpafi
,
1180 { "Multicast Group AFI", "pgm.nak.grpafi", FT_UINT16
, BASE_DEC
,
1181 VALS(afn_vals
), 0x0, NULL
, HFILL
}},
1182 { &hf_pgm_nak_grpres
,
1183 { "Reserved", "pgm.nak.grpres", FT_UINT16
, BASE_HEX
,
1184 NULL
, 0x0, NULL
, HFILL
}},
1186 { "Multicast Group NLA", "pgm.nak.grp", FT_IPv4
, BASE_NONE
,
1187 NULL
, 0x0, NULL
, HFILL
}},
1189 { "Multicast Group NLA", "pgm.nak.grp", FT_IPv6
, BASE_NONE
,
1190 NULL
, 0x0, NULL
, HFILL
}},
1192 { "Sequence Number", "pgm.poll.sqn", FT_UINT32
, BASE_HEX
,
1193 NULL
, 0x0, NULL
, HFILL
}},
1194 { &hf_pgm_poll_round
,
1195 { "Round", "pgm.poll.round", FT_UINT16
, BASE_DEC
,
1196 NULL
, 0x0, NULL
, HFILL
}},
1197 { &hf_pgm_poll_subtype
,
1198 { "Subtype", "pgm.poll.subtype", FT_UINT16
, BASE_HEX
,
1199 VALS(poll_subtype_vals
), 0x0, NULL
, HFILL
}},
1200 { &hf_pgm_poll_pathafi
,
1201 { "Path NLA AFI", "pgm.poll.pathafi", FT_UINT16
, BASE_DEC
,
1202 VALS(afn_vals
), 0x0, NULL
, HFILL
}},
1204 { "Reserved", "pgm.poll.res", FT_UINT16
, BASE_HEX
,
1205 NULL
, 0x0, NULL
, HFILL
}},
1206 { &hf_pgm_poll_path
,
1207 { "Path NLA", "pgm.poll.path", FT_IPv4
, BASE_NONE
,
1208 NULL
, 0x0, NULL
, HFILL
}},
1209 { &hf_pgm_poll_path6
,
1210 { "Path NLA", "pgm.poll.path", FT_IPv6
, BASE_NONE
,
1211 NULL
, 0x0, NULL
, HFILL
}},
1212 { &hf_pgm_poll_backoff_ivl
,
1213 { "Back-off Interval", "pgm.poll.backoff_ivl", FT_UINT32
, BASE_DEC
,
1214 NULL
, 0x0, NULL
, HFILL
}},
1215 { &hf_pgm_poll_rand_str
,
1216 { "Random String", "pgm.poll.rand_str", FT_UINT32
, BASE_HEX
,
1217 NULL
, 0x0, NULL
, HFILL
}},
1218 { &hf_pgm_poll_matching_bmask
,
1219 { "Matching Bitmask", "pgm.poll.matching_bmask", FT_UINT32
, BASE_HEX
,
1220 NULL
, 0x0, NULL
, HFILL
}},
1222 { "Sequence Number", "pgm.polr.sqn", FT_UINT32
, BASE_HEX
,
1223 NULL
, 0x0, NULL
, HFILL
}},
1224 { &hf_pgm_polr_round
,
1225 { "Round", "pgm.polr.round", FT_UINT16
, BASE_DEC
,
1226 NULL
, 0x0, NULL
, HFILL
}},
1228 { "Reserved", "pgm.polr.res", FT_UINT16
, BASE_HEX
,
1229 NULL
, 0x0, NULL
, HFILL
}},
1231 { "Maximum Received Sequence Number", "pgm.ack.maxsqn", FT_UINT32
,
1232 BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1233 { &hf_pgm_ack_bitmap
,
1234 { "Packet Bitmap", "pgm.ack.bitmap", FT_UINT32
, BASE_HEX
,
1235 NULL
, 0x0, NULL
, HFILL
}},
1237 { "Type", "pgm.opts.type", FT_UINT8
, BASE_HEX
,
1238 VALS(opt_vals
), 0x0, NULL
, HFILL
}},
1240 { "Length", "pgm.opts.len", FT_UINT8
, BASE_DEC
,
1241 NULL
, 0x0, NULL
, HFILL
}},
1243 { "Total Length", "pgm.opts.tlen", FT_UINT16
, BASE_DEC
,
1244 NULL
, 0x0, NULL
, HFILL
}},
1245 { &hf_pgm_genopt_end
,
1246 { "Option end", "pgm.genopts.end", FT_BOOLEAN
, 8,
1247 TFS(&tfs_yes_no
), 0x80, NULL
, HFILL
}},
1248 { &hf_pgm_genopt_type
,
1249 { "Type", "pgm.genopts.type", FT_UINT8
, BASE_HEX
,
1250 VALS(opt_vals
), 0x7f, NULL
, HFILL
}},
1251 { &hf_pgm_genopt_len
,
1252 { "Length", "pgm.genopts.len", FT_UINT8
, BASE_DEC
,
1253 NULL
, 0x0, NULL
, HFILL
}},
1254 { &hf_pgm_genopt_opx
,
1255 { "Option Extensibility Bits", "pgm.genopts.opx", FT_UINT8
, BASE_HEX
,
1256 VALS(opx_vals
), 0x0, NULL
, HFILL
}},
1257 { &hf_pgm_opt_parity_prm_po
,
1258 { "Parity Parameters", "pgm.opts.parity_prm.op", FT_UINT8
, BASE_HEX
,
1259 NULL
, 0x0, NULL
, HFILL
}},
1260 { &hf_pgm_opt_parity_prm_prmtgsz
,
1261 { "Transmission Group Size", "pgm.opts.parity_prm.prm_grp",
1262 FT_UINT32
, BASE_HEX
,
1263 NULL
, 0x0, NULL
, HFILL
}},
1264 { &hf_pgm_opt_join_res
,
1265 { "Reserved", "pgm.opts.join.res", FT_UINT8
, BASE_HEX
,
1266 NULL
, 0x0, NULL
, HFILL
}},
1267 { &hf_pgm_opt_join_minjoin
,
1268 { "Minimum Sequence Number", "pgm.opts.join.min_join",
1269 FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1270 { &hf_pgm_opt_parity_grp_res
,
1271 { "Reserved", "pgm.opts.parity_prm.op", FT_UINT8
, BASE_HEX
,
1272 NULL
, 0x0, NULL
, HFILL
}},
1273 { &hf_pgm_opt_parity_grp_prmgrp
,
1274 { "Transmission Group Size", "pgm.opts.parity_prm.prm_grp",
1275 FT_UINT32
, BASE_HEX
,
1276 NULL
, 0x0, NULL
, HFILL
}},
1277 { &hf_pgm_opt_nak_res
,
1278 { "Reserved", "pgm.opts.nak.op", FT_UINT8
, BASE_HEX
,
1279 NULL
, 0x0, NULL
, HFILL
}},
1280 { &hf_pgm_opt_nak_list
,
1281 { "List", "pgm.opts.nak.list", FT_BYTES
, BASE_NONE
,
1282 NULL
, 0x0, NULL
, HFILL
}},
1283 { &hf_pgm_opt_ccdata_res
,
1284 { "Reserved", "pgm.opts.ccdata.res", FT_UINT8
, BASE_DEC
,
1285 NULL
, 0x0, NULL
, HFILL
}},
1286 { &hf_pgm_opt_ccdata_tsp
,
1287 { "Time Stamp", "pgm.opts.ccdata.tstamp", FT_UINT16
, BASE_HEX
,
1288 NULL
, 0x0, NULL
, HFILL
}},
1289 { &hf_pgm_opt_ccdata_afi
,
1290 { "Acker AFI", "pgm.opts.ccdata.afi", FT_UINT16
, BASE_DEC
,
1291 VALS(afn_vals
), 0x0, NULL
, HFILL
}},
1292 { &hf_pgm_opt_ccdata_res2
,
1293 { "Reserved", "pgm.opts.ccdata.res2", FT_UINT16
, BASE_DEC
,
1294 NULL
, 0x0, NULL
, HFILL
}},
1295 { &hf_pgm_opt_ccdata_acker
,
1296 { "Acker", "pgm.opts.ccdata.acker", FT_IPv4
, BASE_NONE
,
1297 NULL
, 0x0, NULL
, HFILL
}},
1298 { &hf_pgm_opt_ccdata_acker6
,
1299 { "Acker", "pgm.opts.ccdata.acker", FT_IPv6
, BASE_NONE
,
1300 NULL
, 0x0, NULL
, HFILL
}},
1301 { &hf_pgm_opt_ccfeedbk_res
,
1302 { "Reserved", "pgm.opts.ccdata.res", FT_UINT8
, BASE_DEC
,
1303 NULL
, 0x0, NULL
, HFILL
}},
1304 { &hf_pgm_opt_ccfeedbk_tsp
,
1305 { "Time Stamp", "pgm.opts.ccdata.tstamp", FT_UINT16
, BASE_HEX
,
1306 NULL
, 0x0, NULL
, HFILL
}},
1307 { &hf_pgm_opt_ccfeedbk_afi
,
1308 { "Acker AFI", "pgm.opts.ccdata.afi", FT_UINT16
, BASE_DEC
,
1309 VALS(afn_vals
), 0x0, NULL
, HFILL
}},
1310 { &hf_pgm_opt_ccfeedbk_lossrate
,
1311 { "Loss Rate", "pgm.opts.ccdata.lossrate", FT_UINT16
, BASE_HEX
,
1312 NULL
, 0x0, NULL
, HFILL
}},
1313 { &hf_pgm_opt_ccfeedbk_acker
,
1314 { "Acker", "pgm.opts.ccdata.acker", FT_IPv4
, BASE_NONE
,
1315 NULL
, 0x0, NULL
, HFILL
}},
1316 { &hf_pgm_opt_ccfeedbk_acker6
,
1317 { "Acker", "pgm.opts.ccdata.acker", FT_IPv6
, BASE_NONE
,
1318 NULL
, 0x0, NULL
, HFILL
}},
1319 { &hf_pgm_opt_nak_bo_ivl_res
,
1320 { "Reserved", "pgm.opts.nak_bo_ivl.res", FT_UINT8
, BASE_HEX
,
1321 NULL
, 0x0, NULL
, HFILL
}},
1322 { &hf_pgm_opt_nak_bo_ivl_bo_ivl
,
1323 { "Back-off Interval", "pgm.opts.nak_bo_ivl.bo_ivl", FT_UINT32
, BASE_DEC
,
1324 NULL
, 0x0, NULL
, HFILL
}},
1325 { &hf_pgm_opt_nak_bo_ivl_bo_ivl_sqn
,
1326 { "Back-off Interval Sequence Number", "pgm.opts.nak_bo_ivl.bo_ivl_sqn", FT_UINT32
, BASE_HEX
,
1327 NULL
, 0x0, NULL
, HFILL
}},
1328 { &hf_pgm_opt_nak_bo_rng_res
,
1329 { "Reserved", "pgm.opts.nak_bo_rng.res", FT_UINT8
, BASE_HEX
,
1330 NULL
, 0x0, NULL
, HFILL
}},
1331 { &hf_pgm_opt_nak_bo_rng_min_bo_ivl
,
1332 { "Min Back-off Interval", "pgm.opts.nak_bo_rng.min_bo_ivl", FT_UINT32
, BASE_DEC
,
1333 NULL
, 0x0, NULL
, HFILL
}},
1334 { &hf_pgm_opt_nak_bo_rng_max_bo_ivl
,
1335 { "Max Back-off Interval", "pgm.opts.nak_bo_rng.max_bo_ivl", FT_UINT32
, BASE_DEC
,
1336 NULL
, 0x0, NULL
, HFILL
}},
1337 { &hf_pgm_opt_redirect_res
,
1338 { "Reserved", "pgm.opts.redirect.res", FT_UINT8
, BASE_DEC
,
1339 NULL
, 0x0, NULL
, HFILL
}},
1340 { &hf_pgm_opt_redirect_afi
,
1341 { "DLR AFI", "pgm.opts.redirect.afi", FT_UINT16
, BASE_DEC
,
1342 VALS(afn_vals
), 0x0, NULL
, HFILL
}},
1343 { &hf_pgm_opt_redirect_res2
,
1344 { "Reserved", "pgm.opts.redirect.res2", FT_UINT16
, BASE_HEX
,
1345 NULL
, 0x0, NULL
, HFILL
}},
1346 { &hf_pgm_opt_redirect_dlr
,
1347 { "DLR", "pgm.opts.redirect.dlr", FT_IPv4
, BASE_NONE
,
1348 NULL
, 0x0, NULL
, HFILL
}},
1349 { &hf_pgm_opt_redirect_dlr6
,
1350 { "DLR", "pgm.opts.redirect.dlr", FT_IPv6
, BASE_NONE
,
1351 NULL
, 0x0, NULL
, HFILL
}},
1352 { &hf_pgm_opt_fragment_res
,
1353 { "Reserved", "pgm.opts.fragment.res", FT_UINT8
, BASE_HEX
,
1354 NULL
, 0x0, NULL
, HFILL
}},
1355 { &hf_pgm_opt_fragment_first_sqn
,
1356 { "First Sequence Number", "pgm.opts.fragment.first_sqn", FT_UINT32
, BASE_HEX
,
1357 NULL
, 0x0, NULL
, HFILL
}},
1358 { &hf_pgm_opt_fragment_offset
,
1359 { "Fragment Offset", "pgm.opts.fragment.fragment_offset", FT_UINT32
, BASE_DEC
,
1360 NULL
, 0x0, NULL
, HFILL
}},
1361 { &hf_pgm_opt_fragment_total_length
,
1362 { "Total Length", "pgm.opts.fragment.total_length", FT_UINT32
, BASE_DEC
,
1363 NULL
, 0x0, NULL
, HFILL
}}
1365 static gint
*ett
[] = {
1376 &ett_pgm_opts_parityprm
,
1377 &ett_pgm_opts_paritygrp
,
1378 &ett_pgm_opts_naklist
,
1379 &ett_pgm_opts_ccdata
,
1380 &ett_pgm_opts_nak_bo_ivl
,
1381 &ett_pgm_opts_nak_bo_rng
,
1382 &ett_pgm_opts_redirect
,
1383 &ett_pgm_opts_fragment
1385 module_t
*pgm_module
;
1387 proto_pgm
= proto_register_protocol("Pragmatic General Multicast",
1390 proto_register_field_array(proto_pgm
, hf
, array_length(hf
));
1391 proto_register_subtree_array(ett
, array_length(ett
));
1393 /* subdissector code */
1394 subdissector_table
= register_dissector_table("pgm.port",
1395 "PGM port", FT_UINT16
, BASE_DEC
);
1396 register_heur_dissector_list("pgm", &heur_subdissector_list
);
1399 * Register configuration preferences for UDP encapsulation
1400 * (Note: Initially the ports are set to zero and the ports
1401 * are not registered so the dissecting of PGM
1402 * encapsulated in UDP packets is off by default;
1403 * dissector_add_handle is called so that pgm
1404 * is available for 'decode-as'
1406 pgm_module
= prefs_register_protocol(proto_pgm
, proto_reg_handoff_pgm
);
1408 prefs_register_bool_preference(pgm_module
, "check_checksum",
1409 "Check the validity of the PGM checksum when possible",
1410 "Whether to check the validity of the PGM checksum",
1411 &pgm_check_checksum
);
1413 prefs_register_uint_preference(pgm_module
, "udp.encap_ucast_port",
1414 "PGM Encap Unicast Port (standard is 3055)",
1415 "PGM Encap is PGM packets encapsulated in UDP packets"
1416 " (Note: This option is off, i.e. port is 0, by default)",
1417 10, &udp_encap_ucast_port
);
1419 prefs_register_uint_preference(pgm_module
, "udp.encap_mcast_port",
1420 "PGM Encap Multicast Port (standard is 3056)",
1421 "PGM Encap is PGM packets encapsulated in UDP packets"
1422 " (Note: This option is off, i.e. port is 0, by default)",
1423 10, &udp_encap_mcast_port
);
1427 /* The registration hand-off routine */
1429 * Set up PGM Encap dissecting, which is off by default for UDP
1433 proto_reg_handoff_pgm(void)
1435 static gboolean initialized
= FALSE
;
1436 static dissector_handle_t pgm_handle
;
1437 static guint old_udp_encap_ucast_port
;
1438 static guint old_udp_encap_mcast_port
;
1440 if (! initialized
) {
1441 pgm_handle
= create_dissector_handle(dissect_pgm
, proto_pgm
);
1442 dissector_add_handle("udp.port", pgm_handle
); /* for 'decode-as' */
1443 dissector_add_uint("ip.proto", IP_PROTO_PGM
, pgm_handle
);
1444 data_handle
= find_dissector("data");
1447 if (old_udp_encap_ucast_port
!= 0) {
1448 dissector_delete_uint("udp.port", old_udp_encap_ucast_port
, pgm_handle
);
1450 if (old_udp_encap_mcast_port
!= 0) {
1451 dissector_delete_uint("udp.port", old_udp_encap_mcast_port
, pgm_handle
);
1455 if (udp_encap_ucast_port
!= 0) {
1456 dissector_add_uint("udp.port", udp_encap_ucast_port
, pgm_handle
);
1458 if (udp_encap_mcast_port
!= 0) {
1459 dissector_add_uint("udp.port", udp_encap_mcast_port
, pgm_handle
);
1461 old_udp_encap_ucast_port
= udp_encap_ucast_port
;
1462 old_udp_encap_mcast_port
= udp_encap_mcast_port
;