Use "tvb_get_ntohieee_float()" to fetch floating-point numbers.
[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.15 2002/04/14 23:04:03 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 static int hf_pgm_opt_curr_tgsize_type = -1;
347 static int hf_pgm_opt_curr_tgsize_len = -1;
348 static int hf_pgm_opt_curr_tgsize_opx = -1;
349 static int hf_pgm_opt_curr_tgsize_res = -1;
350 static int hf_pgm_opt_curr_tgsize_prmatgsz = -1;
351
352 static int hf_pgm_opt_nak_res = -1;
353 static int hf_pgm_opt_nak_list = -1;
354
355 static int hf_pgm_opt_ccdata_res = -1;
356 static int hf_pgm_opt_ccdata_tsp = -1;
357 static int hf_pgm_opt_ccdata_afi = -1;
358 static int hf_pgm_opt_ccdata_res2 = -1;
359 static int hf_pgm_opt_ccdata_acker = -1;
360
361 static int hf_pgm_opt_ccfeedbk_res = -1;
362 static int hf_pgm_opt_ccfeedbk_tsp = -1;
363 static int hf_pgm_opt_ccfeedbk_afi = -1;
364 static int hf_pgm_opt_ccfeedbk_lossrate = -1;
365 static int hf_pgm_opt_ccfeedbk_acker = -1;
366
367 static dissector_table_t subdissector_table;
368 static heur_dissector_list_t heur_subdissector_list;
369 static dissector_handle_t data_handle;
370
371 /*
372  * As of the time this comment was typed
373  *
374  *      http://search.ietf.org/internet-drafts/draft-speakman-pgm-spec-06.txt
375  *
376  * was the URL for the PGM draft.
377  */
378
379 static char *
380 optsstr(nchar_t opts)
381 {
382         static char msg[256];
383         char *p = msg, *str;
384
385         if (opts == 0)
386                 return("");
387
388         if (opts & PGM_OPT){
389                 sprintf(p, "Present");
390                 p += strlen("Present");
391         }
392         if (opts & PGM_OPT_NETSIG){
393                 if (p != msg)
394                         str = ",NetSig";
395                 else
396                         str = "NetSig";
397                 sprintf(p, str);
398                 p += strlen(str);
399         }
400         if (opts & PGM_OPT_VAR_PKTLEN){
401                 if (p != msg)
402                         str = ",VarLen";
403                 else
404                         str = "VarLen";
405                 sprintf(p, str);
406                 p += strlen(str);
407         }
408         if (opts & PGM_OPT_PARITY){
409                 if (p != msg)
410                         str = ",Parity";
411                 else
412                         str = "Parity";
413                 sprintf(p, str);
414                 p += strlen(str);
415         }
416         if (p == msg) {
417                 sprintf(p, "0x%x", opts);
418         }
419         return(msg);
420 }
421 static char *
422 paritystr(nchar_t parity)
423 {
424         static char msg[256];
425         char *p = msg, *str;
426
427         if (parity == 0)
428                 return("");
429
430         if (parity & PGM_OPT_PARITY_PRM_PRO){
431                 sprintf(p, "Pro-active");
432                 p += strlen("Pro-active");
433         }
434         if (parity & PGM_OPT_PARITY_PRM_OND){
435                 if (p != msg)
436                         str = ",On-demand";
437                 else
438                         str = "On-demand";
439                 sprintf(p, str);
440                 p += strlen(str);
441         }
442         if (p == msg) {
443                 sprintf(p, "0x%x", parity);
444         }
445         return(msg);
446 }
447
448 static const value_string opt_vals[] = {
449         { PGM_OPT_LENGTH,      "Length" },
450         { PGM_OPT_END,         "End" },
451         { PGM_OPT_FRAGMENT,    "Fragment" },
452         { PGM_OPT_NAK_LIST,    "NakList" },
453         { PGM_OPT_JOIN,        "Join" },
454         { PGM_OPT_REDIRECT,    "ReDirect" },
455         { PGM_OPT_SYN,         "Syn" },
456         { PGM_OPT_FIN,         "Fin" },
457         { PGM_OPT_RST,         "Rst" },
458         { PGM_OPT_PARITY_PRM,  "ParityPrm" },
459         { PGM_OPT_PARITY_GRP,  "ParityGrp" },
460         { PGM_OPT_CURR_TGSIZE, "CurrTgsiz" },
461         { PGM_OPT_PGMCC_DATA,  "CcData" },
462         { PGM_OPT_PGMCC_FEEDBACK, "CcFeedBack" },
463         { 0,                   NULL }
464 };
465
466 static const value_string opx_vals[] = {
467         { PGM_OPX_IGNORE,  "Ignore" },
468         { PGM_OPX_INVAL,   "Inval" },
469         { PGM_OPX_DISCARD, "DisCard" },
470         { 0,               NULL }
471 };
472
473 static void
474 dissect_pgmopts(tvbuff_t *tvb, int offset, proto_tree *tree,
475     const char *pktname)
476 {
477         proto_item *tf;
478         proto_tree *opts_tree = NULL;
479         proto_tree *opt_tree = NULL;
480         pgm_opt_length_t opts;
481         pgm_opt_generic_t genopts;
482         int theend = 0, firsttime = 1;
483
484         tvb_memcpy(tvb, (guint8 *)&opts, offset, sizeof(opts));
485         opts.total_len = ntohs(opts.total_len);
486
487         tf = proto_tree_add_text(tree, tvb, offset, 
488                 opts.total_len, 
489                 "%s Options (Total Length %d)", pktname, opts.total_len);
490         opts_tree = proto_item_add_subtree(tf, ett_pgm_opts);
491         proto_tree_add_uint(opts_tree, hf_pgm_opt_type, tvb, 
492                 offset, 1, opts.type);
493         proto_tree_add_uint(opts_tree, hf_pgm_opt_len, tvb, 
494                 offset+1, 1, opts.len);
495         proto_tree_add_uint(opts_tree, hf_pgm_opt_tlen, tvb, 
496                 offset+2, 2, opts.total_len);
497
498         offset += 4;
499         for (opts.total_len -= 4; opts.total_len > 0;){
500                 tvb_memcpy(tvb, (guint8 *)&genopts, offset, sizeof(genopts));
501                 if (genopts.type & PGM_OPT_END)  {
502                         genopts.type &= ~PGM_OPT_END;
503                         theend = 1;
504                 }
505                 tf = proto_tree_add_text(opts_tree, tvb, offset, genopts.len,
506                         "Option: %s, Length: %u",
507                         val_to_str(genopts.type, opt_vals, "Unknown (0x%02x)"),
508                         genopts.len);
509                 if (genopts.len == 0)
510                         break;
511
512                 switch(genopts.type) {
513                 case PGM_OPT_JOIN:{
514                         pgm_opt_join_t optdata;
515
516                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
517                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_join);
518
519                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type, 
520                                 tvb, offset, 1, genopts.type);
521
522                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb, 
523                                 offset+1, 1, genopts.len);
524
525                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx, tvb, 
526                                 offset+2, 1, genopts.opx);
527
528                         proto_tree_add_uint(opt_tree, hf_pgm_opt_join_res, tvb, 
529                                 offset+3, 1, optdata.res);
530
531                         proto_tree_add_uint(opt_tree, hf_pgm_opt_join_minjoin, tvb, 
532                                 offset+4, 4, ntohl(optdata.opt_join_min));
533
534                         break;
535                 }
536                 case PGM_OPT_PARITY_PRM:{
537                         pgm_opt_parity_prm_t optdata;
538
539                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
540                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_parityprm);
541
542                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type, 
543                                 tvb, offset, 1, genopts.type);
544
545                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb, 
546                                 offset+1, 1, genopts.len);
547
548                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx, 
549                                 tvb, offset+2, 1, genopts.opx);
550
551                         proto_tree_add_uint_format(opt_tree, hf_pgm_opt_parity_prm_po, tvb, 
552                                 offset+3, 1, optdata.po, "Parity Parameters: %s (0x%x)",
553                                 paritystr(optdata.po), optdata.po);
554
555                         proto_tree_add_uint(opt_tree, hf_pgm_opt_parity_prm_prmtgsz,
556                                 tvb, offset+4, 4, ntohl(optdata.prm_tgsz));
557
558                         break;
559                 }
560                 case PGM_OPT_PARITY_GRP:{
561                         pgm_opt_parity_grp_t optdata;
562
563                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
564                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_paritygrp);
565
566                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type, 
567                                 tvb, offset, 1, genopts.type);
568
569                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb, 
570                                 offset+1, 1, genopts.len);
571
572                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx, 
573                                 tvb, offset+2, 1, genopts.opx);
574
575                         proto_tree_add_uint(opt_tree, hf_pgm_opt_parity_grp_res, tvb, 
576                                 offset+3, 1, optdata.res);
577
578                         proto_tree_add_uint(opt_tree, hf_pgm_opt_parity_grp_prmgrp,
579                                 tvb, offset+4, 4, ntohl(optdata.prm_grp));
580
581                         break;
582                 }
583                 case PGM_OPT_NAK_LIST:{
584                         pgm_opt_nak_list_t optdata;
585                         nlong_t naklist[PGM_MAX_NAK_LIST_SZ+1];
586                         char nakbuf[8192], *ptr;
587                         int i, j, naks, soffset = 0;
588
589                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
590                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_naklist);
591
592                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type, tvb, 
593                                 offset, 1, genopts.type);
594
595                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb, 
596                                 offset+1, 1, genopts.len);
597
598                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx, 
599                                 tvb, offset+2, 1, genopts.opx);
600
601                         proto_tree_add_uint(opt_tree, hf_pgm_opt_nak_res, tvb, 
602                                 offset+3, 1, optdata.res);
603
604                         optdata.len -= sizeof(pgm_opt_nak_list_t);
605                         tvb_memcpy(tvb, (guint8 *)naklist, offset+4, optdata.len);
606                         naks = (optdata.len/sizeof(nlong_t));
607                         ptr = nakbuf;
608                         j = 0;
609                         /*
610                          * Print out 8 per line 
611                          */
612                         for (i=0; i < naks; i++) {
613                                 sprintf(nakbuf+soffset, "0x%lx ",
614                                     (unsigned long)ntohl(naklist[i]));
615                                 soffset = strlen(nakbuf);
616                                 if ((++j % 8) == 0) {
617                                         if (firsttime) {
618                                                 proto_tree_add_bytes_format(opt_tree, 
619                                                         hf_pgm_opt_nak_list, tvb, offset+4, optdata.len,
620                                                         nakbuf, "List(%d): %s", naks, nakbuf);
621                                                         soffset = 0;
622                                         } else {
623                                                 proto_tree_add_bytes_format(opt_tree, 
624                                                         hf_pgm_opt_nak_list, tvb, offset+4, optdata.len, 
625                                                         nakbuf, "List: %s", nakbuf);
626                                                         soffset = 0;
627                                         }
628                                         firsttime = 0;
629                                 }
630                         }
631                         if (soffset) {
632                                 if (firsttime) {
633                                         proto_tree_add_bytes_format(opt_tree, 
634                                                 hf_pgm_opt_nak_list, tvb, offset+4, optdata.len,
635                                                 nakbuf, "List(%d): %s", naks, nakbuf);
636                                                 soffset = 0;
637                                 } else {
638                                         proto_tree_add_bytes_format(opt_tree, 
639                                                 hf_pgm_opt_nak_list, tvb, offset+4, optdata.len, 
640                                                 nakbuf, "List: %s", nakbuf);
641                                                 soffset = 0;
642                                 }
643                         }
644                         break;
645                 }
646                 case PGM_OPT_PGMCC_DATA:{
647                         pgm_opt_pgmcc_data_t optdata;
648
649                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
650                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_ccdata);
651
652                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type, 
653                                 tvb, offset, 1, genopts.type);
654
655                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb, 
656                                 offset+1, 1, genopts.len);
657
658                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx, 
659                                 tvb, offset+2, 1, genopts.opx);
660
661                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccdata_res, tvb, 
662                                 offset+3, 1, optdata.res);
663
664                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccdata_tsp, tvb, 
665                                 offset+4, 4, optdata.tsp);
666
667                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccdata_afi, tvb, 
668                                 offset+8, 2, ntohs(optdata.acker_afi));
669
670                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccdata_res2, tvb, 
671                                 offset+10, 2, ntohs(optdata.res2));
672
673                         switch (ntohs(optdata.acker_afi)) {
674
675                         case AFNUM_INET:
676                                 proto_tree_add_ipv4(opt_tree, hf_pgm_opt_ccdata_acker,
677                                     tvb, offset+12, 4, optdata.acker);
678                                 break;
679
680                         default:
681                                 /*
682                                  * XXX - the header is variable-length,
683                                  * as the length of the NLA depends on
684                                  * its AFI.
685                                  *
686                                  * However, our structure for it is
687                                  * fixed-length, and assumes it's a 4-byte
688                                  * IPv4 address.
689                                  */
690                                 break;
691                         }
692
693                         break;
694                 }
695                 case PGM_OPT_PGMCC_FEEDBACK:{
696                         pgm_opt_pgmcc_feedback_t optdata;
697
698                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
699                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_ccdata);
700
701                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type, 
702                                 tvb, offset, 1, genopts.type);
703
704                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb, 
705                                 offset+1, 1, genopts.len);
706
707                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx, 
708                                 tvb, offset+2, 1, genopts.opx);
709
710                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccfeedbk_res, tvb, 
711                                 offset+3, 1, optdata.res);
712
713                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccfeedbk_tsp, tvb, 
714                                 offset+4, 4, optdata.tsp);
715
716                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccfeedbk_afi, tvb, 
717                                 offset+8, 2, ntohs(optdata.acker_afi));
718
719                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccfeedbk_lossrate, tvb, 
720                                 offset+10, 2, ntohs(optdata.loss_rate));
721
722                         switch (ntohs(optdata.acker_afi)) {
723
724                         case AFNUM_INET:
725                                 proto_tree_add_ipv4(opt_tree, hf_pgm_opt_ccfeedbk_acker,
726                                     tvb, offset+12, 4, optdata.acker);
727                                 break;
728
729                         default:
730                                 /*
731                                  * XXX - the header is variable-length,
732                                  * as the length of the NLA depends on
733                                  * its AFI.
734                                  *
735                                  * However, our structure for it is
736                                  * fixed-length, and assumes it's a 4-byte
737                                  * IPv4 address.
738                                  */
739                                 break;
740                         }
741
742                         break;
743                 }
744                 }
745                 offset += genopts.len;
746                 opts.total_len -= genopts.len;
747
748         }
749         return ;
750 }
751
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_ACK_PCKT,   "ACK" },
760         { 0,              NULL }
761 };
762 /* Determine if there is a sub-dissector and call it.  This has been */
763 /* separated into a stand alone routine to other protocol dissectors */
764 /* can call to it, ie. socks    */
765
766 void
767 decode_pgm_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,
768         proto_tree *tree, pgm_type *pgmhdr)
769 {
770   tvbuff_t *next_tvb;
771   int found = 0;
772
773   next_tvb = tvb_new_subset(tvb, offset, -1, -1);
774
775   /* do lookup with the subdissector table */
776   found = dissector_try_port(subdissector_table, pgmhdr->sport, 
777                         next_tvb, pinfo, tree);
778   if (found)
779         return;
780
781   found = dissector_try_port(subdissector_table, pgmhdr->dport, 
782                         next_tvb, pinfo, tree);
783   if (found)
784         return;
785
786   /* do lookup with the heuristic subdissector table */
787   if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree))
788     return;
789
790   /* Oh, well, we don't know this; dissect it as data. */
791   call_dissector(data_handle,next_tvb, pinfo, tree);
792
793 }
794 int 
795 total_size(tvbuff_t *tvb, pgm_type *hdr)
796 {
797         int bytes = sizeof(pgm_type);
798         pgm_opt_length_t opts;
799
800         switch(hdr->type) {
801         case PGM_SPM_PCKT:
802                 bytes += sizeof(pgm_spm_t);
803                 break;
804
805         case PGM_RDATA_PCKT:
806         case PGM_ODATA_PCKT:
807                 bytes += sizeof(pgm_data_t);
808                 break;
809
810         case PGM_NAK_PCKT:
811         case PGM_NNAK_PCKT:
812         case PGM_NCF_PCKT:
813                 bytes += sizeof(pgm_nak_t);
814                 break;
815         case PGM_ACK_PCKT:
816                 bytes += sizeof(pgm_ack_t);
817                 break;
818         }
819         if ((hdr->opts & PGM_OPT)) {
820                 tvb_memcpy(tvb, (guint8 *)&opts, bytes, sizeof(opts));
821                 bytes += ntohs(opts.total_len);
822         }
823         return(bytes);
824 }
825 /*
826  * dissect_pgm - The dissector for Pragmatic General Multicast
827  */
828 static void
829 dissect_pgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
830 {
831         proto_tree *pgm_tree = NULL;
832         proto_tree *opt_tree = NULL;
833         proto_tree *type_tree = NULL;
834         proto_item *tf;
835         pgm_type pgmhdr;
836         pgm_spm_t spm;
837         pgm_data_t data;
838         pgm_nak_t nak;
839         pgm_ack_t ack;
840         int offset = 0;
841         guint hlen, plen;
842         proto_item *ti;
843         const char *pktname;
844         char *gsi;
845         int isdata = 0;
846
847         if (check_col(pinfo->cinfo, COL_PROTOCOL))
848                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PGM");
849
850         /* Clear out the Info column. */
851         if (check_col(pinfo->cinfo, COL_INFO))
852                 col_clear(pinfo->cinfo, COL_INFO);
853
854         tvb_memcpy(tvb, (guint8 *)&pgmhdr, offset, sizeof(pgm_type));
855         hlen = sizeof(pgm_type);
856         pgmhdr.sport = ntohs(pgmhdr.sport);
857         pgmhdr.dport = ntohs(pgmhdr.dport);
858         pgmhdr.tsdulen = ntohs(pgmhdr.tsdulen);
859
860         pktname = val_to_str(pgmhdr.type, type_vals, "Unknown (0x%02x)");
861
862         gsi = bytes_to_str(pgmhdr.gsi, 6);
863         switch(pgmhdr.type) {
864         case PGM_SPM_PCKT:
865                 plen = sizeof(pgm_spm_t);
866                 tvb_memcpy(tvb, (guint8 *)&spm, sizeof(pgm_type), plen);
867                 spm_ntoh(&spm);
868                 if (check_col(pinfo->cinfo, COL_INFO)) {
869                         col_add_fstr(pinfo->cinfo, COL_INFO,
870                                 "%-5s sqn 0x%x gsi %s", pktname, spm.sqn, gsi);
871                 }
872                 break;
873
874         case PGM_RDATA_PCKT:
875         case PGM_ODATA_PCKT:
876                 plen = sizeof(pgm_data_t);
877                 tvb_memcpy(tvb, (guint8 *)&data, sizeof(pgm_type), plen);
878                 data_ntoh(&data);
879                 if (check_col(pinfo->cinfo, COL_INFO)) {
880                         col_add_fstr(pinfo->cinfo, COL_INFO,
881                             "%-5s sqn 0x%x gsi %s tsdulen %d", pktname, data.sqn, gsi,
882                             pgmhdr.tsdulen);
883                 }
884                 isdata = 1;
885                 break;
886
887         case PGM_NAK_PCKT:
888         case PGM_NNAK_PCKT:
889         case PGM_NCF_PCKT:
890                 plen = sizeof(pgm_nak_t);
891                 tvb_memcpy(tvb, (guint8 *)&nak, sizeof(pgm_type), plen);
892                 nak_ntoh(&nak);
893                 if (check_col(pinfo->cinfo, COL_INFO)) {
894                         col_add_fstr(pinfo->cinfo, COL_INFO,
895                                 "%-5s sqn 0x%x gsi %s", pktname, nak.sqn, gsi);
896                 }
897                 break;
898         case PGM_ACK_PCKT:
899                 plen = sizeof(pgm_ack_t);
900                 tvb_memcpy(tvb, (guint8 *)&ack, sizeof(pgm_type), plen);
901                 ack_ntoh(&ack);
902                 if (check_col(pinfo->cinfo, COL_INFO)) {
903                         col_add_fstr(pinfo->cinfo, COL_INFO,
904                             "%-5s sqn 0x%x gsi %s", pktname, ack.rx_max_sqn, gsi);
905                 }
906                 break;
907
908         default:
909                 return;
910         }
911
912         if (tree) {
913                 ti = proto_tree_add_protocol_format(tree, proto_pgm, 
914                         tvb, offset, total_size(tvb, &pgmhdr),
915                         "Pragmatic General Multicast: Type %s"
916                             " SrcPort %u, DstPort %u, GSI %s", pktname,
917                         pgmhdr.sport, pgmhdr.dport,
918                         bytes_to_str(pgmhdr.gsi, 6));
919
920                 pgm_tree = proto_item_add_subtree(ti, ett_pgm);
921                 proto_tree_add_uint(pgm_tree, hf_pgm_main_sport, tvb, offset, 2,
922                         pgmhdr.sport);
923                 proto_tree_add_uint(pgm_tree, hf_pgm_main_dport, tvb, offset+2, 
924                         2, pgmhdr.dport);
925                 proto_tree_add_uint(pgm_tree, hf_pgm_main_type, tvb, 
926                         offset+4, 1, pgmhdr.type);
927
928                 tf = proto_tree_add_uint_format(pgm_tree, hf_pgm_main_opts, tvb, 
929                         offset+5, 1, pgmhdr.opts, "Options: %s (0x%x)", 
930                         optsstr(pgmhdr.opts), pgmhdr.opts);
931                 opt_tree = proto_item_add_subtree(tf, ett_pgm_optbits);
932
933                 proto_tree_add_boolean(opt_tree, hf_pgm_main_opts_opt, tvb, 
934                         offset+5, 1, (pgmhdr.opts & PGM_OPT));
935                 proto_tree_add_boolean(opt_tree, hf_pgm_main_opts_netsig, tvb, 
936                         offset+5, 1, (pgmhdr.opts & PGM_OPT_NETSIG));
937                 proto_tree_add_boolean(opt_tree, hf_pgm_main_opts_varlen, tvb, 
938                         offset+5, 1, (pgmhdr.opts & PGM_OPT_VAR_PKTLEN));
939                 proto_tree_add_boolean(opt_tree, hf_pgm_main_opts_parity, tvb, 
940                         offset+5, 1, (pgmhdr.opts & PGM_OPT_PARITY));
941
942                 proto_tree_add_uint(pgm_tree, hf_pgm_main_cksum, tvb, offset+6, 
943                         2, pgmhdr.cksum);
944                 proto_tree_add_bytes(pgm_tree, hf_pgm_main_gsi, tvb, offset+8, 
945                         6, pgmhdr.gsi);
946                 proto_tree_add_uint(pgm_tree, hf_pgm_main_tsdulen, tvb, 
947                         offset+14, 2, pgmhdr.tsdulen);
948
949                 offset = sizeof(pgm_type);
950                 tf = proto_tree_add_text(pgm_tree, tvb, offset, plen, "%s Packet",
951                         pktname);
952                 switch(pgmhdr.type) {
953                 case PGM_SPM_PCKT:
954                         type_tree = proto_item_add_subtree(tf, ett_pgm_spm);
955
956                         proto_tree_add_uint(type_tree, hf_pgm_spm_sqn, tvb, 
957                                 offset, 4, spm.sqn);
958                         proto_tree_add_uint(type_tree, hf_pgm_spm_trail, tvb, 
959                                 offset+4, 4, spm.trail);
960                         proto_tree_add_uint(type_tree, hf_pgm_spm_lead, tvb, 
961                                 offset+8, 4, spm.lead);
962                         proto_tree_add_uint(type_tree, hf_pgm_spm_pathafi, tvb, 
963                                 offset+10, 2, spm.path_afi);
964                         proto_tree_add_uint(type_tree, hf_pgm_spm_res, tvb, 
965                                 offset+12, 2, spm.res);
966                         switch (spm.path_afi) {
967
968                         case AFNUM_INET:
969                                 proto_tree_add_ipv4(type_tree, hf_pgm_spm_path,
970                                     tvb, offset+14, 4, spm.path);
971                                 break;
972
973                         default:
974                                 /*
975                                  * XXX - the header is variable-length,
976                                  * as the length of the NLA depends on
977                                  * its AFI.
978                                  *
979                                  * However, our structure for it is
980                                  * fixed-length, and assumes it's a 4-byte
981                                  * IPv4 address.
982                                  */
983                                 return;
984                         }
985
986                         if ((pgmhdr.opts & PGM_OPT) == FALSE)
987                                 break;
988                         offset += plen;
989
990                         dissect_pgmopts(tvb, offset, type_tree, pktname);
991
992                         break;
993
994                 case PGM_RDATA_PCKT:
995                 case PGM_ODATA_PCKT: {
996                         type_tree = proto_item_add_subtree(tf, ett_pgm_data);
997
998                         proto_tree_add_uint(type_tree, hf_pgm_spm_sqn, tvb, 
999                                 offset, 4, data.sqn);
1000                         proto_tree_add_uint(type_tree, hf_pgm_spm_trail, tvb, 
1001                                 offset+4, 4, data.trail);
1002
1003                         if ((pgmhdr.opts & PGM_OPT) == FALSE)
1004                                 break;
1005                         offset += plen;
1006
1007                         dissect_pgmopts(tvb, offset, type_tree, pktname);
1008
1009                         break;
1010                 }
1011
1012
1013                 case PGM_NAK_PCKT:
1014                 case PGM_NNAK_PCKT:
1015                 case PGM_NCF_PCKT:
1016                         type_tree = proto_item_add_subtree(tf, ett_pgm_nak);
1017
1018                         proto_tree_add_uint(type_tree, hf_pgm_nak_sqn, tvb, 
1019                                 offset, 4, nak.sqn);
1020                         proto_tree_add_uint(type_tree, hf_pgm_nak_srcafi, tvb, 
1021                                 offset+4, 2, nak.src_afi);
1022                         proto_tree_add_uint(type_tree, hf_pgm_nak_srcres, tvb, 
1023                                 offset+6, 2, nak.src_res);
1024
1025                         switch (nak.src_afi) {
1026
1027                         case AFNUM_INET:
1028                                 proto_tree_add_ipv4(type_tree, hf_pgm_nak_src,
1029                                     tvb, offset+8, 4, nak.src);
1030                                 break;
1031
1032                         default:
1033                                 /*
1034                                  * XXX - the header is variable-length,
1035                                  * as the length of the NLA depends on
1036                                  * its AFI.
1037                                  *
1038                                  * However, our structure for it is
1039                                  * fixed-length, and assumes it's a 4-byte
1040                                  * IPv4 address.
1041                                  */
1042                                 break;
1043                         }
1044
1045                         proto_tree_add_uint(type_tree, hf_pgm_nak_grpafi, tvb, 
1046                                 offset+12, 2, nak.grp_afi);
1047                         proto_tree_add_uint(type_tree, hf_pgm_nak_grpres, tvb, 
1048                                 offset+14, 2, nak.grp_res);
1049
1050                         switch (nak.grp_afi) {
1051
1052                         case AFNUM_INET:
1053                                 proto_tree_add_ipv4(type_tree, hf_pgm_nak_grp,
1054                                     tvb, offset+16, 4, nak.grp);
1055                                 break;
1056
1057                         default:
1058                                 /*
1059                                  * XXX - the header is variable-length,
1060                                  * as the length of the NLA depends on
1061                                  * its AFI.
1062                                  *
1063                                  * However, our structure for it is
1064                                  * fixed-length, and assumes it's a 4-byte
1065                                  * IPv4 address.
1066                                  */
1067                                 return;
1068                         }
1069
1070                         if ((pgmhdr.opts & PGM_OPT) == FALSE)
1071                                 break;
1072                         offset += plen;
1073
1074                         dissect_pgmopts(tvb, offset, type_tree, pktname);
1075
1076                         break;
1077                 case PGM_ACK_PCKT:
1078                         type_tree = proto_item_add_subtree(tf, ett_pgm_ack);
1079
1080                         proto_tree_add_uint(type_tree, hf_pgm_ack_sqn, tvb, 
1081                                 offset, 4, ack.rx_max_sqn);
1082                         proto_tree_add_uint(type_tree, hf_pgm_ack_bitmap, tvb, 
1083                                 offset+4, 4, ack.bitmap);
1084
1085                         if ((pgmhdr.opts & PGM_OPT) == FALSE)
1086                                 break;
1087                         offset += plen;
1088
1089                         dissect_pgmopts(tvb, offset, type_tree, pktname);
1090
1091                         break;
1092                 }
1093
1094         }
1095         if (isdata) {
1096                 /*
1097                  * Now see if there are any sub-dissectors, if so call them
1098                  */
1099                 offset = total_size(tvb, &pgmhdr);
1100                 decode_pgm_ports(tvb, offset, pinfo, tree, &pgmhdr);
1101         }
1102         pktname = NULL;
1103 }
1104 static const true_false_string opts_present = {      
1105         "Present",
1106         "Not Present" 
1107 };
1108
1109 /* Register all the bits needed with the filtering engine */
1110 void 
1111 proto_register_pgm(void)
1112 {
1113   static hf_register_info hf[] = {
1114     { &hf_pgm_main_sport,
1115       { "Source Port", "pgm.hdr.sport", FT_UINT16, BASE_DEC,
1116           NULL, 0x0, "", HFILL }},
1117     { &hf_pgm_main_dport,
1118       { "Destination Port", "pgm.hdr.dport", FT_UINT16, BASE_DEC,
1119           NULL, 0x0, "", HFILL }},
1120     { &hf_pgm_main_type,
1121       { "Type", "pgm.hdr.type", FT_UINT8, BASE_HEX,
1122           VALS(type_vals), 0x0, "", HFILL }},
1123     { &hf_pgm_main_opts,
1124       { "Options", "pgm.hdr.opts", FT_UINT8, BASE_HEX,
1125           NULL, 0x0, "", HFILL }},
1126     { &hf_pgm_main_opts_opt,
1127       { "Options", "pgm.hdr.opts.opt", FT_BOOLEAN, BASE_NONE,
1128           TFS(&opts_present), PGM_OPT, "", HFILL }},
1129     { &hf_pgm_main_opts_netsig,
1130       { "Network Significant Options", "pgm.hdr.opts.netsig", 
1131           FT_BOOLEAN, BASE_NONE,
1132           TFS(&opts_present), PGM_OPT_NETSIG, "", HFILL }},
1133     { &hf_pgm_main_opts_varlen,
1134       { "Variable length Parity Packet Option", "pgm.hdr.opts.varlen", 
1135           FT_BOOLEAN, BASE_NONE,
1136           TFS(&opts_present), PGM_OPT_VAR_PKTLEN, "", HFILL }},
1137     { &hf_pgm_main_opts_parity,
1138       { "Parity", "pgm.hdr.opts.parity", FT_BOOLEAN, BASE_NONE,
1139           TFS(&opts_present), PGM_OPT_PARITY, "", HFILL }},
1140     { &hf_pgm_main_cksum,
1141       { "Checksum", "pgm.hdr.cksum", FT_UINT16, BASE_HEX,
1142         NULL, 0x0, "", HFILL }},
1143     { &hf_pgm_main_gsi,
1144       { "Global Source Identifier", "pgm.hdr.gsi", FT_BYTES, BASE_HEX, 
1145           NULL, 0x0, "", HFILL }},
1146     { &hf_pgm_main_tsdulen,
1147       { "Transport Service Data Unit Length", "pgm.hdr.tsdulen", FT_UINT16, 
1148           BASE_DEC, NULL, 0x0, "", HFILL }},
1149     { &hf_pgm_spm_sqn,
1150       { "Sequence number", "pgm.spm.sqn", FT_UINT32, BASE_HEX,
1151           NULL, 0x0, "", HFILL }},
1152     { &hf_pgm_spm_trail,
1153       { "Trailing Edge Sequence Number", "pgm.spm.trail", FT_UINT32, BASE_HEX, 
1154           NULL, 0x0, "", HFILL }},
1155     { &hf_pgm_spm_lead,
1156       { "Leading Edge Sequence Number", "pgm.spm.lead", FT_UINT32, BASE_HEX, 
1157           NULL, 0x0, "", HFILL }},
1158     { &hf_pgm_spm_pathafi,
1159       { "Path NLA AFI", "pgm.spm.pathafi", FT_UINT16, BASE_DEC,
1160           VALS(afn_vals), 0x0, "", HFILL }},
1161     { &hf_pgm_spm_res,
1162       { "Reserved", "pgm.spm.res", FT_UINT16, BASE_HEX,
1163           NULL, 0x0, "", HFILL }},
1164     { &hf_pgm_spm_path,
1165       { "Path NLA", "pgm.spm.path", FT_IPv4, BASE_NONE,
1166           NULL, 0x0, "", HFILL }},
1167     { &hf_pgm_data_sqn,
1168       { "Data Packet Sequence Number", "pgm.data.sqn", FT_UINT32, BASE_HEX, 
1169           NULL, 0x0, "", HFILL }},
1170     { &hf_pgm_data_trail,
1171       { "Trailing Edge Sequence Number", "pgm.data.trail", FT_UINT32, BASE_HEX, 
1172           NULL, 0x0, "", HFILL }},
1173     { &hf_pgm_nak_sqn,
1174       { "Requested Sequence Number", "pgm.nak.sqn", FT_UINT32, BASE_HEX, 
1175           NULL, 0x0, "", HFILL }},
1176     { &hf_pgm_nak_srcafi,
1177       { "Source NLA AFI", "pgm.nak.srcafi", FT_UINT16, BASE_DEC,
1178           VALS(afn_vals), 0x0, "", HFILL }},
1179     { &hf_pgm_nak_srcres,
1180       { "Reserved", "pgm.nak.srcres", FT_UINT16, BASE_HEX,
1181           NULL, 0x0, "", HFILL }},
1182     { &hf_pgm_nak_src,
1183       { "Source NLA", "pgm.nak.src", FT_IPv4, BASE_NONE,
1184           NULL, 0x0, "", HFILL }},
1185     { &hf_pgm_nak_grpafi,
1186       { "Multicast Group AFI", "pgm.nak.grpafi", FT_UINT16, BASE_DEC,
1187           VALS(afn_vals), 0x0, "", HFILL }},
1188     { &hf_pgm_nak_grpres,
1189       { "Reserved", "pgm.nak.grpres", FT_UINT16, BASE_HEX,
1190           NULL, 0x0, "", HFILL }},
1191     { &hf_pgm_nak_grp,
1192       { "Multicast Group NLA", "pgm.nak.grp", FT_IPv4, BASE_NONE,
1193           NULL, 0x0, "", HFILL }},
1194     { &hf_pgm_ack_sqn,
1195       { "Maximum Received Sequence Number", "pgm.ack.maxsqn", FT_UINT32, 
1196           BASE_HEX, NULL, 0x0, "", HFILL }},
1197     { &hf_pgm_ack_bitmap,
1198       { "Packet Bitmap", "pgm.ack.bitmap", FT_UINT32, BASE_HEX, 
1199           NULL, 0x0, "", HFILL }},
1200     { &hf_pgm_opt_type,
1201       { "Type", "pgm.opts.type", FT_UINT8, BASE_HEX,
1202           VALS(opt_vals), 0x0, "", HFILL }},
1203     { &hf_pgm_opt_len,
1204       { "Length", "pgm.opts.len", FT_UINT8, BASE_DEC,
1205           NULL, 0x0, "", HFILL }},
1206     { &hf_pgm_opt_tlen,
1207       { "Total Length", "pgm.opts.tlen", FT_UINT16, BASE_DEC,
1208           NULL, 0x0, "", HFILL }},
1209     { &hf_pgm_genopt_type,
1210       { "Type", "pgm.genopts.type", FT_UINT8, BASE_HEX,
1211           VALS(opt_vals), 0x0, "", HFILL }},
1212     { &hf_pgm_genopt_len,
1213       { "Length", "pgm.genopts.len", FT_UINT8, BASE_DEC,
1214           NULL, 0x0, "", HFILL }},
1215     { &hf_pgm_genopt_opx,
1216       { "Option Extensibility Bits", "pgm.genopts.opx", FT_UINT8, BASE_HEX,
1217           VALS(opx_vals), 0x0, "", HFILL }},
1218     { &hf_pgm_opt_parity_prm_po,
1219       { "Parity Parameters", "pgm.opts.parity_prm.op", FT_UINT8, BASE_HEX,
1220           NULL, 0x0, "", HFILL }},
1221     { &hf_pgm_opt_parity_prm_prmtgsz,
1222       { "Transmission Group Size", "pgm.opts.parity_prm.prm_grp",
1223           FT_UINT32, BASE_HEX,
1224           NULL, 0x0, "", HFILL }},
1225     { &hf_pgm_opt_join_res,
1226       { "Reserved", "pgm.opts.join.res", FT_UINT8, BASE_HEX,
1227           NULL, 0x0, "", HFILL }},
1228     { &hf_pgm_opt_join_minjoin,
1229       { "Minimum Sequence Number", "pgm.opts.join.min_join",
1230           FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
1231     { &hf_pgm_opt_parity_grp_res,
1232       { "Reserved", "pgm.opts.parity_prm.op", FT_UINT8, BASE_HEX,
1233           NULL, 0x0, "", HFILL }},
1234     { &hf_pgm_opt_parity_grp_prmgrp,
1235       { "Transmission Group Size", "pgm.opts.parity_prm.prm_grp",
1236           FT_UINT32, BASE_HEX,
1237           NULL, 0x0, "", HFILL }},
1238     { &hf_pgm_opt_nak_res,
1239       { "Reserved", "pgm.opts.nak.op", FT_UINT8, BASE_HEX,
1240           NULL, 0x0, "", HFILL }},
1241     { &hf_pgm_opt_nak_list,
1242       { "List", "pgm.opts.nak.list", FT_BYTES, BASE_NONE,
1243           NULL, 0x0, "", HFILL }},
1244     { &hf_pgm_opt_ccdata_res,
1245       { "Reserved", "pgm.opts.ccdata.res", FT_UINT8, BASE_DEC,
1246           NULL, 0x0, "", HFILL }},
1247     { &hf_pgm_opt_ccdata_tsp,
1248       { "Time Stamp", "pgm.opts.ccdata.tstamp", FT_UINT16, BASE_HEX,
1249           NULL, 0x0, "", HFILL }},
1250     { &hf_pgm_opt_ccdata_afi,
1251       { "Acker AFI", "pgm.opts.ccdata.afi", FT_UINT16, BASE_DEC,
1252           VALS(afn_vals), 0x0, "", HFILL }},
1253     { &hf_pgm_opt_ccdata_res2,
1254       { "Reserved", "pgm.opts.ccdata.res2", FT_UINT16, BASE_DEC,
1255           NULL, 0x0, "", HFILL }},
1256     { &hf_pgm_opt_ccdata_acker,
1257       { "Acker", "pgm.opts.ccdata.acker", FT_IPv4, BASE_NONE,
1258           NULL, 0x0, "", HFILL }},
1259     { &hf_pgm_opt_ccfeedbk_res,
1260       { "Reserved", "pgm.opts.ccdata.res", FT_UINT8, BASE_DEC,
1261           NULL, 0x0, "", HFILL }},
1262     { &hf_pgm_opt_ccfeedbk_tsp,
1263       { "Time Stamp", "pgm.opts.ccdata.tstamp", FT_UINT16, BASE_HEX,
1264           NULL, 0x0, "", HFILL }},
1265     { &hf_pgm_opt_ccfeedbk_afi,
1266       { "Acker AFI", "pgm.opts.ccdata.afi", FT_UINT16, BASE_DEC,
1267           VALS(afn_vals), 0x0, "", HFILL }},
1268     { &hf_pgm_opt_ccfeedbk_lossrate,
1269       { "Loss Rate", "pgm.opts.ccdata.lossrate", FT_UINT16, BASE_HEX,
1270           NULL, 0x0, "", HFILL }},
1271     { &hf_pgm_opt_ccfeedbk_acker,
1272       { "Acker", "pgm.opts.ccdata.acker", FT_IPv4, BASE_NONE,
1273           NULL, 0x0, "", HFILL }},
1274   };
1275   static gint *ett[] = {
1276     &ett_pgm,
1277         &ett_pgm_optbits,
1278         &ett_pgm_spm,
1279         &ett_pgm_data,
1280         &ett_pgm_nak,
1281         &ett_pgm_ack,
1282         &ett_pgm_opts,
1283         &ett_pgm_opts_join,
1284         &ett_pgm_opts_parityprm,
1285         &ett_pgm_opts_paritygrp,
1286         &ett_pgm_opts_naklist,
1287         &ett_pgm_opts_ccdata,
1288   };
1289   module_t *pgm_module;
1290
1291   proto_pgm = proto_register_protocol("Pragmatic General Multicast",
1292                                        "PGM", "pgm");
1293
1294   proto_register_field_array(proto_pgm, hf, array_length(hf));
1295   proto_register_subtree_array(ett, array_length(ett));
1296
1297         /* subdissector code */
1298   subdissector_table = register_dissector_table("pgm.port",
1299                 "PGM port", FT_UINT16, BASE_DEC);
1300   register_heur_dissector_list("pgm", &heur_subdissector_list);
1301
1302   /*
1303    * Register configuration preferences for UDP encapsulation
1304    * (Note: Initially the ports are set to zero so the 
1305    *        dissecting of PGM encapsulated in UPD packets
1306    *        is off by default)
1307    */
1308    pgm_module = prefs_register_protocol(proto_pgm, proto_rereg_pgm);
1309
1310    prefs_register_uint_preference(pgm_module, "udp.encap_ucast_port",
1311                 "PGM Encap Unicast Port (standard is 3055)", 
1312                 "PGM Encap is PGM packets encapsulated in UDP packets"
1313                 " (Note: This option is off, i.e. port is 0, by default)", 
1314                 10, &udp_encap_ucast_port);
1315    old_encap_ucast_port = udp_encap_ucast_port;
1316
1317    prefs_register_uint_preference(pgm_module, "udp.encap_mcast_port",
1318                 "PGM Encap Multicast Port (standard is 3056)", 
1319                 "PGM Encap is PGM packets encapsulated in UDP packets"
1320                 " (Note: This option is off, i.e. port is 0, by default)", 
1321                 10, &udp_encap_mcast_port);
1322
1323    old_encap_mcast_port = udp_encap_mcast_port;
1324 }
1325
1326 static dissector_handle_t pgm_handle;
1327
1328 /* The registration hand-off routine */
1329 void
1330 proto_reg_handoff_pgm(void)
1331 {
1332   pgm_handle = create_dissector_handle(dissect_pgm, proto_pgm);
1333
1334   /*
1335    * Set up PGM Encap dissecting, which is off by default
1336    */
1337   dissector_add("udp.port", udp_encap_ucast_port, pgm_handle);
1338   dissector_add("udp.port", udp_encap_mcast_port, pgm_handle);
1339
1340   dissector_add("ip.proto", IP_PROTO_PGM, pgm_handle);
1341   
1342   data_handle = find_dissector("data");
1343 }
1344
1345 static void
1346 proto_rereg_pgm(void)
1347 {
1348         /*
1349          * Remove the old ones
1350          */
1351         dissector_delete("udp.port", old_encap_ucast_port, pgm_handle);
1352         dissector_delete("udp.port", old_encap_mcast_port, pgm_handle);
1353
1354         /*
1355          * Set the new ones
1356          */
1357         dissector_add("udp.port", udp_encap_ucast_port, pgm_handle);
1358         dissector_add("udp.port", udp_encap_mcast_port, pgm_handle);
1359 }