2 * Routines for pgm packet disassembly
5 * $Id: packet-pgm.c,v 1.1 2001/07/12 20:16:28 guy Exp $
7 * Copyright (c) 2000 by Talarian Corp
9 * Ethereal - Network traffic analyzer
10 * By Gerald Combs <gerald@ethereal.com>
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #ifdef HAVE_SYS_TYPES_H
33 #include <sys/types.h>
36 #ifdef HAVE_SYS_SOCKET_H
37 #include <sys/socket.h>
40 #ifdef HAVE_NETINET_IN_H
41 #include <netinet/in.h>
44 #ifdef HAVE_ARPA_INET_H
45 #include <arpa/inet.h>
59 #include "packet-pgm.h"
68 #define IP_PROTO_PGM 113
71 void proto_reg_handoff_pgm(void);
72 extern void decode_tcp_ports(tvbuff_t *, int , packet_info *,
73 proto_tree *, int, int);
76 static int proto_pgm = -1;
77 static int ett_pgm = -1;
78 static int ett_pgm_optbits = -1;
79 static int ett_pgm_opts = -1;
80 static int ett_pgm_spm = -1;
81 static int ett_pgm_data = -1;
82 static int ett_pgm_nak = -1;
83 static int ett_pgm_opts_join = -1;
84 static int ett_pgm_opts_parityprm = -1;
85 static int ett_pgm_opts_paritygrp = -1;
86 static int ett_pgm_opts_naklist = -1;
88 static int hf_pgm_main_sport = -1;
89 static int hf_pgm_main_dport = -1;
90 static int hf_pgm_main_type = -1;
91 static int hf_pgm_main_opts = -1;
92 static int hf_pgm_main_opts_opt = -1;
93 static int hf_pgm_main_opts_netsig = -1;
94 static int hf_pgm_main_opts_varlen = -1;
95 static int hf_pgm_main_opts_parity = -1;
96 static int hf_pgm_main_cksum = -1;
97 static int hf_pgm_main_gsi = -1;
98 static int hf_pgm_main_tsdulen = -1;
99 static int hf_pgm_spm_sqn = -1;
100 static int hf_pgm_spm_lead = -1;
101 static int hf_pgm_spm_trail = -1;
102 static int hf_pgm_spm_pathafi = -1;
103 static int hf_pgm_spm_res = -1;
104 static int hf_pgm_spm_path = -1;
105 static int hf_pgm_data_sqn = -1;
106 static int hf_pgm_data_trail = -1;
107 static int hf_pgm_nak_sqn = -1;
108 static int hf_pgm_nak_srcafi = -1;
109 static int hf_pgm_nak_srcres = -1;
110 static int hf_pgm_nak_src = -1;
111 static int hf_pgm_nak_grpafi = -1;
112 static int hf_pgm_nak_grpres = -1;
113 static int hf_pgm_nak_grp = -1;
115 static int hf_pgm_opt_type = -1;
116 static int hf_pgm_opt_len = -1;
117 static int hf_pgm_opt_tlen = -1;
119 static int hf_pgm_genopt_type = -1;
120 static int hf_pgm_genopt_len = -1;
121 static int hf_pgm_genopt_opx = -1;
122 static int hf_pgm_genopt_res = -1;
124 static int hf_pgm_opt_join_type = -1;
125 static int hf_pgm_opt_join_len = -1;
126 static int hf_pgm_opt_join_opx = -1;
127 static int hf_pgm_opt_join_res = -1;
128 static int hf_pgm_opt_join_minjoin = -1;
130 static int hf_pgm_opt_parity_prm_type = -1;
131 static int hf_pgm_opt_parity_prm_len = -1;
132 static int hf_pgm_opt_parity_prm_opx = -1;
133 static int hf_pgm_opt_parity_prm_po = -1;
134 static int hf_pgm_opt_parity_prm_prmtgsz = -1;
136 static int hf_pgm_opt_parity_grp_type = -1;
137 static int hf_pgm_opt_parity_grp_len = -1;
138 static int hf_pgm_opt_parity_grp_opx = -1;
139 static int hf_pgm_opt_parity_grp_res = -1;
140 static int hf_pgm_opt_parity_grp_prmgrp = -1;
142 static int hf_pgm_opt_curr_tgsize_type = -1;
143 static int hf_pgm_opt_curr_tgsize_len = -1;
144 static int hf_pgm_opt_curr_tgsize_opx = -1;
145 static int hf_pgm_opt_curr_tgsize_res = -1;
146 static int hf_pgm_opt_curr_tgsize_prmatgsz = -1;
148 static int hf_pgm_opt_nak_type = -1;
149 static int hf_pgm_opt_nak_len = -1;
150 static int hf_pgm_opt_nak_opx = -1;
151 static int hf_pgm_opt_nak_res = -1;
152 static int hf_pgm_opt_nak_list = -1;
155 gsistr(char *gsi, int len)
157 static char msg[256];
161 for (i = 0; i <= 255 && i < len; i++) {
162 sprintf(p,"%02x",(nchar_t)gsi[i]);
168 optsstr(nchar_t opts)
170 static char msg[256];
177 sprintf(p, "Present");
178 p += strlen("Present");
180 if (opts & PGM_OPT_NETSIG){
188 if (opts & PGM_OPT_VAR_PKTLEN){
196 if (opts & PGM_OPT_PARITY){
205 sprintf(p, "0x%x", opts);
210 opttypes(nchar_t opt)
212 static char msg[128];
214 if (opt == PGM_OPT_LENGTH)
216 if (opt == PGM_OPT_END)
218 if (opt == PGM_OPT_FRAGMENT)
220 if (opt == PGM_OPT_NAK_LIST)
222 if (opt == PGM_OPT_JOIN)
224 if (opt == PGM_OPT_REDIRECT)
226 if (opt == PGM_OPT_SYN)
228 if (opt == PGM_OPT_FIN)
230 if (opt == PGM_OPT_RST)
232 if (opt == PGM_OPT_PARITY_PRM)
234 if (opt == PGM_OPT_PARITY_GRP)
236 if (opt == PGM_OPT_CURR_TGSIZE)
239 sprintf(msg, "0x%x", opt);
245 static char msg[128];
250 if (opt == PGM_OPX_IGNORE)
252 if (opt == PGM_OPX_INVAL)
254 if (opt == PGM_OPX_DISCARD)
257 sprintf(msg, "0x%x", opt);
260 char *pktname = NULL;
263 dissect_pgmopts(tvbuff_t *tvb, int offset, proto_tree *tree)
266 proto_tree *opts_tree = NULL;
267 proto_tree *opt_tree = NULL;
268 pgm_opt_length_t opts;
269 pgm_opt_generic_t genopts;
270 int theend = 0, firsttime = 1;
272 tvb_memcpy(tvb, (guint8 *)&opts, offset, sizeof(opts));
273 opts.total_len = ntohs(opts.total_len);
275 tf = proto_tree_add_text(tree, tvb, offset,
277 "%s Options (Total Length %d)", pktname, opts.total_len);
278 opts_tree = proto_item_add_subtree(tf, ett_pgm_opts);
279 proto_tree_add_uint_format(opts_tree, hf_pgm_opt_type, tvb,
280 offset, 4, opts.type,
281 "Option: %-9s (0x%x), Length: %d, Total Length: %d",
282 opttypes(opts.type), opts.type, opts.len, opts.total_len);
285 for (opts.total_len -= 4; opts.total_len > 0;){
286 tvb_memcpy(tvb, (guint8 *)&genopts, offset, sizeof(genopts));
287 if (genopts.type & PGM_OPT_END) {
288 genopts.type &= ~PGM_OPT_END;
291 tf = proto_tree_add_uint_format(opts_tree, hf_pgm_genopt_type, tvb,
292 offset, genopts.len, genopts.type,
293 "Option: %-9s (0x%x), Length: %d", opttypes(genopts.type),
294 genopts.type, genopts.len );
295 if (genopts.len == 0)
298 switch(genopts.type) {
300 pgm_opt_join_t optdata;
302 tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
303 opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_join);
305 proto_tree_add_uint_format(opt_tree, hf_pgm_opt_join_type,
306 tvb, offset, 1, optdata.type, "Type: %s (0x%x)",
307 opttypes(optdata.type), optdata.type);
309 proto_tree_add_uint(opt_tree, hf_pgm_opt_join_len, tvb,
310 offset+1, 1, optdata.len);
312 proto_tree_add_uint(opt_tree, hf_pgm_opt_join_opx, tvb,
313 offset+2, 1, optdata.opx);
315 proto_tree_add_uint_format(opt_tree, hf_pgm_opt_join_res, tvb,
316 offset+3, 1, optdata.opx, "Reserved: 0x%x", optdata.res);
318 proto_tree_add_uint(opt_tree, hf_pgm_opt_join_minjoin, tvb,
319 offset+4, 4, ntohl(optdata.opt_join_min));
323 case PGM_OPT_PARITY_PRM:{
324 pgm_opt_parity_prm_t optdata;
326 tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
327 opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_parityprm);
329 proto_tree_add_uint_format(opt_tree, hf_pgm_opt_parity_prm_type,
330 tvb, offset, 1, optdata.type, "Type: %s (0x%x)",
331 opttypes(optdata.type), optdata.type);
333 proto_tree_add_uint(opt_tree, hf_pgm_opt_parity_prm_len, tvb,
334 offset+1, 1, optdata.len);
336 proto_tree_add_uint_format(opt_tree, hf_pgm_opt_parity_prm_opx,
337 tvb, offset+2, 1, optdata.opx,
338 "Extensibility Bits: %s (0x%x)", opxbits(optdata.opx),
341 proto_tree_add_uint(opt_tree, hf_pgm_opt_parity_prm_po, tvb,
342 offset+3, 1, optdata.po);
344 proto_tree_add_uint(opt_tree, hf_pgm_opt_parity_prm_prmtgsz,
345 tvb, offset+4, 4, ntohl(optdata.prm_tgsz));
349 case PGM_OPT_PARITY_GRP:{
350 pgm_opt_parity_grp_t optdata;
352 tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
353 opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_paritygrp);
355 proto_tree_add_uint_format(opt_tree, hf_pgm_opt_parity_prm_type,
356 tvb, offset, 1, optdata.type, "Type: %s (0x%x)",
357 opttypes(optdata.type), optdata.type);
359 proto_tree_add_uint(opt_tree, hf_pgm_opt_parity_prm_len, tvb,
360 offset+1, 1, optdata.len);
362 proto_tree_add_uint_format(opt_tree, hf_pgm_opt_parity_grp_opx,
363 tvb, offset+2, 1, optdata.opx,
364 "Extensibility Bits: %s (0x%x)", opxbits(optdata.opx),
367 proto_tree_add_uint(opt_tree, hf_pgm_opt_parity_grp_res, tvb,
368 offset+3, 1, optdata.res);
370 proto_tree_add_uint(opt_tree, hf_pgm_opt_parity_grp_prmgrp,
371 tvb, offset+4, 4, ntohl(optdata.prm_grp));
375 case PGM_OPT_NAK_LIST:{
376 pgm_opt_nak_list_t optdata;
377 nlong_t naklist[PGM_MAX_NAK_LIST_SZ+1];
378 char nakbuf[8192], *ptr;
379 int i, j, naks, soffset = 0;
381 tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
382 opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_naklist);
384 proto_tree_add_uint_format(opt_tree, hf_pgm_opt_nak_type, tvb,
385 offset, 1, optdata.type, "Type: %s (0x%x)",
386 opttypes(optdata.type), optdata.type);
388 proto_tree_add_uint(opt_tree, hf_pgm_opt_nak_len, tvb,
389 offset+1, 1, optdata.len);
391 proto_tree_add_uint_format(opt_tree, hf_pgm_opt_nak_opx,
392 tvb, offset+2, 1, optdata.opx,
393 "Extensibility Bits: %s (0x%x)", opxbits(optdata.opx),
396 proto_tree_add_uint(opt_tree, hf_pgm_opt_nak_res, tvb,
397 offset+3, 1, optdata.res);
399 optdata.len -= sizeof(pgm_opt_nak_list_t);
400 tvb_memcpy(tvb, (guint8 *)naklist, offset+4, optdata.len);
401 naks = (optdata.len/sizeof(nlong_t));
405 * Print out 8 per line
407 for (i=0; i < naks; i++) {
408 sprintf(nakbuf+soffset, "0x%lx ",
409 (unsigned long)ntohl(naklist[i]));
410 soffset = strlen(nakbuf);
411 if ((++j % 8) == 0) {
413 proto_tree_add_bytes_format(opt_tree,
414 hf_pgm_opt_nak_list, tvb, offset+4, optdata.len,
415 nakbuf, "List(%d): %s", naks, nakbuf);
418 proto_tree_add_bytes_format(opt_tree,
419 hf_pgm_opt_nak_list, tvb, offset+4, optdata.len,
420 nakbuf, "List: %s", nakbuf);
428 proto_tree_add_bytes_format(opt_tree,
429 hf_pgm_opt_nak_list, tvb, offset+4, optdata.len,
430 nakbuf, "List(%d): %s", naks, nakbuf);
433 proto_tree_add_bytes_format(opt_tree,
434 hf_pgm_opt_nak_list, tvb, offset+4, optdata.len,
435 nakbuf, "List: %s", nakbuf);
442 offset += genopts.len;
443 opts.total_len -= genopts.len;
448 * dissect_pgm - The dissector for Pragmatic General Multicast
451 dissect_pgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
453 proto_tree *pgm_tree = NULL;
454 proto_tree *opt_tree = NULL;
455 proto_tree *type_tree = NULL;
466 struct in_addr inaddr;
469 if (check_col(pinfo->fd, COL_PROTOCOL))
470 col_set_str(pinfo->fd, COL_PROTOCOL, "PGM");
472 /* Clear out the Info column. */
473 if (check_col(pinfo->fd, COL_INFO))
474 col_clear(pinfo->fd, COL_INFO);
476 tvb_memcpy(tvb, (guint8 *)&pgmhdr, offset, sizeof(pgm_t));
477 hlen = sizeof(pgm_t);
478 pgmhdr.sport = ntohs(pgmhdr.sport);
479 pgmhdr.dport = ntohs(pgmhdr.dport);
480 pgmhdr.tsdulen = ntohs(pgmhdr.tsdulen);
482 switch(pgmhdr.type) {
484 plen = sizeof(pgm_spm_t);
485 tvb_memcpy(tvb, (guint8 *)&spm, sizeof(pgm_t), plen);
488 inaddr.s_addr = htonl(spm.path);
489 sprintf(buf, "SPM: sqn 0x%x path %s", spm.sqn, inet_ntoa(inaddr));
498 plen = sizeof(pgm_data_t);
499 tvb_memcpy(tvb, (guint8 *)&data, sizeof(pgm_t), plen);
501 sprintf(buf, "%s: sqn 0x%x tsdulen %d", pktname, data.sqn,
515 plen = sizeof(pgm_nak_t);
516 tvb_memcpy(tvb, (guint8 *)&nak, sizeof(pgm_t), plen);
518 inaddr.s_addr = htonl(nak.src);
519 strcpy(tmpaddr, inet_ntoa(inaddr));
520 inaddr.s_addr = htonl(nak.grp);
521 sprintf(buf, "%s: sqn 0x%x src %s grp %s", pktname, nak.sqn,
522 tmpaddr, inet_ntoa(inaddr));
529 if (check_col(pinfo->fd, COL_INFO)) {
530 col_add_fstr(pinfo->fd, COL_INFO, "%s", buf);
533 sprintf(buf, "Pragmatic General Multicast: Type %s (%d)"
534 " SrcPort %u, DstPort %u, GSI %s", pktname,
535 pgmhdr.type, pgmhdr.sport, pgmhdr.dport, gsistr(pgmhdr.gsi, 6));
536 ti = proto_tree_add_protocol_format(tree, proto_pgm,
537 tvb, offset, hlen, "%s", buf);
539 ti = proto_tree_add_item(tree, proto_pgm, tvb, offset, hlen, FALSE);
542 pgm_tree = proto_item_add_subtree(ti, ett_pgm);
543 proto_tree_add_uint_format(pgm_tree, hf_pgm_main_sport, tvb, offset, 2,
544 pgmhdr.sport, "Source port: %u", pgmhdr.sport);
545 proto_tree_add_uint_format(pgm_tree, hf_pgm_main_dport, tvb, offset+2,
546 2, pgmhdr.dport, "Destination port: %u", pgmhdr.dport);
547 tf = proto_tree_add_uint_format(pgm_tree, hf_pgm_main_type, tvb,
548 offset+4, 1, pgmhdr.type, "Packet type: %s (%d)", pktname,
551 tf = proto_tree_add_uint_format(pgm_tree, hf_pgm_main_opts, tvb,
552 offset+5, 1, pgmhdr.opts, "Options: %s (0x%x)",
553 optsstr(pgmhdr.opts), pgmhdr.opts);
554 opt_tree = proto_item_add_subtree(tf, ett_pgm_optbits);
556 proto_tree_add_boolean(opt_tree, hf_pgm_main_opts_opt, tvb,
557 offset+5, 1, (pgmhdr.opts & PGM_OPT));
558 proto_tree_add_boolean(opt_tree, hf_pgm_main_opts_netsig, tvb,
559 offset+5, 1, (pgmhdr.opts & PGM_OPT_NETSIG));
560 proto_tree_add_boolean(opt_tree, hf_pgm_main_opts_varlen, tvb,
561 offset+5, 1, (pgmhdr.opts & PGM_OPT_VAR_PKTLEN));
562 proto_tree_add_boolean(opt_tree, hf_pgm_main_opts_parity, tvb,
563 offset+5, 1, (pgmhdr.opts & PGM_OPT_PARITY));
565 proto_tree_add_uint_format(pgm_tree, hf_pgm_main_cksum, tvb, offset+6,
566 2, pgmhdr.cksum, "Check Sum: 0x%x", pgmhdr.cksum);
567 proto_tree_add_bytes(pgm_tree, hf_pgm_main_gsi, tvb, offset+8,
569 proto_tree_add_uint_format(pgm_tree, hf_pgm_main_tsdulen, tvb,
570 offset+14, 2, pgmhdr.tsdulen, "Transport Service Data Unit: %u",
573 offset = sizeof(pgm_t);
574 tf = proto_tree_add_text(pgm_tree, tvb, offset, plen, "%s Packet",
576 switch(pgmhdr.type) {
578 type_tree = proto_item_add_subtree(tf, ett_pgm_spm);
580 proto_tree_add_uint_format(type_tree, hf_pgm_spm_sqn, tvb,
581 offset, 4, spm.sqn, "Sequence Number: 0x%x", spm.sqn);
582 proto_tree_add_uint_format(type_tree, hf_pgm_spm_sqn, tvb,
583 offset+4, 4, spm.trail, "Trailing Edge Sequence Number: 0x%x",
585 proto_tree_add_uint_format(type_tree, hf_pgm_spm_sqn, tvb,
586 offset+8, 4, spm.lead, "Leading Edge Sequence Number: 0x%x",
588 proto_tree_add_uint_format(type_tree, hf_pgm_spm_sqn, tvb,
589 offset+10, 2, spm.path_afi,
590 "Network Layer Address (Family Indicator): 0x%x",
592 proto_tree_add_uint_format(type_tree, hf_pgm_spm_sqn, tvb,
593 offset+12, 2, spm.res, "Reserved: 0x%x", spm.res);
594 inaddr.s_addr = htonl(spm.path);
595 hp = gethostbyaddr((const char *)&inaddr,
596 sizeof(struct in_addr), AF_INET);
598 sprintf(buf, "Network Layer Address Path: %s (%s)",
599 inet_ntoa(inaddr), hp->h_name);
601 sprintf(buf, "Network Layer Address Path: %s",
603 proto_tree_add_uint_format(type_tree, hf_pgm_spm_sqn, tvb,
604 offset+14, 4, spm.sqn, "%s", buf);
606 if ((pgmhdr.opts & PGM_OPT) == FALSE)
610 dissect_pgmopts(tvb, offset, type_tree);
616 type_tree = proto_item_add_subtree(tf, ett_pgm_data);
618 proto_tree_add_uint_format(type_tree, hf_pgm_spm_sqn, tvb,
619 offset, 4, data.sqn, "Sequence Number: 0x%x", spm.sqn);
620 proto_tree_add_uint_format(type_tree, hf_pgm_spm_sqn, tvb,
621 offset+4, 4, data.trail, "Trailing Edge Sequence Number: 0x%x",
624 if ((pgmhdr.opts & PGM_OPT) == TRUE) {
626 dissect_pgmopts(tvb, offset, type_tree);
629 * Now see if there are any sub-dissectors, of so call them
631 decode_tcp_ports(tvb, offset, pinfo, tree,
632 pgmhdr.sport, pgmhdr.dport);
638 type_tree = proto_item_add_subtree(tf, ett_pgm_nak);
640 proto_tree_add_uint(type_tree, hf_pgm_nak_sqn, tvb,
642 proto_tree_add_uint(type_tree, hf_pgm_nak_srcafi, tvb,
643 offset+4, 2, nak.src_afi);
644 proto_tree_add_uint(type_tree, hf_pgm_nak_srcres, tvb,
645 offset+6, 2, nak.src_res);
647 inaddr.s_addr = htonl(nak.src);
648 hp = gethostbyaddr((const char *)&inaddr,
649 sizeof(struct in_addr), AF_INET);
651 sprintf(buf, "Source Network Layer Address: %s (%s)",
652 inet_ntoa(inaddr), hp->h_name);
654 sprintf(buf, "Source Network Layer Address Path: %s",
656 proto_tree_add_uint_format(type_tree, hf_pgm_nak_src, tvb,
657 offset+8, 4, nak.src, "%s", buf);
659 proto_tree_add_uint_format(type_tree, hf_pgm_nak_grpafi, tvb,
660 offset+12, 2, nak.grp_afi,
661 "Multicast group Network Layer Address (Family Indicator):"
662 " 0x%x", nak.grp_afi);
663 proto_tree_add_uint_format(type_tree, hf_pgm_nak_grpres, tvb,
664 offset+14, 2, nak.grp_res, "Reserved: 0x%x", nak.grp_res);
666 inaddr.s_addr = htonl(nak.grp);
667 proto_tree_add_uint_format(type_tree, hf_pgm_nak_grp, tvb,
668 offset+16, 4, nak.grp,
669 "Multicast group Network Layer Address Path: %s",
672 if ((pgmhdr.opts & PGM_OPT) == FALSE)
676 dissect_pgmopts(tvb, offset, type_tree);
684 static const true_false_string opts_present = {
689 /* Register all the bits needed with the filtering engine */
691 proto_register_pgm(void)
693 static hf_register_info hf[] = {
694 { &hf_pgm_main_sport,
695 { "Source Port", "pgm.hdr.sport", FT_UINT16, BASE_HEX, NULL, 0x0,
697 { &hf_pgm_main_dport,
698 { "Destination Port", "pgm.hdr.dport", FT_UINT16, BASE_HEX, NULL, 0x0,
701 { "Type", "pgm.hdr.type", FT_UINT8, BASE_HEX, NULL, 0x0,
704 { "Options", "pgm.hdr.opts", FT_UINT8, BASE_HEX, NULL, 0x0,
706 { &hf_pgm_main_opts_opt,
707 { "Options", "pgm.hdr.opts.opt", FT_BOOLEAN, BASE_HEX,
708 TFS(&opts_present), PGM_OPT, "", HFILL }},
709 { &hf_pgm_main_opts_netsig,
710 { "Network Significant Options", "pgm.hdr.opts.netsig",
711 FT_BOOLEAN, BASE_HEX, TFS(&opts_present), PGM_OPT_NETSIG, "", HFILL }},
712 { &hf_pgm_main_opts_varlen,
713 { "Variable lenght Parity Packet Option", "pgm.hdr.opts.varlen",
714 FT_BOOLEAN, BASE_HEX, TFS(&opts_present), PGM_OPT_VAR_PKTLEN, "", HFILL }},
715 { &hf_pgm_main_opts_parity,
716 { "Parity", "pgm.hdr.opts.parity", FT_BOOLEAN, BASE_HEX,
717 TFS(&opts_present), PGM_OPT_PARITY, "", HFILL }},
718 { &hf_pgm_main_cksum,
719 { "Checksum", "pgm.hdr.cksum", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
721 { "Global Source Identifier", "pgm.hdr.gsi", FT_BYTES, BASE_HEX,
722 NULL, 0x0, "", HFILL }},
723 { &hf_pgm_main_tsdulen,
724 { "Transport Service Data Unit", "pgm.hdr.tsdulen", FT_UINT8, BASE_HEX,
725 NULL, 0x0, "", HFILL }},
727 { "Sequence number", "pgm.spm.sqn", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
729 { "Trailing Edge Sequence Number", "pgm.spm.trail", FT_UINT32, BASE_HEX,
730 NULL, 0x0, "", HFILL }},
732 { "Leading Edge Sequence Number", "pgm.spm.lead", FT_UINT32, BASE_HEX,
733 NULL, 0x0, "", HFILL }},
734 { &hf_pgm_spm_pathafi,
735 { "NLA AFI (IPv4 is set to 1)", "pgm.spm.pathafi", FT_UINT16, BASE_HEX,
736 NULL, 0x0, "", HFILL }},
738 { "Reserved", "pgm.spm.res", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
740 { "Path NLA", "pgm.spm.path", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
742 { "Data Packet Sequence Number", "pgm.data.sqn", FT_UINT32, BASE_HEX,
743 NULL, 0x0, "", HFILL }},
744 { &hf_pgm_data_trail,
745 { "Trailing Edge Sequence Number", "pgm.data.trail", FT_UINT32, BASE_HEX,
746 NULL, 0x0, "", HFILL }},
748 { "Requested Sequence Number", "pgm.nak.sqn", FT_UINT32, BASE_HEX,
749 NULL, 0x0, "", HFILL }},
750 { &hf_pgm_nak_srcafi,
751 { "Source Network Layer Address (Family Indicator)", "pgm.nak.srcafi",
752 FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
753 { &hf_pgm_nak_srcres,
754 { "Reserved", "pgm.nak.srcres", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
756 { "Source NLA", "pgm.nak.src", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
757 { &hf_pgm_nak_grpafi,
758 { "Multicast group AFI", "pgm.nak.grpafi", FT_UINT16, BASE_HEX,
759 NULL, 0x0, "", HFILL }},
760 { &hf_pgm_nak_grpres,
761 { "Reserved", "pgm.nak.grpres", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
763 { "Multicast Group NLA", "pgm.nak.grp", FT_UINT32, BASE_HEX,
764 NULL, 0x0, "", HFILL }},
766 { "Type", "pgm.opts.type", FT_UINT8, BASE_HEX, NULL, 0x0,
769 { "Length", "pgm.opts.len", FT_UINT8, BASE_DEC, NULL, 0x0,
772 { "Total Length", "pgm.opts.tlen", FT_UINT16, BASE_DEC, NULL, 0x0,
774 { &hf_pgm_genopt_type,
775 { "Type", "pgm.genopts.type", FT_UINT8, BASE_HEX, NULL, 0x0,
777 { &hf_pgm_genopt_len,
778 { "Length", "pgm.genopts.len", FT_UINT8, BASE_DEC, NULL, 0x0,
780 { &hf_pgm_genopt_opx,
781 { "Option Extensibility Bits", "pgm.genopts.opx", FT_UINT8,
782 BASE_HEX, NULL, 0x0, "", HFILL }},
783 { &hf_pgm_genopt_res,
784 { "Reserved", "pgm.genopts.opx", FT_UINT8, BASE_HEX, NULL, 0x0,
786 { &hf_pgm_opt_parity_prm_type,
787 { "Type", "pgm.parity_prm.type", FT_UINT8, BASE_HEX, NULL, 0x0,
789 { &hf_pgm_opt_parity_prm_len,
790 { "Length", "pgm.parity_prm.len", FT_UINT8, BASE_DEC, NULL, 0x0,
792 { &hf_pgm_opt_parity_prm_opx,
793 { "Option Extensibility Bits", "pgm.opts.parity_prm.opx", FT_UINT8,
794 BASE_HEX, NULL, 0x0, "", HFILL }},
795 { &hf_pgm_opt_parity_prm_po,
796 { "Pro-Active Parity", "pgm.opts.parity_prm.op", FT_UINT8,
797 BASE_HEX, NULL, 0x0, "", HFILL }},
798 { &hf_pgm_opt_parity_prm_prmtgsz,
799 { "Transmission Group Size", "pgm.opts.parity_prm.prm_grp", FT_UINT32,
800 BASE_HEX, NULL, 0x0, "", HFILL }},
801 { &hf_pgm_opt_join_type,
802 { "Type", "pgm.opts.join.type", FT_UINT8,
803 BASE_HEX, NULL, 0x0, "", HFILL }},
804 { &hf_pgm_opt_join_len,
805 { "Length", "pgm.opts.join.res", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
806 { &hf_pgm_opt_join_opx,
807 { "Option Extensibility Bits", "pgm.opts.join.opx", FT_UINT8,
808 BASE_HEX, NULL, 0x0, "", HFILL }},
809 { &hf_pgm_opt_join_res,
810 { "Reserved", "pgm.opts.join.res", FT_UINT8,
811 BASE_HEX, NULL, 0x0, "", HFILL }},
812 { &hf_pgm_opt_join_minjoin,
813 { "Minimum Sequence Number", "pgm.opts.join.min_join", FT_UINT32,
814 BASE_HEX, NULL, 0x0, "", HFILL }},
815 { &hf_pgm_opt_parity_grp_type,
816 { "Type", "pgm.parity_grp.type", FT_UINT8, BASE_HEX, NULL, 0x0,
818 { &hf_pgm_opt_parity_grp_len,
819 { "Length", "pgm.parity_grp.len", FT_UINT8, BASE_DEC, NULL, 0x0,
821 { &hf_pgm_opt_parity_grp_opx,
822 { "Option Extensibility Bits", "pgm.opts.parity_prm.opx", FT_UINT8,
823 BASE_HEX, NULL, 0x0, "", HFILL }},
824 { &hf_pgm_opt_parity_grp_res,
825 { "Reserved", "pgm.opts.parity_prm.op", FT_UINT8,
826 BASE_HEX, NULL, 0x0, "", HFILL }},
827 { &hf_pgm_opt_parity_grp_prmgrp,
828 { "Transmission Group Size", "pgm.opts.parity_prm.prm_grp", FT_UINT32,
829 BASE_HEX, NULL, 0x0, "", HFILL }},
830 { &hf_pgm_opt_nak_type,
831 { "Type", "pgm.opt.nak.type", FT_UINT8, BASE_HEX, NULL, 0x0,
833 { &hf_pgm_opt_nak_len,
834 { "Length", "pgm.opts.nak.len", FT_UINT8, BASE_DEC, NULL, 0x0,
836 { &hf_pgm_opt_nak_opx,
837 { "Option Extensibility Bits", "pgm.opts.nak.opx", FT_UINT8,
838 BASE_HEX, NULL, 0x0, "", HFILL }},
839 { &hf_pgm_opt_nak_res,
840 { "Reserved", "pgm.opts.nak.op", FT_UINT8,
841 BASE_HEX, NULL, 0x0, "", HFILL }},
842 { &hf_pgm_opt_nak_list,
843 { "List", "pgm.opts.nak.list", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
845 static gint *ett[] = {
853 &ett_pgm_opts_parityprm,
854 &ett_pgm_opts_paritygrp,
855 &ett_pgm_opts_naklist,
858 proto_pgm = proto_register_protocol("Pragmatic General Multicast",
861 proto_register_field_array(proto_pgm, hf, array_length(hf));
862 proto_register_subtree_array(ett, array_length(ett));
866 /* The registration hand-off routine */
868 proto_reg_handoff_pgm(void)
870 dissector_add("ip.proto", IP_PROTO_PGM, dissect_pgm, proto_pgm);