HACK: 2nd try to match RowsetProperties
[wireshark-wip.git] / epan / dissectors / packet-pgm.c
blobb67bee398aa6b06782a97bdbd4f257ab077df364
1 /* packet-pgm.c
2 * Routines for PGM packet disassembly, RFC 3208
4 * $Id$
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.
28 #include "config.h"
30 #include <epan/packet.h>
31 #include <epan/afn.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) */
59 #define PGM_OPT 0x01
60 #define PGM_OPT_NETSIG 0x02
61 #define PGM_OPT_VAR_PKTLEN 0x40
62 #define PGM_OPT_PARITY 0x80
64 /* option types */
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
82 /* POLL subtypes */
83 #define PGM_POLL_GENERAL 0x0
84 #define PGM_POLL_DLR 0x1
86 /* OPX bit values */
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;
250 static const char *
251 optsstr(guint8 opts)
253 char *msg;
254 gint returned_length, idx = 0;
255 const int MAX_STR_LEN = 256;
257 if (opts == 0)
258 return("");
260 msg=(char *)wmem_alloc(wmem_packet_scope(), MAX_STR_LEN);
261 if (opts & PGM_OPT){
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);
277 if (!idx) {
278 g_snprintf(&msg[idx], MAX_STR_LEN-idx, "0x%x", opts);
280 return(msg);
282 static const char *
283 paritystr(guint8 parity)
285 char *msg;
286 gint returned_length, idx = 0;
287 const int MAX_STR_LEN = 256;
289 if (parity == 0)
290 return("");
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);
301 if (!idx) {
302 g_snprintf(&msg[idx], MAX_STR_LEN-idx, "0x%x", parity);
304 return(msg);
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" },
325 { 0, NULL }
328 static const value_string opx_vals[] = {
329 { PGM_OPX_IGNORE, "Ignore" },
330 { PGM_OPX_INVAL, "Inval" },
331 { PGM_OPX_DISCARD, "DisCard" },
332 { 0, NULL }
335 static const true_false_string opts_present = {
336 "Present",
337 "Not Present"
340 static void
341 dissect_pgmopts(ptvcursor_t* cursor, const char *pktname)
343 proto_item *tf;
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;
351 guint8 genopts_type;
352 guint8 genopts_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",
358 pktname,
359 val_to_str(opts_type, opt_vals, "Unknown (0x%02x)"),
360 val_to_str(PGM_OPT_LENGTH, opt_vals, "Unknown (0x%02x)"));
361 return;
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);
370 return;
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");
385 break;
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;
393 theend = TRUE;
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)"),
399 genopts_len);
400 break;
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)"),
406 genopts_len);
407 break;
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)"),
412 genopts_len);
414 switch(genopts_type) {
415 case PGM_OPT_JOIN:{
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);
427 break;
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);
434 break;
436 case PGM_OPT_PARITY_PRM:{
437 guint8 optdata_po;
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);
451 break;
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);
463 break;
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);
477 break;
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);
484 break;
486 case PGM_OPT_NAK_LIST:{
487 guint8 optdata_len;
488 guint32 naklist[PGM_MAX_NAK_LIST_SZ+1];
489 unsigned char *nakbuf;
490 gboolean firsttime;
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);
506 firsttime = TRUE;
507 soffset = 0;
508 naks = (int)(optdata_len/sizeof(guint32));
509 nakbuf = (unsigned char *)wmem_alloc(wmem_packet_scope(), 8192);
510 j = 0;
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) {
519 if (firsttime) {
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);
523 soffset = 0;
524 firsttime = FALSE;
525 } else {
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);
529 soffset = 0;
531 ptvcursor_advance(cursor, j*4);
532 j = 0;
535 if (j) {
536 if (firsttime) {
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);
540 } else {
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);
547 break;
549 case PGM_OPT_PGMCC_DATA:{
550 guint16 optdata_afi;
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);
563 break;
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) {
575 case AFNUM_INET:
576 ptvcursor_add(cursor, hf_pgm_opt_ccdata_acker, 4, ENC_BIG_ENDIAN);
577 break;
579 case AFNUM_INET6:
580 ptvcursor_add(cursor, hf_pgm_opt_ccdata_acker6, 16, ENC_NA);
581 break;
583 default:
584 proto_tree_add_text(opt_tree, tvb, ptvcursor_current_offset(cursor), -1,
585 "Can't handle this address format");
586 break;
589 break;
591 case PGM_OPT_PGMCC_FEEDBACK:{
592 guint16 optdata_afi;
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);
605 break;
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) {
617 case AFNUM_INET:
618 ptvcursor_add(cursor, hf_pgm_opt_ccfeedbk_acker, 4, ENC_BIG_ENDIAN);
619 break;
621 case AFNUM_INET6:
622 ptvcursor_add(cursor, hf_pgm_opt_ccfeedbk_acker6, 16, ENC_NA);
623 break;
625 default:
626 proto_tree_add_text(opt_tree, tvb, ptvcursor_current_offset(cursor), -1,
627 "Can't handle this address format");
628 break;
631 break;
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);
645 break;
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);
653 break;
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);
667 break;
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);
675 break;
677 case PGM_OPT_REDIRECT:{
678 guint16 optdata_afi;
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);
691 break;
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) {
702 case AFNUM_INET:
703 ptvcursor_add(cursor, hf_pgm_opt_redirect_dlr, 4, ENC_BIG_ENDIAN);
704 break;
706 case AFNUM_INET6:
707 ptvcursor_add(cursor, hf_pgm_opt_redirect_dlr6, 16, ENC_NA);
708 break;
710 default:
711 proto_tree_add_text(opt_tree, tvb, ptvcursor_current_offset(cursor), -1,
712 "Can't handle this address format");
713 break;
716 break;
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);
730 break;
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);
739 break;
741 default:{
742 ptvcursor_advance(cursor, genopts_len);
743 break;
747 opts_total_len -= genopts_len;
749 return;
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" },
762 { 0, NULL }
765 static const value_string poll_subtype_vals[] = {
766 { PGM_POLL_GENERAL, "General" },
767 { PGM_POLL_DLR, "DLR" },
768 { 0, NULL }
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 */
775 static void
776 decode_pgm_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,
777 proto_tree *tree, guint16 pgmhdr_sport, guint16 pgmhdr_dport)
779 tvbuff_t *next_tvb;
780 int found = 0;
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);
787 if (found)
788 return;
790 found = dissector_try_uint(subdissector_table, pgmhdr_dport,
791 next_tvb, pinfo, tree);
792 if (found)
793 return;
795 /* do lookup with the heuristic subdissector table */
796 if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree, NULL))
797 return;
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
806 static void
807 dissect_pgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
809 guint16 pgmhdr_sport;
810 guint16 pgmhdr_dport;
811 guint8 pgmhdr_type;
812 guint8 pgmhdr_opts;
813 guint16 pgmhdr_cksum;
814 guint16 pgmhdr_tsdulen;
815 guint32 sqn;
816 guint16 afi;
818 guint plen = 0;
819 proto_item *ti;
820 const char *pktname;
821 const char *pollstname;
822 char *gsi;
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,
831 "Packet too small");
832 return;
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) {
848 case PGM_SPM_PCKT:
849 case PGM_NAK_PCKT:
850 case PGM_NNAK_PCKT:
851 case PGM_NCF_PCKT:
852 case PGM_POLR_PCKT:
853 case PGM_ACK_PCKT:
854 col_add_fstr(pinfo->cinfo, COL_INFO,
855 "%-5s sqn 0x%x gsi %s", pktname, sqn, gsi);
856 break;
857 case PGM_RDATA_PCKT:
858 case PGM_ODATA_PCKT:
859 col_add_fstr(pinfo->cinfo, COL_INFO,
860 "%-5s sqn 0x%x gsi %s tsdulen %d", pktname, sqn, gsi,
861 pgmhdr_tsdulen);
863 isdata = TRUE;
864 break;
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);
873 break;
874 default:
875 return;
879 proto_tree *pgm_tree = NULL;
880 proto_tree *opt_tree = NULL;
881 proto_tree *type_tree = NULL;
882 proto_item *tf, *hidden_item;
883 ptvcursor_t* cursor;
885 ti = proto_tree_add_protocol_format(tree, proto_pgm,
886 tvb, 0, -1,
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) &&
917 (pgmhdr_cksum == 0))
919 proto_tree_add_uint_format_value(pgm_tree, hf_pgm_main_cksum, tvb,
920 ptvcursor_current_offset(cursor), 2, pgmhdr_cksum, "not available");
921 } else {
922 reportedlen = tvb_reported_length(tvb);
923 pgmlen = tvb_length(tvb);
924 if (pgm_check_checksum && pgmlen >= reportedlen) {
925 vec_t cksum_vec[1];
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);
934 } else {
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));
942 } else {
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) {
953 case PGM_SPM_PCKT:
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);
964 switch (afi) {
965 case AFNUM_INET:
966 ptvcursor_add(cursor, hf_pgm_spm_path, 4, ENC_BIG_ENDIAN);
967 break;
969 case AFNUM_INET6:
970 ptvcursor_add(cursor, hf_pgm_spm_path6, 16, ENC_NA);
971 break;
973 default:
974 proto_tree_add_text(type_tree, tvb, ptvcursor_current_offset(cursor), -1,
975 "Can't handle this address format");
976 return;
978 break;
979 case PGM_RDATA_PCKT:
980 case PGM_ODATA_PCKT:
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);
986 break;
987 case PGM_NAK_PCKT:
988 case PGM_NNAK_PCKT:
989 case PGM_NCF_PCKT:
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);
998 switch (afi) {
999 case AFNUM_INET:
1000 ptvcursor_add(cursor, hf_pgm_nak_src, 4, ENC_BIG_ENDIAN);
1001 break;
1003 case AFNUM_INET6:
1004 ptvcursor_add(cursor, hf_pgm_nak_src6, 16, ENC_NA);
1005 break;
1007 default:
1008 proto_tree_add_text(type_tree, tvb, ptvcursor_current_offset(cursor), -1,
1009 "Can't handle this address format");
1010 break;
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);
1017 switch (afi) {
1018 case AFNUM_INET:
1019 ptvcursor_add(cursor, hf_pgm_nak_grp, 4, ENC_BIG_ENDIAN);
1020 break;
1022 case AFNUM_INET6:
1023 ptvcursor_add(cursor, hf_pgm_nak_grp6, 16, ENC_NA);
1024 break;
1026 default:
1027 proto_tree_add_text(type_tree, tvb, ptvcursor_current_offset(cursor), -1,
1028 "Can't handle this address format");
1029 return;
1031 break;
1032 case PGM_POLL_PCKT:
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);
1043 switch (afi) {
1044 case AFNUM_INET:
1045 ptvcursor_add(cursor, hf_pgm_poll_path, 4, ENC_BIG_ENDIAN);
1046 break;
1048 case AFNUM_INET6:
1049 ptvcursor_add(cursor, hf_pgm_poll_path6, 16, ENC_NA);
1050 break;
1052 default:
1053 proto_tree_add_text(type_tree, tvb, ptvcursor_current_offset(cursor), -1,
1054 "Can't handle this address format");
1055 break;
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);
1061 break;
1062 case PGM_POLR_PCKT:
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);
1069 break;
1070 case PGM_ACK_PCKT:
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);
1076 break;
1079 if (pgmhdr_opts & PGM_OPT)
1080 dissect_pgmopts(cursor, pktname);
1082 if (isdata)
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 */
1088 void
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 }},
1098 { &hf_pgm_port,
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",
1112 FT_BOOLEAN, 8,
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",
1116 FT_BOOLEAN, 8,
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 }},
1127 { &hf_pgm_main_gsi,
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 }},
1133 { &hf_pgm_spm_sqn,
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 }},
1139 { &hf_pgm_spm_lead,
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 }},
1145 { &hf_pgm_spm_res,
1146 { "Reserved", "pgm.spm.res", FT_UINT16, BASE_HEX,
1147 NULL, 0x0, NULL, HFILL }},
1148 { &hf_pgm_spm_path,
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 }},
1154 #if 0
1155 { &hf_pgm_data_sqn,
1156 { "Data Packet Sequence Number", "pgm.data.sqn", FT_UINT32, BASE_HEX,
1157 NULL, 0x0, NULL, HFILL }},
1158 #endif
1159 #if 0
1160 { &hf_pgm_data_trail,
1161 { "Trailing Edge Sequence Number", "pgm.data.trail", FT_UINT32, BASE_HEX,
1162 NULL, 0x0, NULL, HFILL }},
1163 #endif
1164 { &hf_pgm_nak_sqn,
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 }},
1173 { &hf_pgm_nak_src,
1174 { "Source NLA", "pgm.nak.src", FT_IPv4, BASE_NONE,
1175 NULL, 0x0, NULL, HFILL }},
1176 { &hf_pgm_nak_src6,
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 }},
1185 { &hf_pgm_nak_grp,
1186 { "Multicast Group NLA", "pgm.nak.grp", FT_IPv4, BASE_NONE,
1187 NULL, 0x0, NULL, HFILL }},
1188 { &hf_pgm_nak_grp6,
1189 { "Multicast Group NLA", "pgm.nak.grp", FT_IPv6, BASE_NONE,
1190 NULL, 0x0, NULL, HFILL }},
1191 { &hf_pgm_poll_sqn,
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 }},
1203 { &hf_pgm_poll_res,
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 }},
1221 { &hf_pgm_polr_sqn,
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 }},
1227 { &hf_pgm_polr_res,
1228 { "Reserved", "pgm.polr.res", FT_UINT16, BASE_HEX,
1229 NULL, 0x0, NULL, HFILL }},
1230 { &hf_pgm_ack_sqn,
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 }},
1236 { &hf_pgm_opt_type,
1237 { "Type", "pgm.opts.type", FT_UINT8, BASE_HEX,
1238 VALS(opt_vals), 0x0, NULL, HFILL }},
1239 { &hf_pgm_opt_len,
1240 { "Length", "pgm.opts.len", FT_UINT8, BASE_DEC,
1241 NULL, 0x0, NULL, HFILL }},
1242 { &hf_pgm_opt_tlen,
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[] = {
1366 &ett_pgm,
1367 &ett_pgm_optbits,
1368 &ett_pgm_spm,
1369 &ett_pgm_data,
1370 &ett_pgm_nak,
1371 &ett_pgm_poll,
1372 &ett_pgm_polr,
1373 &ett_pgm_ack,
1374 &ett_pgm_opts,
1375 &ett_pgm_opts_join,
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",
1388 "PGM", "pgm");
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
1432 void
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");
1445 initialized = TRUE;
1446 } else {
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;