Don't hand off the stub body of a Fault PDU to the subdissector for the
[obnox/wireshark/wip.git] / packet-pgm.c
1 /* packet-pgm.c
2  * Routines for pgm packet disassembly
3  *
4  * $Id: packet-pgm.c,v 1.16 2002/04/29 08:20:09 guy Exp $
5  * 
6  * Copyright (c) 2000 by Talarian Corp
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1999 Gerald Combs
11  * 
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #ifdef HAVE_SYS_TYPES_H
32 #include <sys/types.h>
33 #endif
34
35 #ifdef HAVE_SYS_SOCKET_H
36 #include <sys/socket.h>
37 #endif
38
39 #ifdef HAVE_NETINET_IN_H
40 #include <netinet/in.h>
41 #endif
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <ctype.h>
46 #include <time.h>
47 #include <string.h>
48 #include <epan/packet.h>
49 #include "afn.h"
50 #include "ipproto.h"
51 #include <epan/resolv.h>
52 #include <epan/strutil.h>
53 #include <epan/conversation.h>
54 #include "prefs.h"
55
56 #include <epan/proto.h>
57
58 void proto_reg_handoff_pgm(void);
59 static void proto_rereg_pgm(void);
60
61 typedef guint8 nchar_t;
62 typedef guint16 nshort_t;
63 typedef guint32 nlong_t;
64
65 /* The PGM main header */
66 typedef struct {
67         nshort_t sport;            /* source port */
68         nshort_t dport;            /* destination port */
69         nchar_t type;              /* PGM type */
70         nchar_t opts;              /* options */
71         nshort_t cksum;            /* checksum */
72         nchar_t gsi[6];            /* Global Source ID */
73         nshort_t tsdulen;          /* TSDU length */
74 } pgm_type;
75 #define pgmhdr_ntoh(_p) \
76         (_p)->sport = ntohs((_p)->sport); \
77         (_p)->dport = ntohs((_p)->dport); \
78         (_p)->type = ntohs((_p)->type); \
79         (_p)->opts = ntohs((_p)->opts); \
80         (_p)->cksum = ntohs((_p)->cksum); \
81         (_p)->tsdulen = ntohs((_p)->tsdulen)
82
83 /* The PGM SPM header */
84 typedef struct {
85         nlong_t sqn;              /* SPM's sequence number */
86         nlong_t trail;            /* Trailing edge sequence number */
87         nlong_t lead;             /* Leading edge sequence number */
88         nshort_t path_afi;        /* NLA AFI */
89         nshort_t res;             /* reserved */
90         nlong_t path;             /* Path NLA */
91 } pgm_spm_t;
92 static const size_t PGM_SPM_SZ = sizeof(pgm_type)+sizeof(pgm_spm_t);
93 #define spm_ntoh(_p) \
94         (_p)->sqn = ntohl((_p)->sqn); \
95         (_p)->trail = ntohl((_p)->trail); \
96         (_p)->lead = ntohl((_p)->lead); \
97         (_p)->path_afi = ntohs((_p)->path_afi); \
98         (_p)->res = ntohs((_p)->res);
99
100 /* The PGM Data (ODATA/RDATA) header */
101 typedef struct {
102         nlong_t sqn;              /* Data Packet sequence number */
103         nlong_t trail;            /* Trailing edge sequence number */
104 } pgm_data_t;
105 #define data_ntoh(_p) \
106         (_p)->sqn = ntohl((_p)->sqn); \
107         (_p)->trail = ntohl((_p)->trail)
108 static const size_t PGM_DATA_HDR_SZ = sizeof(pgm_type)+sizeof(pgm_data_t);
109
110 /* The PGM NAK (NAK/N-NAK/NCF) header */
111 typedef struct {
112         nlong_t sqn;             /* Requested sequence number */
113         nshort_t src_afi;        /* NLA AFI for source (IPv4 is set to 1) */
114         nshort_t src_res;        /* reserved */
115         nlong_t src;             /* Source NLA  */
116         nshort_t grp_afi;        /* Multicast group AFI (IPv4 is set to 1) */
117         nshort_t grp_res;        /* reserved */
118         nlong_t grp;             /* Multicast group NLA */
119 } pgm_nak_t;
120 static const size_t PGM_NAK_SZ = sizeof(pgm_type)+sizeof(pgm_nak_t);
121 #define nak_ntoh(_p) \
122         (_p)->sqn = ntohl((_p)->sqn); \
123         (_p)->src_afi = ntohs((_p)->src_afi); \
124         (_p)->src_res = ntohs((_p)->src_res); \
125         (_p)->grp_afi = ntohs((_p)->grp_afi); \
126         (_p)->grp_res = ntohs((_p)->grp_res)
127
128 /* The PGM ACK header (PGMCC) */
129 typedef struct {
130         nlong_t rx_max_sqn;      /* RX_MAX sequence number */
131         nlong_t bitmap;          /* Received Packet Bitmap */
132 } pgm_ack_t;
133 static const size_t PGM_ACK_SZ = sizeof(pgm_type)+sizeof(pgm_ack_t);
134 #define ack_ntoh(_p) \
135         (_p)->rx_max_sqn = ntohl((_p)->rx_max_sqn); \
136         (_p)->bitmap = ntohl((_p)->bitmap)
137
138 /* constants for hdr types */
139 #if defined(PGM_SPEC_01_PCKTS)
140 /* old spec-01 types */
141 #define PGM_SPM_PCKT  0x00
142 #define PGM_ODATA_PCKT  0x10
143 #define PGM_RDATA_PCKT  0x11
144 #define PGM_NAK_PCKT  0x20
145 #define PGM_NNAK_PCKT  0x21
146 #define PGM_NCF_PCKT 0x30
147 #else
148 /* spec-02 types (as well as spec-04+) */
149 #define PGM_SPM_PCKT  0x00
150 #define PGM_ODATA_PCKT  0x04
151 #define PGM_RDATA_PCKT  0x05
152 #define PGM_NAK_PCKT  0x08
153 #define PGM_NNAK_PCKT  0x09
154 #define PGM_NCF_PCKT 0x0A
155 #define PGM_ACK_PCKT 0x0D
156 #endif /* PGM_SPEC_01_PCKTS */
157
158 /* port swapping on NAK and NNAKs or not (default is to swap) */
159 /* PGM_NO_PORT_SWAP */
160
161 /* option flags (main PGM header) */
162 #define PGM_OPT 0x01
163 #define PGM_OPT_NETSIG 0x02
164 #define PGM_OPT_VAR_PKTLEN 0x40
165 #define PGM_OPT_PARITY 0x80
166
167 /* option types */
168 #define PGM_OPT_LENGTH 0x00
169 #define PGM_OPT_END 0x80
170 #define PGM_OPT_FRAGMENT 0x01
171 #define PGM_OPT_NAK_LIST 0x02
172 #define PGM_OPT_JOIN 0x03
173 #define PGM_OPT_REDIRECT 0x07
174 #define PGM_OPT_SYN 0x0D
175 #define PGM_OPT_FIN 0x0E
176 #define PGM_OPT_RST 0x0F
177 #define PGM_OPT_PARITY_PRM 0x08
178 #define PGM_OPT_PARITY_GRP 0x09
179 #define PGM_OPT_CURR_TGSIZE 0x0A
180 #define PGM_OPT_PGMCC_DATA  0x12
181 #define PGM_OPT_PGMCC_FEEDBACK  0x13
182
183 static const nchar_t PGM_OPT_INVALID = 0x7F;
184
185 /* OPX bit values */
186 #define PGM_OPX_IGNORE  0x00
187 #define PGM_OPX_INVAL   0x01
188 #define PGM_OPX_DISCARD 0x10
189
190 /* option formats */
191 typedef struct {
192         nchar_t type;
193         nchar_t len;
194         nchar_t opx;
195         nchar_t res;
196 } pgm_opt_generic_t;
197
198 typedef struct {
199         nchar_t type;
200         nchar_t len;
201         nshort_t total_len;
202 } pgm_opt_length_t;
203
204 typedef struct {
205         nchar_t type;
206         nchar_t len;
207         nchar_t opx;
208         nchar_t res;
209 } pgm_opt_nak_list_t;
210
211 /* 
212  * To squeeze the whole option into 255 bytes, we
213  * can only have 62 in the list
214  */
215 #define PGM_MAX_NAK_LIST_SZ (62)
216
217 typedef struct {
218         nchar_t type;
219         nchar_t len;
220         nchar_t opx;
221         nchar_t res;
222         nlong_t opt_join_min;
223 } pgm_opt_join_t;
224
225 typedef struct {
226         nchar_t type;
227         nchar_t len;
228         nchar_t opx;
229         nchar_t po;
230         nlong_t prm_tgsz;
231 } pgm_opt_parity_prm_t;
232
233 /* OPT_PARITY_PRM P and O bits */
234 static const nchar_t PGM_OPT_PARITY_PRM_PRO = 0x2;
235 static const nchar_t PGM_OPT_PARITY_PRM_OND = 0x1;
236
237 typedef struct {
238         nchar_t type;
239         nchar_t len;
240         nchar_t opx;
241         nchar_t res;
242         nlong_t prm_grp;
243 } pgm_opt_parity_grp_t;
244
245 typedef struct {
246         nchar_t type;
247         nchar_t len;
248         nchar_t opx;
249         nchar_t res;
250         nlong_t prm_atgsz;
251 } pgm_opt_curr_tgsize_t;
252
253 typedef struct {
254         nchar_t type;
255         nchar_t len;
256         nchar_t opx;
257         nchar_t res;
258         nlong_t tsp;
259         nshort_t acker_afi;
260         nshort_t res2;
261         nlong_t acker;
262 } pgm_opt_pgmcc_data_t;
263
264 typedef struct {
265         nchar_t type;
266         nchar_t len;
267         nchar_t opx;
268         nchar_t res;
269         nlong_t tsp;
270         nshort_t acker_afi;
271         nshort_t loss_rate;
272         nlong_t acker;
273 } pgm_opt_pgmcc_feedback_t;
274
275 /*
276  * Udp port for UDP encapsulation
277  */
278 #define DEFAULT_UDP_ENCAP_UCAST_PORT 3055
279 #define DEFAULT_UDP_ENCAP_MCAST_PORT 3056
280
281 static int udp_encap_ucast_port = 0;
282 static int udp_encap_mcast_port = 0;
283 static int old_encap_ucast_port = 0;
284 static int old_encap_mcast_port = 0;
285
286 static int proto_pgm = -1;
287 static int ett_pgm = -1;
288 static int ett_pgm_optbits = -1;
289 static int ett_pgm_opts = -1;
290 static int ett_pgm_spm = -1;
291 static int ett_pgm_data = -1;
292 static int ett_pgm_nak = -1;
293 static int ett_pgm_ack = -1;
294 static int ett_pgm_opts_join = -1;
295 static int ett_pgm_opts_parityprm = -1;
296 static int ett_pgm_opts_paritygrp = -1;
297 static int ett_pgm_opts_naklist = -1;
298 static int ett_pgm_opts_ccdata = -1;
299
300 static int hf_pgm_main_sport = -1;
301 static int hf_pgm_main_dport = -1;
302 static int hf_pgm_main_type = -1;
303 static int hf_pgm_main_opts = -1;
304 static int hf_pgm_main_opts_opt = -1;
305 static int hf_pgm_main_opts_netsig = -1;
306 static int hf_pgm_main_opts_varlen = -1;
307 static int hf_pgm_main_opts_parity = -1;
308 static int hf_pgm_main_cksum = -1;
309 static int hf_pgm_main_gsi = -1;
310 static int hf_pgm_main_tsdulen = -1;
311 static int hf_pgm_spm_sqn = -1;
312 static int hf_pgm_spm_lead = -1;
313 static int hf_pgm_spm_trail = -1;
314 static int hf_pgm_spm_pathafi = -1;
315 static int hf_pgm_spm_res = -1;
316 static int hf_pgm_spm_path = -1;
317 static int hf_pgm_data_sqn = -1;
318 static int hf_pgm_data_trail = -1;
319 static int hf_pgm_nak_sqn = -1;
320 static int hf_pgm_nak_srcafi = -1;
321 static int hf_pgm_nak_srcres = -1;
322 static int hf_pgm_nak_src = -1;
323 static int hf_pgm_nak_grpafi = -1;
324 static int hf_pgm_nak_grpres = -1;
325 static int hf_pgm_nak_grp = -1;
326 static int hf_pgm_ack_sqn = -1;
327 static int hf_pgm_ack_bitmap = -1;
328
329 static int hf_pgm_opt_type = -1;
330 static int hf_pgm_opt_len = -1;
331 static int hf_pgm_opt_tlen = -1;
332
333 static int hf_pgm_genopt_type = -1;
334 static int hf_pgm_genopt_len = -1;
335 static int hf_pgm_genopt_opx = -1;
336
337 static int hf_pgm_opt_join_res = -1;
338 static int hf_pgm_opt_join_minjoin = -1;
339
340 static int hf_pgm_opt_parity_prm_po = -1;
341 static int hf_pgm_opt_parity_prm_prmtgsz = -1;
342
343 static int hf_pgm_opt_parity_grp_res = -1;
344 static int hf_pgm_opt_parity_grp_prmgrp = -1;
345
346 #ifdef PGM_UNUSED_HANDLES
347 static int hf_pgm_opt_curr_tgsize_type = -1;
348 static int hf_pgm_opt_curr_tgsize_len = -1;
349 static int hf_pgm_opt_curr_tgsize_opx = -1;
350 static int hf_pgm_opt_curr_tgsize_res = -1;
351 static int hf_pgm_opt_curr_tgsize_prmatgsz = -1;
352 #endif
353
354 static int hf_pgm_opt_nak_res = -1;
355 static int hf_pgm_opt_nak_list = -1;
356
357 static int hf_pgm_opt_ccdata_res = -1;
358 static int hf_pgm_opt_ccdata_tsp = -1;
359 static int hf_pgm_opt_ccdata_afi = -1;
360 static int hf_pgm_opt_ccdata_res2 = -1;
361 static int hf_pgm_opt_ccdata_acker = -1;
362
363 static int hf_pgm_opt_ccfeedbk_res = -1;
364 static int hf_pgm_opt_ccfeedbk_tsp = -1;
365 static int hf_pgm_opt_ccfeedbk_afi = -1;
366 static int hf_pgm_opt_ccfeedbk_lossrate = -1;
367 static int hf_pgm_opt_ccfeedbk_acker = -1;
368
369 static dissector_table_t subdissector_table;
370 static heur_dissector_list_t heur_subdissector_list;
371 static dissector_handle_t data_handle;
372
373 /*
374  * As of the time this comment was typed
375  *
376  *      http://search.ietf.org/internet-drafts/draft-speakman-pgm-spec-06.txt
377  *
378  * was the URL for the PGM draft.
379  */
380
381 static char *
382 optsstr(nchar_t opts)
383 {
384         static char msg[256];
385         char *p = msg, *str;
386
387         if (opts == 0)
388                 return("");
389
390         if (opts & PGM_OPT){
391                 sprintf(p, "Present");
392                 p += strlen("Present");
393         }
394         if (opts & PGM_OPT_NETSIG){
395                 if (p != msg)
396                         str = ",NetSig";
397                 else
398                         str = "NetSig";
399                 sprintf(p, str);
400                 p += strlen(str);
401         }
402         if (opts & PGM_OPT_VAR_PKTLEN){
403                 if (p != msg)
404                         str = ",VarLen";
405                 else
406                         str = "VarLen";
407                 sprintf(p, str);
408                 p += strlen(str);
409         }
410         if (opts & PGM_OPT_PARITY){
411                 if (p != msg)
412                         str = ",Parity";
413                 else
414                         str = "Parity";
415                 sprintf(p, str);
416                 p += strlen(str);
417         }
418         if (p == msg) {
419                 sprintf(p, "0x%x", opts);
420         }
421         return(msg);
422 }
423 static char *
424 paritystr(nchar_t parity)
425 {
426         static char msg[256];
427         char *p = msg, *str;
428
429         if (parity == 0)
430                 return("");
431
432         if (parity & PGM_OPT_PARITY_PRM_PRO){
433                 sprintf(p, "Pro-active");
434                 p += strlen("Pro-active");
435         }
436         if (parity & PGM_OPT_PARITY_PRM_OND){
437                 if (p != msg)
438                         str = ",On-demand";
439                 else
440                         str = "On-demand";
441                 sprintf(p, str);
442                 p += strlen(str);
443         }
444         if (p == msg) {
445                 sprintf(p, "0x%x", parity);
446         }
447         return(msg);
448 }
449
450 static const value_string opt_vals[] = {
451         { PGM_OPT_LENGTH,      "Length" },
452         { PGM_OPT_END,         "End" },
453         { PGM_OPT_FRAGMENT,    "Fragment" },
454         { PGM_OPT_NAK_LIST,    "NakList" },
455         { PGM_OPT_JOIN,        "Join" },
456         { PGM_OPT_REDIRECT,    "ReDirect" },
457         { PGM_OPT_SYN,         "Syn" },
458         { PGM_OPT_FIN,         "Fin" },
459         { PGM_OPT_RST,         "Rst" },
460         { PGM_OPT_PARITY_PRM,  "ParityPrm" },
461         { PGM_OPT_PARITY_GRP,  "ParityGrp" },
462         { PGM_OPT_CURR_TGSIZE, "CurrTgsiz" },
463         { PGM_OPT_PGMCC_DATA,  "CcData" },
464         { PGM_OPT_PGMCC_FEEDBACK, "CcFeedBack" },
465         { 0,                   NULL }
466 };
467
468 static const value_string opx_vals[] = {
469         { PGM_OPX_IGNORE,  "Ignore" },
470         { PGM_OPX_INVAL,   "Inval" },
471         { PGM_OPX_DISCARD, "DisCard" },
472         { 0,               NULL }
473 };
474
475 static void
476 dissect_pgmopts(tvbuff_t *tvb, int offset, proto_tree *tree,
477     const char *pktname)
478 {
479         proto_item *tf;
480         proto_tree *opts_tree = NULL;
481         proto_tree *opt_tree = NULL;
482         pgm_opt_length_t opts;
483         pgm_opt_generic_t genopts;
484         int theend = 0, firsttime = 1;
485
486         tvb_memcpy(tvb, (guint8 *)&opts, offset, sizeof(opts));
487         opts.total_len = ntohs(opts.total_len);
488
489         tf = proto_tree_add_text(tree, tvb, offset, 
490                 opts.total_len, 
491                 "%s Options (Total Length %d)", pktname, opts.total_len);
492         opts_tree = proto_item_add_subtree(tf, ett_pgm_opts);
493         proto_tree_add_uint(opts_tree, hf_pgm_opt_type, tvb, 
494                 offset, 1, opts.type);
495         proto_tree_add_uint(opts_tree, hf_pgm_opt_len, tvb, 
496                 offset+1, 1, opts.len);
497         proto_tree_add_uint(opts_tree, hf_pgm_opt_tlen, tvb, 
498                 offset+2, 2, opts.total_len);
499
500         offset += 4;
501         for (opts.total_len -= 4; opts.total_len > 0;){
502                 tvb_memcpy(tvb, (guint8 *)&genopts, offset, sizeof(genopts));
503                 if (genopts.type & PGM_OPT_END)  {
504                         genopts.type &= ~PGM_OPT_END;
505                         theend = 1;
506                 }
507                 tf = proto_tree_add_text(opts_tree, tvb, offset, genopts.len,
508                         "Option: %s, Length: %u",
509                         val_to_str(genopts.type, opt_vals, "Unknown (0x%02x)"),
510                         genopts.len);
511                 if (genopts.len == 0)
512                         break;
513
514                 switch(genopts.type) {
515                 case PGM_OPT_JOIN:{
516                         pgm_opt_join_t optdata;
517
518                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
519                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_join);
520
521                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type, 
522                                 tvb, offset, 1, genopts.type);
523
524                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb, 
525                                 offset+1, 1, genopts.len);
526
527                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx, tvb, 
528                                 offset+2, 1, genopts.opx);
529
530                         proto_tree_add_uint(opt_tree, hf_pgm_opt_join_res, tvb, 
531                                 offset+3, 1, optdata.res);
532
533                         proto_tree_add_uint(opt_tree, hf_pgm_opt_join_minjoin, tvb, 
534                                 offset+4, 4, ntohl(optdata.opt_join_min));
535
536                         break;
537                 }
538                 case PGM_OPT_PARITY_PRM:{
539                         pgm_opt_parity_prm_t optdata;
540
541                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
542                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_parityprm);
543
544                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type, 
545                                 tvb, offset, 1, genopts.type);
546
547                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb, 
548                                 offset+1, 1, genopts.len);
549
550                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx, 
551                                 tvb, offset+2, 1, genopts.opx);
552
553                         proto_tree_add_uint_format(opt_tree, hf_pgm_opt_parity_prm_po, tvb, 
554                                 offset+3, 1, optdata.po, "Parity Parameters: %s (0x%x)",
555                                 paritystr(optdata.po), optdata.po);
556
557                         proto_tree_add_uint(opt_tree, hf_pgm_opt_parity_prm_prmtgsz,
558                                 tvb, offset+4, 4, ntohl(optdata.prm_tgsz));
559
560                         break;
561                 }
562                 case PGM_OPT_PARITY_GRP:{
563                         pgm_opt_parity_grp_t optdata;
564
565                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
566                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_paritygrp);
567
568                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type, 
569                                 tvb, offset, 1, genopts.type);
570
571                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb, 
572                                 offset+1, 1, genopts.len);
573
574                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx, 
575                                 tvb, offset+2, 1, genopts.opx);
576
577                         proto_tree_add_uint(opt_tree, hf_pgm_opt_parity_grp_res, tvb, 
578                                 offset+3, 1, optdata.res);
579
580                         proto_tree_add_uint(opt_tree, hf_pgm_opt_parity_grp_prmgrp,
581                                 tvb, offset+4, 4, ntohl(optdata.prm_grp));
582
583                         break;
584                 }
585                 case PGM_OPT_NAK_LIST:{
586                         pgm_opt_nak_list_t optdata;
587                         nlong_t naklist[PGM_MAX_NAK_LIST_SZ+1];
588                         char nakbuf[8192], *ptr;
589                         int i, j, naks, soffset = 0;
590
591                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
592                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_naklist);
593
594                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type, tvb, 
595                                 offset, 1, genopts.type);
596
597                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb, 
598                                 offset+1, 1, genopts.len);
599
600                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx, 
601                                 tvb, offset+2, 1, genopts.opx);
602
603                         proto_tree_add_uint(opt_tree, hf_pgm_opt_nak_res, tvb, 
604                                 offset+3, 1, optdata.res);
605
606                         optdata.len -= sizeof(pgm_opt_nak_list_t);
607                         tvb_memcpy(tvb, (guint8 *)naklist, offset+4, optdata.len);
608                         naks = (optdata.len/sizeof(nlong_t));
609                         ptr = nakbuf;
610                         j = 0;
611                         /*
612                          * Print out 8 per line 
613                          */
614                         for (i=0; i < naks; i++) {
615                                 sprintf(nakbuf+soffset, "0x%lx ",
616                                     (unsigned long)ntohl(naklist[i]));
617                                 soffset = strlen(nakbuf);
618                                 if ((++j % 8) == 0) {
619                                         if (firsttime) {
620                                                 proto_tree_add_bytes_format(opt_tree, 
621                                                         hf_pgm_opt_nak_list, tvb, offset+4, optdata.len,
622                                                         nakbuf, "List(%d): %s", naks, nakbuf);
623                                                         soffset = 0;
624                                         } else {
625                                                 proto_tree_add_bytes_format(opt_tree, 
626                                                         hf_pgm_opt_nak_list, tvb, offset+4, optdata.len, 
627                                                         nakbuf, "List: %s", nakbuf);
628                                                         soffset = 0;
629                                         }
630                                         firsttime = 0;
631                                 }
632                         }
633                         if (soffset) {
634                                 if (firsttime) {
635                                         proto_tree_add_bytes_format(opt_tree, 
636                                                 hf_pgm_opt_nak_list, tvb, offset+4, optdata.len,
637                                                 nakbuf, "List(%d): %s", naks, nakbuf);
638                                                 soffset = 0;
639                                 } else {
640                                         proto_tree_add_bytes_format(opt_tree, 
641                                                 hf_pgm_opt_nak_list, tvb, offset+4, optdata.len, 
642                                                 nakbuf, "List: %s", nakbuf);
643                                                 soffset = 0;
644                                 }
645                         }
646                         break;
647                 }
648                 case PGM_OPT_PGMCC_DATA:{
649                         pgm_opt_pgmcc_data_t optdata;
650
651                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
652                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_ccdata);
653
654                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type, 
655                                 tvb, offset, 1, genopts.type);
656
657                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb, 
658                                 offset+1, 1, genopts.len);
659
660                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx, 
661                                 tvb, offset+2, 1, genopts.opx);
662
663                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccdata_res, tvb, 
664                                 offset+3, 1, optdata.res);
665
666                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccdata_tsp, tvb, 
667                                 offset+4, 4, optdata.tsp);
668
669                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccdata_afi, tvb, 
670                                 offset+8, 2, ntohs(optdata.acker_afi));
671
672                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccdata_res2, tvb, 
673                                 offset+10, 2, ntohs(optdata.res2));
674
675                         switch (ntohs(optdata.acker_afi)) {
676
677                         case AFNUM_INET:
678                                 proto_tree_add_ipv4(opt_tree, hf_pgm_opt_ccdata_acker,
679                                     tvb, offset+12, 4, optdata.acker);
680                                 break;
681
682                         default:
683                                 /*
684                                  * XXX - the header is variable-length,
685                                  * as the length of the NLA depends on
686                                  * its AFI.
687                                  *
688                                  * However, our structure for it is
689                                  * fixed-length, and assumes it's a 4-byte
690                                  * IPv4 address.
691                                  */
692                                 break;
693                         }
694
695                         break;
696                 }
697                 case PGM_OPT_PGMCC_FEEDBACK:{
698                         pgm_opt_pgmcc_feedback_t optdata;
699
700                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
701                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_ccdata);
702
703                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type, 
704                                 tvb, offset, 1, genopts.type);
705
706                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb, 
707                                 offset+1, 1, genopts.len);
708
709                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx, 
710                                 tvb, offset+2, 1, genopts.opx);
711
712                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccfeedbk_res, tvb, 
713                                 offset+3, 1, optdata.res);
714
715                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccfeedbk_tsp, tvb, 
716                                 offset+4, 4, optdata.tsp);
717
718                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccfeedbk_afi, tvb, 
719                                 offset+8, 2, ntohs(optdata.acker_afi));
720
721                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccfeedbk_lossrate, tvb, 
722                                 offset+10, 2, ntohs(optdata.loss_rate));
723
724                         switch (ntohs(optdata.acker_afi)) {
725
726                         case AFNUM_INET:
727                                 proto_tree_add_ipv4(opt_tree, hf_pgm_opt_ccfeedbk_acker,
728                                     tvb, offset+12, 4, optdata.acker);
729                                 break;
730
731                         default:
732                                 /*
733                                  * XXX - the header is variable-length,
734                                  * as the length of the NLA depends on
735                                  * its AFI.
736                                  *
737                                  * However, our structure for it is
738                                  * fixed-length, and assumes it's a 4-byte
739                                  * IPv4 address.
740                                  */
741                                 break;
742                         }
743
744                         break;
745                 }
746                 }
747                 offset += genopts.len;
748                 opts.total_len -= genopts.len;
749
750         }
751         return ;
752 }
753
754 static const value_string type_vals[] = {
755         { PGM_SPM_PCKT,   "SPM" },
756         { PGM_RDATA_PCKT, "RDATA" },
757         { PGM_ODATA_PCKT, "ODATA" },
758         { PGM_NAK_PCKT,   "NAK" },
759         { PGM_NNAK_PCKT,  "NNAK" },
760         { PGM_NCF_PCKT,   "NCF" },
761         { PGM_ACK_PCKT,   "ACK" },
762         { 0,              NULL }
763 };
764 /* Determine if there is a sub-dissector and call it.  This has been */
765 /* separated into a stand alone routine to other protocol dissectors */
766 /* can call to it, ie. socks    */
767
768 void
769 decode_pgm_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,
770         proto_tree *tree, pgm_type *pgmhdr)
771 {
772   tvbuff_t *next_tvb;
773   int found = 0;
774
775   next_tvb = tvb_new_subset(tvb, offset, -1, -1);
776
777   /* do lookup with the subdissector table */
778   found = dissector_try_port(subdissector_table, pgmhdr->sport, 
779                         next_tvb, pinfo, tree);
780   if (found)
781         return;
782
783   found = dissector_try_port(subdissector_table, pgmhdr->dport, 
784                         next_tvb, pinfo, tree);
785   if (found)
786         return;
787
788   /* do lookup with the heuristic subdissector table */
789   if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree))
790     return;
791
792   /* Oh, well, we don't know this; dissect it as data. */
793   call_dissector(data_handle,next_tvb, pinfo, tree);
794
795 }
796 int 
797 total_size(tvbuff_t *tvb, pgm_type *hdr)
798 {
799         int bytes = sizeof(pgm_type);
800         pgm_opt_length_t opts;
801
802         switch(hdr->type) {
803         case PGM_SPM_PCKT:
804                 bytes += sizeof(pgm_spm_t);
805                 break;
806
807         case PGM_RDATA_PCKT:
808         case PGM_ODATA_PCKT:
809                 bytes += sizeof(pgm_data_t);
810                 break;
811
812         case PGM_NAK_PCKT:
813         case PGM_NNAK_PCKT:
814         case PGM_NCF_PCKT:
815                 bytes += sizeof(pgm_nak_t);
816                 break;
817         case PGM_ACK_PCKT:
818                 bytes += sizeof(pgm_ack_t);
819                 break;
820         }
821         if ((hdr->opts & PGM_OPT)) {
822                 tvb_memcpy(tvb, (guint8 *)&opts, bytes, sizeof(opts));
823                 bytes += ntohs(opts.total_len);
824         }
825         return(bytes);
826 }
827 /*
828  * dissect_pgm - The dissector for Pragmatic General Multicast
829  */
830 static void
831 dissect_pgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
832 {
833         proto_tree *pgm_tree = NULL;
834         proto_tree *opt_tree = NULL;
835         proto_tree *type_tree = NULL;
836         proto_item *tf;
837         pgm_type pgmhdr;
838         pgm_spm_t spm;
839         pgm_data_t data;
840         pgm_nak_t nak;
841         pgm_ack_t ack;
842         int offset = 0;
843         guint hlen, plen;
844         proto_item *ti;
845         const char *pktname;
846         char *gsi;
847         int isdata = 0;
848
849         if (check_col(pinfo->cinfo, COL_PROTOCOL))
850                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PGM");
851
852         /* Clear out the Info column. */
853         if (check_col(pinfo->cinfo, COL_INFO))
854                 col_clear(pinfo->cinfo, COL_INFO);
855
856         tvb_memcpy(tvb, (guint8 *)&pgmhdr, offset, sizeof(pgm_type));
857         hlen = sizeof(pgm_type);
858         pgmhdr.sport = ntohs(pgmhdr.sport);
859         pgmhdr.dport = ntohs(pgmhdr.dport);
860         pgmhdr.tsdulen = ntohs(pgmhdr.tsdulen);
861
862         pktname = val_to_str(pgmhdr.type, type_vals, "Unknown (0x%02x)");
863
864         gsi = bytes_to_str(pgmhdr.gsi, 6);
865         switch(pgmhdr.type) {
866         case PGM_SPM_PCKT:
867                 plen = sizeof(pgm_spm_t);
868                 tvb_memcpy(tvb, (guint8 *)&spm, sizeof(pgm_type), plen);
869                 spm_ntoh(&spm);
870                 if (check_col(pinfo->cinfo, COL_INFO)) {
871                         col_add_fstr(pinfo->cinfo, COL_INFO,
872                                 "%-5s sqn 0x%x gsi %s", pktname, spm.sqn, gsi);
873                 }
874                 break;
875
876         case PGM_RDATA_PCKT:
877         case PGM_ODATA_PCKT:
878                 plen = sizeof(pgm_data_t);
879                 tvb_memcpy(tvb, (guint8 *)&data, sizeof(pgm_type), plen);
880                 data_ntoh(&data);
881                 if (check_col(pinfo->cinfo, COL_INFO)) {
882                         col_add_fstr(pinfo->cinfo, COL_INFO,
883                             "%-5s sqn 0x%x gsi %s tsdulen %d", pktname, data.sqn, gsi,
884                             pgmhdr.tsdulen);
885                 }
886                 isdata = 1;
887                 break;
888
889         case PGM_NAK_PCKT:
890         case PGM_NNAK_PCKT:
891         case PGM_NCF_PCKT:
892                 plen = sizeof(pgm_nak_t);
893                 tvb_memcpy(tvb, (guint8 *)&nak, sizeof(pgm_type), plen);
894                 nak_ntoh(&nak);
895                 if (check_col(pinfo->cinfo, COL_INFO)) {
896                         col_add_fstr(pinfo->cinfo, COL_INFO,
897                                 "%-5s sqn 0x%x gsi %s", pktname, nak.sqn, gsi);
898                 }
899                 break;
900         case PGM_ACK_PCKT:
901                 plen = sizeof(pgm_ack_t);
902                 tvb_memcpy(tvb, (guint8 *)&ack, sizeof(pgm_type), plen);
903                 ack_ntoh(&ack);
904                 if (check_col(pinfo->cinfo, COL_INFO)) {
905                         col_add_fstr(pinfo->cinfo, COL_INFO,
906                             "%-5s sqn 0x%x gsi %s", pktname, ack.rx_max_sqn, gsi);
907                 }
908                 break;
909
910         default:
911                 return;
912         }
913
914         if (tree) {
915                 ti = proto_tree_add_protocol_format(tree, proto_pgm, 
916                         tvb, offset, total_size(tvb, &pgmhdr),
917                         "Pragmatic General Multicast: Type %s"
918                             " SrcPort %u, DstPort %u, GSI %s", pktname,
919                         pgmhdr.sport, pgmhdr.dport,
920                         bytes_to_str(pgmhdr.gsi, 6));
921
922                 pgm_tree = proto_item_add_subtree(ti, ett_pgm);
923                 proto_tree_add_uint(pgm_tree, hf_pgm_main_sport, tvb, offset, 2,
924                         pgmhdr.sport);
925                 proto_tree_add_uint(pgm_tree, hf_pgm_main_dport, tvb, offset+2, 
926                         2, pgmhdr.dport);
927                 proto_tree_add_uint(pgm_tree, hf_pgm_main_type, tvb, 
928                         offset+4, 1, pgmhdr.type);
929
930                 tf = proto_tree_add_uint_format(pgm_tree, hf_pgm_main_opts, tvb, 
931                         offset+5, 1, pgmhdr.opts, "Options: %s (0x%x)", 
932                         optsstr(pgmhdr.opts), pgmhdr.opts);
933                 opt_tree = proto_item_add_subtree(tf, ett_pgm_optbits);
934
935                 proto_tree_add_boolean(opt_tree, hf_pgm_main_opts_opt, tvb, 
936                         offset+5, 1, (pgmhdr.opts & PGM_OPT));
937                 proto_tree_add_boolean(opt_tree, hf_pgm_main_opts_netsig, tvb, 
938                         offset+5, 1, (pgmhdr.opts & PGM_OPT_NETSIG));
939                 proto_tree_add_boolean(opt_tree, hf_pgm_main_opts_varlen, tvb, 
940                         offset+5, 1, (pgmhdr.opts & PGM_OPT_VAR_PKTLEN));
941                 proto_tree_add_boolean(opt_tree, hf_pgm_main_opts_parity, tvb, 
942                         offset+5, 1, (pgmhdr.opts & PGM_OPT_PARITY));
943
944                 proto_tree_add_uint(pgm_tree, hf_pgm_main_cksum, tvb, offset+6, 
945                         2, pgmhdr.cksum);
946                 proto_tree_add_bytes(pgm_tree, hf_pgm_main_gsi, tvb, offset+8, 
947                         6, pgmhdr.gsi);
948                 proto_tree_add_uint(pgm_tree, hf_pgm_main_tsdulen, tvb, 
949                         offset+14, 2, pgmhdr.tsdulen);
950
951                 offset = sizeof(pgm_type);
952                 tf = proto_tree_add_text(pgm_tree, tvb, offset, plen, "%s Packet",
953                         pktname);
954                 switch(pgmhdr.type) {
955                 case PGM_SPM_PCKT:
956                         type_tree = proto_item_add_subtree(tf, ett_pgm_spm);
957
958                         proto_tree_add_uint(type_tree, hf_pgm_spm_sqn, tvb, 
959                                 offset, 4, spm.sqn);
960                         proto_tree_add_uint(type_tree, hf_pgm_spm_trail, tvb, 
961                                 offset+4, 4, spm.trail);
962                         proto_tree_add_uint(type_tree, hf_pgm_spm_lead, tvb, 
963                                 offset+8, 4, spm.lead);
964                         proto_tree_add_uint(type_tree, hf_pgm_spm_pathafi, tvb, 
965                                 offset+10, 2, spm.path_afi);
966                         proto_tree_add_uint(type_tree, hf_pgm_spm_res, tvb, 
967                                 offset+12, 2, spm.res);
968                         switch (spm.path_afi) {
969
970                         case AFNUM_INET:
971                                 proto_tree_add_ipv4(type_tree, hf_pgm_spm_path,
972                                     tvb, offset+14, 4, spm.path);
973                                 break;
974
975                         default:
976                                 /*
977                                  * XXX - the header is variable-length,
978                                  * as the length of the NLA depends on
979                                  * its AFI.
980                                  *
981                                  * However, our structure for it is
982                                  * fixed-length, and assumes it's a 4-byte
983                                  * IPv4 address.
984                                  */
985                                 return;
986                         }
987
988                         if ((pgmhdr.opts & PGM_OPT) == FALSE)
989                                 break;
990                         offset += plen;
991
992                         dissect_pgmopts(tvb, offset, type_tree, pktname);
993
994                         break;
995
996                 case PGM_RDATA_PCKT:
997                 case PGM_ODATA_PCKT: {
998                         type_tree = proto_item_add_subtree(tf, ett_pgm_data);
999
1000                         proto_tree_add_uint(type_tree, hf_pgm_spm_sqn, tvb, 
1001                                 offset, 4, data.sqn);
1002                         proto_tree_add_uint(type_tree, hf_pgm_spm_trail, tvb, 
1003                                 offset+4, 4, data.trail);
1004
1005                         if ((pgmhdr.opts & PGM_OPT) == FALSE)
1006                                 break;
1007                         offset += plen;
1008
1009                         dissect_pgmopts(tvb, offset, type_tree, pktname);
1010
1011                         break;
1012                 }
1013
1014
1015                 case PGM_NAK_PCKT:
1016                 case PGM_NNAK_PCKT:
1017                 case PGM_NCF_PCKT:
1018                         type_tree = proto_item_add_subtree(tf, ett_pgm_nak);
1019
1020                         proto_tree_add_uint(type_tree, hf_pgm_nak_sqn, tvb, 
1021                                 offset, 4, nak.sqn);
1022                         proto_tree_add_uint(type_tree, hf_pgm_nak_srcafi, tvb, 
1023                                 offset+4, 2, nak.src_afi);
1024                         proto_tree_add_uint(type_tree, hf_pgm_nak_srcres, tvb, 
1025                                 offset+6, 2, nak.src_res);
1026
1027                         switch (nak.src_afi) {
1028
1029                         case AFNUM_INET:
1030                                 proto_tree_add_ipv4(type_tree, hf_pgm_nak_src,
1031                                     tvb, offset+8, 4, nak.src);
1032                                 break;
1033
1034                         default:
1035                                 /*
1036                                  * XXX - the header is variable-length,
1037                                  * as the length of the NLA depends on
1038                                  * its AFI.
1039                                  *
1040                                  * However, our structure for it is
1041                                  * fixed-length, and assumes it's a 4-byte
1042                                  * IPv4 address.
1043                                  */
1044                                 break;
1045                         }
1046
1047                         proto_tree_add_uint(type_tree, hf_pgm_nak_grpafi, tvb, 
1048                                 offset+12, 2, nak.grp_afi);
1049                         proto_tree_add_uint(type_tree, hf_pgm_nak_grpres, tvb, 
1050                                 offset+14, 2, nak.grp_res);
1051
1052                         switch (nak.grp_afi) {
1053
1054                         case AFNUM_INET:
1055                                 proto_tree_add_ipv4(type_tree, hf_pgm_nak_grp,
1056                                     tvb, offset+16, 4, nak.grp);
1057                                 break;
1058
1059                         default:
1060                                 /*
1061                                  * XXX - the header is variable-length,
1062                                  * as the length of the NLA depends on
1063                                  * its AFI.
1064                                  *
1065                                  * However, our structure for it is
1066                                  * fixed-length, and assumes it's a 4-byte
1067                                  * IPv4 address.
1068                                  */
1069                                 return;
1070                         }
1071
1072                         if ((pgmhdr.opts & PGM_OPT) == FALSE)
1073                                 break;
1074                         offset += plen;
1075
1076                         dissect_pgmopts(tvb, offset, type_tree, pktname);
1077
1078                         break;
1079                 case PGM_ACK_PCKT:
1080                         type_tree = proto_item_add_subtree(tf, ett_pgm_ack);
1081
1082                         proto_tree_add_uint(type_tree, hf_pgm_ack_sqn, tvb, 
1083                                 offset, 4, ack.rx_max_sqn);
1084                         proto_tree_add_uint(type_tree, hf_pgm_ack_bitmap, tvb, 
1085                                 offset+4, 4, ack.bitmap);
1086
1087                         if ((pgmhdr.opts & PGM_OPT) == FALSE)
1088                                 break;
1089                         offset += plen;
1090
1091                         dissect_pgmopts(tvb, offset, type_tree, pktname);
1092
1093                         break;
1094                 }
1095
1096         }
1097         if (isdata) {
1098                 /*
1099                  * Now see if there are any sub-dissectors, if so call them
1100                  */
1101                 offset = total_size(tvb, &pgmhdr);
1102                 decode_pgm_ports(tvb, offset, pinfo, tree, &pgmhdr);
1103         }
1104         pktname = NULL;
1105 }
1106 static const true_false_string opts_present = {      
1107         "Present",
1108         "Not Present" 
1109 };
1110
1111 /* Register all the bits needed with the filtering engine */
1112 void 
1113 proto_register_pgm(void)
1114 {
1115   static hf_register_info hf[] = {
1116     { &hf_pgm_main_sport,
1117       { "Source Port", "pgm.hdr.sport", FT_UINT16, BASE_DEC,
1118           NULL, 0x0, "", HFILL }},
1119     { &hf_pgm_main_dport,
1120       { "Destination Port", "pgm.hdr.dport", FT_UINT16, BASE_DEC,
1121           NULL, 0x0, "", HFILL }},
1122     { &hf_pgm_main_type,
1123       { "Type", "pgm.hdr.type", FT_UINT8, BASE_HEX,
1124           VALS(type_vals), 0x0, "", HFILL }},
1125     { &hf_pgm_main_opts,
1126       { "Options", "pgm.hdr.opts", FT_UINT8, BASE_HEX,
1127           NULL, 0x0, "", HFILL }},
1128     { &hf_pgm_main_opts_opt,
1129       { "Options", "pgm.hdr.opts.opt", FT_BOOLEAN, BASE_NONE,
1130           TFS(&opts_present), PGM_OPT, "", HFILL }},
1131     { &hf_pgm_main_opts_netsig,
1132       { "Network Significant Options", "pgm.hdr.opts.netsig", 
1133           FT_BOOLEAN, BASE_NONE,
1134           TFS(&opts_present), PGM_OPT_NETSIG, "", HFILL }},
1135     { &hf_pgm_main_opts_varlen,
1136       { "Variable length Parity Packet Option", "pgm.hdr.opts.varlen", 
1137           FT_BOOLEAN, BASE_NONE,
1138           TFS(&opts_present), PGM_OPT_VAR_PKTLEN, "", HFILL }},
1139     { &hf_pgm_main_opts_parity,
1140       { "Parity", "pgm.hdr.opts.parity", FT_BOOLEAN, BASE_NONE,
1141           TFS(&opts_present), PGM_OPT_PARITY, "", HFILL }},
1142     { &hf_pgm_main_cksum,
1143       { "Checksum", "pgm.hdr.cksum", FT_UINT16, BASE_HEX,
1144         NULL, 0x0, "", HFILL }},
1145     { &hf_pgm_main_gsi,
1146       { "Global Source Identifier", "pgm.hdr.gsi", FT_BYTES, BASE_HEX, 
1147           NULL, 0x0, "", HFILL }},
1148     { &hf_pgm_main_tsdulen,
1149       { "Transport Service Data Unit Length", "pgm.hdr.tsdulen", FT_UINT16, 
1150           BASE_DEC, NULL, 0x0, "", HFILL }},
1151     { &hf_pgm_spm_sqn,
1152       { "Sequence number", "pgm.spm.sqn", FT_UINT32, BASE_HEX,
1153           NULL, 0x0, "", HFILL }},
1154     { &hf_pgm_spm_trail,
1155       { "Trailing Edge Sequence Number", "pgm.spm.trail", FT_UINT32, BASE_HEX, 
1156           NULL, 0x0, "", HFILL }},
1157     { &hf_pgm_spm_lead,
1158       { "Leading Edge Sequence Number", "pgm.spm.lead", FT_UINT32, BASE_HEX, 
1159           NULL, 0x0, "", HFILL }},
1160     { &hf_pgm_spm_pathafi,
1161       { "Path NLA AFI", "pgm.spm.pathafi", FT_UINT16, BASE_DEC,
1162           VALS(afn_vals), 0x0, "", HFILL }},
1163     { &hf_pgm_spm_res,
1164       { "Reserved", "pgm.spm.res", FT_UINT16, BASE_HEX,
1165           NULL, 0x0, "", HFILL }},
1166     { &hf_pgm_spm_path,
1167       { "Path NLA", "pgm.spm.path", FT_IPv4, BASE_NONE,
1168           NULL, 0x0, "", HFILL }},
1169     { &hf_pgm_data_sqn,
1170       { "Data Packet Sequence Number", "pgm.data.sqn", FT_UINT32, BASE_HEX, 
1171           NULL, 0x0, "", HFILL }},
1172     { &hf_pgm_data_trail,
1173       { "Trailing Edge Sequence Number", "pgm.data.trail", FT_UINT32, BASE_HEX, 
1174           NULL, 0x0, "", HFILL }},
1175     { &hf_pgm_nak_sqn,
1176       { "Requested Sequence Number", "pgm.nak.sqn", FT_UINT32, BASE_HEX, 
1177           NULL, 0x0, "", HFILL }},
1178     { &hf_pgm_nak_srcafi,
1179       { "Source NLA AFI", "pgm.nak.srcafi", FT_UINT16, BASE_DEC,
1180           VALS(afn_vals), 0x0, "", HFILL }},
1181     { &hf_pgm_nak_srcres,
1182       { "Reserved", "pgm.nak.srcres", FT_UINT16, BASE_HEX,
1183           NULL, 0x0, "", HFILL }},
1184     { &hf_pgm_nak_src,
1185       { "Source NLA", "pgm.nak.src", FT_IPv4, BASE_NONE,
1186           NULL, 0x0, "", HFILL }},
1187     { &hf_pgm_nak_grpafi,
1188       { "Multicast Group AFI", "pgm.nak.grpafi", FT_UINT16, BASE_DEC,
1189           VALS(afn_vals), 0x0, "", HFILL }},
1190     { &hf_pgm_nak_grpres,
1191       { "Reserved", "pgm.nak.grpres", FT_UINT16, BASE_HEX,
1192           NULL, 0x0, "", HFILL }},
1193     { &hf_pgm_nak_grp,
1194       { "Multicast Group NLA", "pgm.nak.grp", FT_IPv4, BASE_NONE,
1195           NULL, 0x0, "", HFILL }},
1196     { &hf_pgm_ack_sqn,
1197       { "Maximum Received Sequence Number", "pgm.ack.maxsqn", FT_UINT32, 
1198           BASE_HEX, NULL, 0x0, "", HFILL }},
1199     { &hf_pgm_ack_bitmap,
1200       { "Packet Bitmap", "pgm.ack.bitmap", FT_UINT32, BASE_HEX, 
1201           NULL, 0x0, "", HFILL }},
1202     { &hf_pgm_opt_type,
1203       { "Type", "pgm.opts.type", FT_UINT8, BASE_HEX,
1204           VALS(opt_vals), 0x0, "", HFILL }},
1205     { &hf_pgm_opt_len,
1206       { "Length", "pgm.opts.len", FT_UINT8, BASE_DEC,
1207           NULL, 0x0, "", HFILL }},
1208     { &hf_pgm_opt_tlen,
1209       { "Total Length", "pgm.opts.tlen", FT_UINT16, BASE_DEC,
1210           NULL, 0x0, "", HFILL }},
1211     { &hf_pgm_genopt_type,
1212       { "Type", "pgm.genopts.type", FT_UINT8, BASE_HEX,
1213           VALS(opt_vals), 0x0, "", HFILL }},
1214     { &hf_pgm_genopt_len,
1215       { "Length", "pgm.genopts.len", FT_UINT8, BASE_DEC,
1216           NULL, 0x0, "", HFILL }},
1217     { &hf_pgm_genopt_opx,
1218       { "Option Extensibility Bits", "pgm.genopts.opx", FT_UINT8, BASE_HEX,
1219           VALS(opx_vals), 0x0, "", HFILL }},
1220     { &hf_pgm_opt_parity_prm_po,
1221       { "Parity Parameters", "pgm.opts.parity_prm.op", FT_UINT8, BASE_HEX,
1222           NULL, 0x0, "", HFILL }},
1223     { &hf_pgm_opt_parity_prm_prmtgsz,
1224       { "Transmission Group Size", "pgm.opts.parity_prm.prm_grp",
1225           FT_UINT32, BASE_HEX,
1226           NULL, 0x0, "", HFILL }},
1227     { &hf_pgm_opt_join_res,
1228       { "Reserved", "pgm.opts.join.res", FT_UINT8, BASE_HEX,
1229           NULL, 0x0, "", HFILL }},
1230     { &hf_pgm_opt_join_minjoin,
1231       { "Minimum Sequence Number", "pgm.opts.join.min_join",
1232           FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
1233     { &hf_pgm_opt_parity_grp_res,
1234       { "Reserved", "pgm.opts.parity_prm.op", FT_UINT8, BASE_HEX,
1235           NULL, 0x0, "", HFILL }},
1236     { &hf_pgm_opt_parity_grp_prmgrp,
1237       { "Transmission Group Size", "pgm.opts.parity_prm.prm_grp",
1238           FT_UINT32, BASE_HEX,
1239           NULL, 0x0, "", HFILL }},
1240     { &hf_pgm_opt_nak_res,
1241       { "Reserved", "pgm.opts.nak.op", FT_UINT8, BASE_HEX,
1242           NULL, 0x0, "", HFILL }},
1243     { &hf_pgm_opt_nak_list,
1244       { "List", "pgm.opts.nak.list", FT_BYTES, BASE_NONE,
1245           NULL, 0x0, "", HFILL }},
1246     { &hf_pgm_opt_ccdata_res,
1247       { "Reserved", "pgm.opts.ccdata.res", FT_UINT8, BASE_DEC,
1248           NULL, 0x0, "", HFILL }},
1249     { &hf_pgm_opt_ccdata_tsp,
1250       { "Time Stamp", "pgm.opts.ccdata.tstamp", FT_UINT16, BASE_HEX,
1251           NULL, 0x0, "", HFILL }},
1252     { &hf_pgm_opt_ccdata_afi,
1253       { "Acker AFI", "pgm.opts.ccdata.afi", FT_UINT16, BASE_DEC,
1254           VALS(afn_vals), 0x0, "", HFILL }},
1255     { &hf_pgm_opt_ccdata_res2,
1256       { "Reserved", "pgm.opts.ccdata.res2", FT_UINT16, BASE_DEC,
1257           NULL, 0x0, "", HFILL }},
1258     { &hf_pgm_opt_ccdata_acker,
1259       { "Acker", "pgm.opts.ccdata.acker", FT_IPv4, BASE_NONE,
1260           NULL, 0x0, "", HFILL }},
1261     { &hf_pgm_opt_ccfeedbk_res,
1262       { "Reserved", "pgm.opts.ccdata.res", FT_UINT8, BASE_DEC,
1263           NULL, 0x0, "", HFILL }},
1264     { &hf_pgm_opt_ccfeedbk_tsp,
1265       { "Time Stamp", "pgm.opts.ccdata.tstamp", FT_UINT16, BASE_HEX,
1266           NULL, 0x0, "", HFILL }},
1267     { &hf_pgm_opt_ccfeedbk_afi,
1268       { "Acker AFI", "pgm.opts.ccdata.afi", FT_UINT16, BASE_DEC,
1269           VALS(afn_vals), 0x0, "", HFILL }},
1270     { &hf_pgm_opt_ccfeedbk_lossrate,
1271       { "Loss Rate", "pgm.opts.ccdata.lossrate", FT_UINT16, BASE_HEX,
1272           NULL, 0x0, "", HFILL }},
1273     { &hf_pgm_opt_ccfeedbk_acker,
1274       { "Acker", "pgm.opts.ccdata.acker", FT_IPv4, BASE_NONE,
1275           NULL, 0x0, "", HFILL }},
1276   };
1277   static gint *ett[] = {
1278     &ett_pgm,
1279         &ett_pgm_optbits,
1280         &ett_pgm_spm,
1281         &ett_pgm_data,
1282         &ett_pgm_nak,
1283         &ett_pgm_ack,
1284         &ett_pgm_opts,
1285         &ett_pgm_opts_join,
1286         &ett_pgm_opts_parityprm,
1287         &ett_pgm_opts_paritygrp,
1288         &ett_pgm_opts_naklist,
1289         &ett_pgm_opts_ccdata,
1290   };
1291   module_t *pgm_module;
1292
1293   proto_pgm = proto_register_protocol("Pragmatic General Multicast",
1294                                        "PGM", "pgm");
1295
1296   proto_register_field_array(proto_pgm, hf, array_length(hf));
1297   proto_register_subtree_array(ett, array_length(ett));
1298
1299         /* subdissector code */
1300   subdissector_table = register_dissector_table("pgm.port",
1301                 "PGM port", FT_UINT16, BASE_DEC);
1302   register_heur_dissector_list("pgm", &heur_subdissector_list);
1303
1304   /*
1305    * Register configuration preferences for UDP encapsulation
1306    * (Note: Initially the ports are set to zero so the 
1307    *        dissecting of PGM encapsulated in UPD packets
1308    *        is off by default)
1309    */
1310    pgm_module = prefs_register_protocol(proto_pgm, proto_rereg_pgm);
1311
1312    prefs_register_uint_preference(pgm_module, "udp.encap_ucast_port",
1313                 "PGM Encap Unicast Port (standard is 3055)", 
1314                 "PGM Encap is PGM packets encapsulated in UDP packets"
1315                 " (Note: This option is off, i.e. port is 0, by default)", 
1316                 10, &udp_encap_ucast_port);
1317    old_encap_ucast_port = udp_encap_ucast_port;
1318
1319    prefs_register_uint_preference(pgm_module, "udp.encap_mcast_port",
1320                 "PGM Encap Multicast Port (standard is 3056)", 
1321                 "PGM Encap is PGM packets encapsulated in UDP packets"
1322                 " (Note: This option is off, i.e. port is 0, by default)", 
1323                 10, &udp_encap_mcast_port);
1324
1325    old_encap_mcast_port = udp_encap_mcast_port;
1326 }
1327
1328 static dissector_handle_t pgm_handle;
1329
1330 /* The registration hand-off routine */
1331 void
1332 proto_reg_handoff_pgm(void)
1333 {
1334   pgm_handle = create_dissector_handle(dissect_pgm, proto_pgm);
1335
1336   /*
1337    * Set up PGM Encap dissecting, which is off by default
1338    */
1339   dissector_add("udp.port", udp_encap_ucast_port, pgm_handle);
1340   dissector_add("udp.port", udp_encap_mcast_port, pgm_handle);
1341
1342   dissector_add("ip.proto", IP_PROTO_PGM, pgm_handle);
1343   
1344   data_handle = find_dissector("data");
1345 }
1346
1347 static void
1348 proto_rereg_pgm(void)
1349 {
1350         /*
1351          * Remove the old ones
1352          */
1353         dissector_delete("udp.port", old_encap_ucast_port, pgm_handle);
1354         dissector_delete("udp.port", old_encap_mcast_port, pgm_handle);
1355
1356         /*
1357          * Set the new ones
1358          */
1359         dissector_add("udp.port", udp_encap_ucast_port, pgm_handle);
1360         dissector_add("udp.port", udp_encap_mcast_port, pgm_handle);
1361 }