The function pointer in a "per_choice_t" or a "per_sequence_t" is to a
[obnox/wireshark/wip.git] / packet-pgm.c
1 /* packet-pgm.c
2  * Routines for PGM packet disassembly, RFC 3208
3  *
4  * $Id: packet-pgm.c,v 1.24 2004/03/09 20:23:20 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 #include <stdio.h>
32 #include <stdlib.h>
33 #include <ctype.h>
34 #include <time.h>
35 #include <string.h>
36 #include <epan/packet.h>
37 #include "afn.h"
38 #include "ipproto.h"
39 #include "in_cksum.h"
40 #include <epan/resolv.h>
41 #include <epan/strutil.h>
42 #include "prefs.h"
43
44 #include <epan/proto.h>
45
46 /*
47  * Flag to control whether to check the PGM checksum.
48  */
49 static gboolean pgm_check_checksum = TRUE;
50
51 void proto_reg_handoff_pgm(void);
52 static void proto_rereg_pgm(void);
53
54 typedef guint8 nchar_t;
55 typedef guint16 nshort_t;
56 typedef guint32 nlong_t;
57
58 /* The PGM main header */
59 typedef struct {
60         nshort_t sport;            /* source port */
61         nshort_t dport;            /* destination port */
62         nchar_t type;              /* PGM type */
63         nchar_t opts;              /* options */
64         nshort_t cksum;            /* checksum */
65         nchar_t gsi[6];            /* Global Source ID */
66         nshort_t tsdulen;          /* TSDU length */
67 } pgm_type;
68 #define pgmhdr_ntoh(_p) \
69         (_p)->sport = g_ntohs((_p)->sport); \
70         (_p)->dport = g_ntohs((_p)->dport); \
71         (_p)->type = g_ntohs((_p)->type); \
72         (_p)->opts = g_ntohs((_p)->opts); \
73         (_p)->cksum = g_ntohs((_p)->cksum); \
74         (_p)->tsdulen = g_ntohs((_p)->tsdulen)
75
76 /* The PGM SPM header */
77 typedef struct {
78         nlong_t sqn;              /* SPM's sequence number */
79         nlong_t trail;            /* Trailing edge sequence number */
80         nlong_t lead;             /* Leading edge sequence number */
81         nshort_t path_afi;        /* NLA AFI */
82         nshort_t res;             /* reserved */
83         nlong_t path;             /* Path NLA */
84 } pgm_spm_t;
85 #define spm_ntoh(_p) \
86         (_p)->sqn = g_ntohl((_p)->sqn); \
87         (_p)->trail = g_ntohl((_p)->trail); \
88         (_p)->lead = g_ntohl((_p)->lead); \
89         (_p)->path_afi = g_ntohs((_p)->path_afi); \
90         (_p)->res = g_ntohs((_p)->res);
91
92 /* The PGM Data (ODATA/RDATA) header */
93 typedef struct {
94         nlong_t sqn;              /* Data Packet sequence number */
95         nlong_t trail;            /* Trailing edge sequence number */
96 } pgm_data_t;
97 #define data_ntoh(_p) \
98         (_p)->sqn = g_ntohl((_p)->sqn); \
99         (_p)->trail = g_ntohl((_p)->trail)
100
101 /* The PGM NAK (NAK/N-NAK/NCF) header */
102 typedef struct {
103         nlong_t sqn;             /* Requested sequence number */
104         nshort_t src_afi;        /* NLA AFI for source (IPv4 is set to 1) */
105         nshort_t src_res;        /* reserved */
106         nlong_t src;             /* Source NLA  */
107         nshort_t grp_afi;        /* Multicast group AFI (IPv4 is set to 1) */
108         nshort_t grp_res;        /* reserved */
109         nlong_t grp;             /* Multicast group NLA */
110 } pgm_nak_t;
111 #define nak_ntoh(_p) \
112         (_p)->sqn = g_ntohl((_p)->sqn); \
113         (_p)->src_afi = g_ntohs((_p)->src_afi); \
114         (_p)->src_res = g_ntohs((_p)->src_res); \
115         (_p)->grp_afi = g_ntohs((_p)->grp_afi); \
116         (_p)->grp_res = g_ntohs((_p)->grp_res)
117
118 /* The PGM POLL header */
119 typedef struct {
120         nlong_t sqn;             /* POLL sequence number */
121         nshort_t round;          /* POLL Round */
122         nshort_t subtype;        /* POLL subtype */
123         nshort_t path_afi;       /* NLA AFI for last hop router (IPv4 is set to 1) */
124         nshort_t res;            /* reserved */
125         nlong_t path;            /* Last hop router NLA  */
126         nlong_t backoff_ivl;     /* POLL backoff interval */
127         nlong_t rand_str;        /* POLL random string */
128         nlong_t matching_bmask;  /* POLL matching bitmask */
129 } pgm_poll_t;
130 #define poll_ntoh(_p) \
131         (_p)->sqn = g_ntohl((_p)->sqn); \
132         (_p)->round = g_ntohs((_p)->round); \
133         (_p)->subtype = g_ntohs((_p)->subtype); \
134         (_p)->path_afi = g_ntohs((_p)->path_afi); \
135         (_p)->res = g_ntohs((_p)->res); \
136         (_p)->backoff_ivl = g_ntohl((_p)->backoff_ivl); \
137         (_p)->rand_str = g_ntohl((_p)->rand_str); \
138         (_p)->matching_bmask = g_ntohl((_p)->matching_bmask)
139
140 /* The PGM POLR header */
141 typedef struct {
142         nlong_t sqn;             /* POLR sequence number */
143         nshort_t round;          /* POLR Round */
144         nshort_t res;            /* reserved */
145 } pgm_polr_t;
146 #define polr_ntoh(_p) \
147         (_p)->sqn = g_ntohl((_p)->sqn); \
148         (_p)->round = g_ntohs((_p)->round); \
149         (_p)->res = g_ntohs((_p)->res)
150
151 /* The PGM ACK header (PGMCC) */
152 typedef struct {
153         nlong_t rx_max_sqn;      /* RX_MAX sequence number */
154         nlong_t bitmap;          /* Received Packet Bitmap */
155 } pgm_ack_t;
156 #define ack_ntoh(_p) \
157         (_p)->rx_max_sqn = g_ntohl((_p)->rx_max_sqn); \
158         (_p)->bitmap = g_ntohl((_p)->bitmap)
159
160 /* constants for hdr types */
161 #if defined(PGM_SPEC_01_PCKTS)
162 /* old spec-01 types */
163 #define PGM_SPM_PCKT  0x00
164 #define PGM_ODATA_PCKT  0x10
165 #define PGM_RDATA_PCKT  0x11
166 #define PGM_NAK_PCKT  0x20
167 #define PGM_NNAK_PCKT  0x21
168 #define PGM_NCF_PCKT 0x30
169 #else
170 /* spec-02 types (as well as spec-04+) */
171 #define PGM_SPM_PCKT  0x00
172 #define PGM_ODATA_PCKT  0x04
173 #define PGM_RDATA_PCKT  0x05
174 #define PGM_NAK_PCKT  0x08
175 #define PGM_NNAK_PCKT  0x09
176 #define PGM_NCF_PCKT 0x0A
177 #define PGM_POLL_PCKT 0x01
178 #define PGM_POLR_PCKT 0x02
179 #define PGM_ACK_PCKT 0x0D
180 #endif /* PGM_SPEC_01_PCKTS */
181
182 /* port swapping on NAK and NNAKs or not (default is to swap) */
183 /* PGM_NO_PORT_SWAP */
184
185 /* option flags (main PGM header) */
186 #define PGM_OPT 0x01
187 #define PGM_OPT_NETSIG 0x02
188 #define PGM_OPT_VAR_PKTLEN 0x40
189 #define PGM_OPT_PARITY 0x80
190
191 /* option types */
192 #define PGM_OPT_LENGTH 0x00
193 #define PGM_OPT_END 0x80
194 #define PGM_OPT_FRAGMENT 0x01
195 #define PGM_OPT_NAK_LIST 0x02
196 #define PGM_OPT_JOIN 0x03
197 #define PGM_OPT_REDIRECT 0x07
198 #define PGM_OPT_SYN 0x0D
199 #define PGM_OPT_FIN 0x0E
200 #define PGM_OPT_RST 0x0F
201 #define PGM_OPT_PARITY_PRM 0x08
202 #define PGM_OPT_PARITY_GRP 0x09
203 #define PGM_OPT_CURR_TGSIZE 0x0A
204 #define PGM_OPT_PGMCC_DATA  0x12
205 #define PGM_OPT_PGMCC_FEEDBACK  0x13
206 #define PGM_OPT_NAK_BO_IVL 0x04
207 #define PGM_OPT_NAK_BO_RNG 0x05
208
209 /* POLL subtypes */
210 #define PGM_POLL_GENERAL 0x0
211 #define PGM_POLL_DLR 0x1
212
213 static const nchar_t PGM_OPT_INVALID = 0x7F;
214
215 /* OPX bit values */
216 #define PGM_OPX_IGNORE  0x00
217 #define PGM_OPX_INVAL   0x01
218 #define PGM_OPX_DISCARD 0x10
219
220 /* option formats */
221 typedef struct {
222         nchar_t type;
223         nchar_t len;
224         nchar_t opx;
225         nchar_t res;
226 } pgm_opt_generic_t;
227
228 typedef struct {
229         nchar_t type;
230         nchar_t len;
231         nshort_t total_len;
232 } pgm_opt_length_t;
233
234 typedef struct {
235         nchar_t type;
236         nchar_t len;
237         nchar_t opx;
238         nchar_t res;
239 } pgm_opt_nak_list_t;
240
241 /*
242  * To squeeze the whole option into 255 bytes, we
243  * can only have 62 in the list
244  */
245 #define PGM_MAX_NAK_LIST_SZ (62)
246
247 typedef struct {
248         nchar_t type;
249         nchar_t len;
250         nchar_t opx;
251         nchar_t res;
252         nlong_t opt_join_min;
253 } pgm_opt_join_t;
254
255 typedef struct {
256         nchar_t type;
257         nchar_t len;
258         nchar_t opx;
259         nchar_t po;
260         nlong_t prm_tgsz;
261 } pgm_opt_parity_prm_t;
262
263 /* OPT_PARITY_PRM P and O bits */
264 static const nchar_t PGM_OPT_PARITY_PRM_PRO = 0x2;
265 static const nchar_t PGM_OPT_PARITY_PRM_OND = 0x1;
266
267 typedef struct {
268         nchar_t type;
269         nchar_t len;
270         nchar_t opx;
271         nchar_t res;
272         nlong_t prm_grp;
273 } pgm_opt_parity_grp_t;
274
275 typedef struct {
276         nchar_t type;
277         nchar_t len;
278         nchar_t opx;
279         nchar_t res;
280         nlong_t prm_atgsz;
281 } pgm_opt_curr_tgsize_t;
282
283 typedef struct {
284         nchar_t type;
285         nchar_t len;
286         nchar_t opx;
287         nchar_t res;
288         nlong_t tsp;
289         nshort_t acker_afi;
290         nshort_t res2;
291         nlong_t acker;
292 } pgm_opt_pgmcc_data_t;
293
294 typedef struct {
295         nchar_t type;
296         nchar_t len;
297         nchar_t opx;
298         nchar_t res;
299         nlong_t tsp;
300         nshort_t acker_afi;
301         nshort_t loss_rate;
302         nlong_t acker;
303 } pgm_opt_pgmcc_feedback_t;
304
305 typedef struct {
306         nchar_t type;
307         nchar_t len;
308         nchar_t opx;
309         nchar_t res;
310         nlong_t bo_ivl;
311         nlong_t bo_ivl_sqn;
312 } pgm_opt_nak_bo_ivl_t;
313
314 typedef struct {
315         nchar_t type;
316         nchar_t len;
317         nchar_t opx;
318         nchar_t res;
319         nlong_t min_bo_ivl;
320         nlong_t max_bo_ivl;
321 } pgm_opt_nak_bo_rng_t;
322
323 typedef struct {
324         nchar_t type;
325         nchar_t len;
326         nchar_t opx;
327         nchar_t res;
328         nshort_t afi;
329         nshort_t res2;
330         nlong_t dlr;
331 } pgm_opt_redirect_t;
332
333 typedef struct {
334         nchar_t type;
335         nchar_t len;
336         nchar_t opx;
337         nchar_t res;
338         nlong_t first_sqn;
339         nlong_t offset;
340         nlong_t total_length;
341 } pgm_opt_fragment_t;
342
343 /*
344  * Udp port for UDP encapsulation
345  */
346 #define DEFAULT_UDP_ENCAP_UCAST_PORT 3055
347 #define DEFAULT_UDP_ENCAP_MCAST_PORT 3056
348
349 static int udp_encap_ucast_port = 0;
350 static int udp_encap_mcast_port = 0;
351 static int old_encap_ucast_port = 0;
352 static int old_encap_mcast_port = 0;
353
354 static int proto_pgm = -1;
355 static int ett_pgm = -1;
356 static int ett_pgm_optbits = -1;
357 static int ett_pgm_opts = -1;
358 static int ett_pgm_spm = -1;
359 static int ett_pgm_data = -1;
360 static int ett_pgm_nak = -1;
361 static int ett_pgm_poll = -1;
362 static int ett_pgm_polr = -1;
363 static int ett_pgm_ack = -1;
364 static int ett_pgm_opts_join = -1;
365 static int ett_pgm_opts_parityprm = -1;
366 static int ett_pgm_opts_paritygrp = -1;
367 static int ett_pgm_opts_naklist = -1;
368 static int ett_pgm_opts_ccdata = -1;
369 static int ett_pgm_opts_nak_bo_ivl = -1;
370 static int ett_pgm_opts_nak_bo_rng = -1;
371 static int ett_pgm_opts_redirect = -1;
372 static int ett_pgm_opts_fragment = -1;
373
374 static int hf_pgm_main_sport = -1;
375 static int hf_pgm_main_dport = -1;
376 static int hf_pgm_main_type = -1;
377 static int hf_pgm_main_opts = -1;
378 static int hf_pgm_main_opts_opt = -1;
379 static int hf_pgm_main_opts_netsig = -1;
380 static int hf_pgm_main_opts_varlen = -1;
381 static int hf_pgm_main_opts_parity = -1;
382 static int hf_pgm_main_cksum = -1;
383 static int hf_pgm_main_cksum_bad = -1;
384 static int hf_pgm_main_gsi = -1;
385 static int hf_pgm_main_tsdulen = -1;
386 static int hf_pgm_spm_sqn = -1;
387 static int hf_pgm_spm_lead = -1;
388 static int hf_pgm_spm_trail = -1;
389 static int hf_pgm_spm_pathafi = -1;
390 static int hf_pgm_spm_res = -1;
391 static int hf_pgm_spm_path = -1;
392 static int hf_pgm_data_sqn = -1;
393 static int hf_pgm_data_trail = -1;
394 static int hf_pgm_nak_sqn = -1;
395 static int hf_pgm_nak_srcafi = -1;
396 static int hf_pgm_nak_srcres = -1;
397 static int hf_pgm_nak_src = -1;
398 static int hf_pgm_nak_grpafi = -1;
399 static int hf_pgm_nak_grpres = -1;
400 static int hf_pgm_nak_grp = -1;
401 static int hf_pgm_poll_sqn = -1;
402 static int hf_pgm_poll_round = -1;
403 static int hf_pgm_poll_subtype = -1;
404 static int hf_pgm_poll_pathafi = -1;
405 static int hf_pgm_poll_res = -1;
406 static int hf_pgm_poll_path = -1;
407 static int hf_pgm_poll_backoff_ivl = -1;
408 static int hf_pgm_poll_rand_str = -1;
409 static int hf_pgm_poll_matching_bmask = -1;
410 static int hf_pgm_polr_sqn = -1;
411 static int hf_pgm_polr_round = -1;
412 static int hf_pgm_polr_res = -1;
413 static int hf_pgm_ack_sqn = -1;
414 static int hf_pgm_ack_bitmap = -1;
415
416 static int hf_pgm_opt_type = -1;
417 static int hf_pgm_opt_len = -1;
418 static int hf_pgm_opt_tlen = -1;
419
420 static int hf_pgm_genopt_type = -1;
421 static int hf_pgm_genopt_len = -1;
422 static int hf_pgm_genopt_opx = -1;
423
424 static int hf_pgm_opt_join_res = -1;
425 static int hf_pgm_opt_join_minjoin = -1;
426
427 static int hf_pgm_opt_parity_prm_po = -1;
428 static int hf_pgm_opt_parity_prm_prmtgsz = -1;
429
430 static int hf_pgm_opt_parity_grp_res = -1;
431 static int hf_pgm_opt_parity_grp_prmgrp = -1;
432
433 #ifdef PGM_UNUSED_HANDLES
434 static int hf_pgm_opt_curr_tgsize_type = -1;
435 static int hf_pgm_opt_curr_tgsize_len = -1;
436 static int hf_pgm_opt_curr_tgsize_opx = -1;
437 static int hf_pgm_opt_curr_tgsize_res = -1;
438 static int hf_pgm_opt_curr_tgsize_prmatgsz = -1;
439 #endif
440
441 static int hf_pgm_opt_nak_res = -1;
442 static int hf_pgm_opt_nak_list = -1;
443
444 static int hf_pgm_opt_ccdata_res = -1;
445 static int hf_pgm_opt_ccdata_tsp = -1;
446 static int hf_pgm_opt_ccdata_afi = -1;
447 static int hf_pgm_opt_ccdata_res2 = -1;
448 static int hf_pgm_opt_ccdata_acker = -1;
449
450 static int hf_pgm_opt_ccfeedbk_res = -1;
451 static int hf_pgm_opt_ccfeedbk_tsp = -1;
452 static int hf_pgm_opt_ccfeedbk_afi = -1;
453 static int hf_pgm_opt_ccfeedbk_lossrate = -1;
454 static int hf_pgm_opt_ccfeedbk_acker = -1;
455
456 static int hf_pgm_opt_nak_bo_ivl_res = -1;
457 static int hf_pgm_opt_nak_bo_ivl_bo_ivl = -1;
458 static int hf_pgm_opt_nak_bo_ivl_bo_ivl_sqn = -1;
459
460 static int hf_pgm_opt_nak_bo_rng_res = -1;
461 static int hf_pgm_opt_nak_bo_rng_min_bo_ivl = -1;
462 static int hf_pgm_opt_nak_bo_rng_max_bo_ivl = -1;
463
464 static int hf_pgm_opt_redirect_res = -1;
465 static int hf_pgm_opt_redirect_afi = -1;
466 static int hf_pgm_opt_redirect_res2 = -1;
467 static int hf_pgm_opt_redirect_dlr = -1;
468
469 static int hf_pgm_opt_fragment_res = -1;
470 static int hf_pgm_opt_fragment_first_sqn = -1;
471 static int hf_pgm_opt_fragment_offset = -1;
472 static int hf_pgm_opt_fragment_total_length = -1;
473
474 static dissector_table_t subdissector_table;
475 static heur_dissector_list_t heur_subdissector_list;
476 static dissector_handle_t data_handle;
477
478 /*
479  * As of the time this comment was typed
480  *
481  *      http://search.ietf.org/internet-drafts/draft-speakman-pgm-spec-06.txt
482  *
483  * was the URL for the PGM draft.
484  */
485
486 static char *
487 optsstr(nchar_t opts)
488 {
489         static char msg[256];
490         char *p = msg, *str;
491
492         if (opts == 0)
493                 return("");
494
495         if (opts & PGM_OPT){
496                 sprintf(p, "Present");
497                 p += strlen("Present");
498         }
499         if (opts & PGM_OPT_NETSIG){
500                 if (p != msg)
501                         str = ",NetSig";
502                 else
503                         str = "NetSig";
504                 sprintf(p, str);
505                 p += strlen(str);
506         }
507         if (opts & PGM_OPT_VAR_PKTLEN){
508                 if (p != msg)
509                         str = ",VarLen";
510                 else
511                         str = "VarLen";
512                 sprintf(p, str);
513                 p += strlen(str);
514         }
515         if (opts & PGM_OPT_PARITY){
516                 if (p != msg)
517                         str = ",Parity";
518                 else
519                         str = "Parity";
520                 sprintf(p, str);
521                 p += strlen(str);
522         }
523         if (p == msg) {
524                 sprintf(p, "0x%x", opts);
525         }
526         return(msg);
527 }
528 static char *
529 paritystr(nchar_t parity)
530 {
531         static char msg[256];
532         char *p = msg, *str;
533
534         if (parity == 0)
535                 return("");
536
537         if (parity & PGM_OPT_PARITY_PRM_PRO){
538                 sprintf(p, "Pro-active");
539                 p += strlen("Pro-active");
540         }
541         if (parity & PGM_OPT_PARITY_PRM_OND){
542                 if (p != msg)
543                         str = ",On-demand";
544                 else
545                         str = "On-demand";
546                 sprintf(p, str);
547                 p += strlen(str);
548         }
549         if (p == msg) {
550                 sprintf(p, "0x%x", parity);
551         }
552         return(msg);
553 }
554
555 static const value_string opt_vals[] = {
556         { PGM_OPT_LENGTH,      "Length" },
557         { PGM_OPT_END,         "End" },
558         { PGM_OPT_FRAGMENT,    "Fragment" },
559         { PGM_OPT_NAK_LIST,    "NakList" },
560         { PGM_OPT_JOIN,        "Join" },
561         { PGM_OPT_REDIRECT,    "ReDirect" },
562         { PGM_OPT_SYN,         "Syn" },
563         { PGM_OPT_FIN,         "Fin" },
564         { PGM_OPT_RST,         "Rst" },
565         { PGM_OPT_PARITY_PRM,  "ParityPrm" },
566         { PGM_OPT_PARITY_GRP,  "ParityGrp" },
567         { PGM_OPT_CURR_TGSIZE, "CurrTgsiz" },
568         { PGM_OPT_PGMCC_DATA,  "CcData" },
569         { PGM_OPT_PGMCC_FEEDBACK, "CcFeedBack" },
570         { PGM_OPT_NAK_BO_IVL,  "NakBackOffIvl" },
571         { PGM_OPT_NAK_BO_RNG,  "NakBackOffRng" },
572         { PGM_OPT_FRAGMENT,    "Fragment" },
573         { 0,                   NULL }
574 };
575
576 static const value_string opx_vals[] = {
577         { PGM_OPX_IGNORE,  "Ignore" },
578         { PGM_OPX_INVAL,   "Inval" },
579         { PGM_OPX_DISCARD, "DisCard" },
580         { 0,               NULL }
581 };
582
583 static void
584 dissect_pgmopts(tvbuff_t *tvb, int offset, proto_tree *tree,
585     const char *pktname)
586 {
587         proto_item *tf;
588         proto_tree *opts_tree = NULL;
589         proto_tree *opt_tree = NULL;
590         pgm_opt_length_t opts;
591         pgm_opt_generic_t genopts;
592         gboolean theend = FALSE, firsttime = TRUE;
593
594         tvb_memcpy(tvb, (guint8 *)&opts, offset, sizeof(opts));
595         if (opts.type != PGM_OPT_LENGTH) {
596                 proto_tree_add_text(tree, tvb, offset, 1,
597                     "%s Options - initial option is %s, should be %s",
598                     pktname,
599                     val_to_str(opts.type, opt_vals, "Unknown (0x%02x)"),
600                     val_to_str(PGM_OPT_LENGTH, opt_vals, "Unknown (0x%02x)"));
601                 return;
602         }
603         opts.total_len = g_ntohs(opts.total_len);
604
605         if (opts.total_len < 4) {
606                 proto_tree_add_text(opts_tree, tvb, offset, 4,
607                         "%s Options (Total Length %u - invalid, must be >= 4)",
608                         pktname, opts.total_len);
609                 return;
610         }
611         tf = proto_tree_add_text(tree, tvb, offset,
612                 opts.total_len,
613                 "%s Options (Total Length %d)", pktname, opts.total_len);
614         opts_tree = proto_item_add_subtree(tf, ett_pgm_opts);
615         proto_tree_add_uint(opts_tree, hf_pgm_opt_type, tvb,
616                 offset, 1, opts.type);
617         proto_tree_add_uint(opts_tree, hf_pgm_opt_len, tvb,
618                 offset+1, 1, opts.len);
619         proto_tree_add_uint(opts_tree, hf_pgm_opt_tlen, tvb,
620                 offset+2, 2, opts.total_len);
621
622         offset += 4;
623         for (opts.total_len -= 4; !theend && opts.total_len != 0;){
624                 if (opts.total_len < 4) {
625                         proto_tree_add_text(opts_tree, tvb, offset, opts.total_len,
626                             "Remaining total options length doesn't have enough for an options header");
627                         break;
628                 }
629                 tvb_memcpy(tvb, (guint8 *)&genopts, offset, sizeof(genopts));
630                 if (genopts.type & PGM_OPT_END)  {
631                         genopts.type &= ~PGM_OPT_END;
632                         theend = TRUE;
633                 }
634                 if (genopts.len < 4) {
635                         proto_tree_add_text(opts_tree, tvb, offset, genopts.len,
636                                 "Option: %s, Length: %u (invalid, must be >= 4)",
637                                 val_to_str(genopts.type, opt_vals, "Unknown (0x%02x)"),
638                                 genopts.len);
639                         break;
640                 }
641                 if (opts.total_len < genopts.len) {
642                         proto_tree_add_text(opts_tree, tvb, offset, genopts.len,
643                             "Option: %s, Length: %u (> remaining total options length)",
644                             val_to_str(genopts.type, opt_vals, "Unknown (0x%02x)"),
645                             genopts.len);
646                         break;
647                 }
648                 tf = proto_tree_add_text(opts_tree, tvb, offset, genopts.len,
649                         "Option: %s, Length: %u",
650                         val_to_str(genopts.type, opt_vals, "Unknown (0x%02x)"),
651                         genopts.len);
652
653                 switch(genopts.type) {
654                 case PGM_OPT_JOIN:{
655                         pgm_opt_join_t optdata;
656
657                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_join);
658
659                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type,
660                                 tvb, offset, 1, genopts.type);
661
662                         if (genopts.len < sizeof optdata) {
663                                 proto_tree_add_uint_format(opt_tree, hf_pgm_genopt_len, tvb,
664                                         offset+1, 1, genopts.len,
665                                         "Length: %u (bogus, must be >= %lu)",
666                                         genopts.len,
667                                         (unsigned long)sizeof optdata);
668                                 break;
669                         }
670                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb,
671                                 offset+1, 1, genopts.len);
672
673                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx, tvb,
674                                 offset+2, 1, genopts.opx);
675
676                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
677
678                         proto_tree_add_uint(opt_tree, hf_pgm_opt_join_res, tvb,
679                                 offset+3, 1, optdata.res);
680
681                         proto_tree_add_uint(opt_tree, hf_pgm_opt_join_minjoin, tvb,
682                                 offset+4, 4, g_ntohl(optdata.opt_join_min));
683
684                         break;
685                 }
686                 case PGM_OPT_PARITY_PRM:{
687                         pgm_opt_parity_prm_t optdata;
688
689                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_parityprm);
690
691                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type,
692                                 tvb, offset, 1, genopts.type);
693
694                         if (genopts.len < sizeof optdata) {
695                                 proto_tree_add_uint_format(opt_tree, hf_pgm_genopt_len, tvb,
696                                         offset+1, 1, genopts.len,
697                                         "Length: %u (bogus, must be >= %lu)",
698                                         genopts.len,
699                                         (unsigned long) sizeof optdata);
700                                 break;
701                         }
702                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb,
703                                 offset+1, 1, genopts.len);
704
705                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx,
706                                 tvb, offset+2, 1, genopts.opx);
707
708                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
709
710                         proto_tree_add_uint_format(opt_tree, hf_pgm_opt_parity_prm_po, tvb,
711                                 offset+3, 1, optdata.po, "Parity Parameters: %s (0x%x)",
712                                 paritystr(optdata.po), optdata.po);
713
714                         proto_tree_add_uint(opt_tree, hf_pgm_opt_parity_prm_prmtgsz,
715                                 tvb, offset+4, 4, g_ntohl(optdata.prm_tgsz));
716
717                         break;
718                 }
719                 case PGM_OPT_PARITY_GRP:{
720                         pgm_opt_parity_grp_t optdata;
721
722                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_paritygrp);
723
724                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type,
725                                 tvb, offset, 1, genopts.type);
726
727                         if (genopts.len < sizeof optdata) {
728                                 proto_tree_add_uint_format(opt_tree, hf_pgm_genopt_len, tvb,
729                                         offset+1, 1, genopts.len,
730                                         "Length: %u (bogus, must be >= %lu)",
731                                         genopts.len,
732                                         (unsigned long) sizeof optdata);
733                                 break;
734                         }
735                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb,
736                                 offset+1, 1, genopts.len);
737
738                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx,
739                                 tvb, offset+2, 1, genopts.opx);
740
741                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
742
743                         proto_tree_add_uint(opt_tree, hf_pgm_opt_parity_grp_res, tvb,
744                                 offset+3, 1, optdata.res);
745
746                         proto_tree_add_uint(opt_tree, hf_pgm_opt_parity_grp_prmgrp,
747                                 tvb, offset+4, 4, g_ntohl(optdata.prm_grp));
748
749                         break;
750                 }
751                 case PGM_OPT_NAK_LIST:{
752                         pgm_opt_nak_list_t optdata;
753                         nlong_t naklist[PGM_MAX_NAK_LIST_SZ+1];
754                         char nakbuf[8192], *ptr;
755                         int i, j, naks, soffset = 0;
756
757                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_naklist);
758
759                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type, tvb,
760                                 offset, 1, genopts.type);
761
762                         if (genopts.len < sizeof optdata) {
763                                 proto_tree_add_uint_format(opt_tree, hf_pgm_genopt_len, tvb,
764                                         offset+1, 1, genopts.len,
765                                         "Length: %u (bogus, must be >= %lu)",
766                                         genopts.len,
767                                         (unsigned long) sizeof optdata);
768                                 break;
769                         }
770                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb,
771                                 offset+1, 1, genopts.len);
772
773                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx,
774                                 tvb, offset+2, 1, genopts.opx);
775
776                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
777
778                         proto_tree_add_uint(opt_tree, hf_pgm_opt_nak_res, tvb,
779                                 offset+3, 1, optdata.res);
780
781                         optdata.len -= sizeof(pgm_opt_nak_list_t);
782                         tvb_memcpy(tvb, (guint8 *)naklist, offset+4, optdata.len);
783                         naks = (optdata.len/sizeof(nlong_t));
784                         ptr = nakbuf;
785                         j = 0;
786                         /*
787                          * Print out 8 per line
788                          */
789                         for (i=0; i < naks; i++) {
790                                 sprintf(nakbuf+soffset, "0x%lx ",
791                                     (unsigned long)g_ntohl(naklist[i]));
792                                 soffset = strlen(nakbuf);
793                                 if ((++j % 8) == 0) {
794                                         if (firsttime) {
795                                                 proto_tree_add_bytes_format(opt_tree,
796                                                         hf_pgm_opt_nak_list, tvb, offset+4, optdata.len,
797                                                         nakbuf, "List(%d): %s", naks, nakbuf);
798                                                         soffset = 0;
799                                         } else {
800                                                 proto_tree_add_bytes_format(opt_tree,
801                                                         hf_pgm_opt_nak_list, tvb, offset+4, optdata.len,
802                                                         nakbuf, "List: %s", nakbuf);
803                                                         soffset = 0;
804                                         }
805                                         firsttime = FALSE;
806                                 }
807                         }
808                         if (soffset) {
809                                 if (firsttime) {
810                                         proto_tree_add_bytes_format(opt_tree,
811                                                 hf_pgm_opt_nak_list, tvb, offset+4, optdata.len,
812                                                 nakbuf, "List(%d): %s", naks, nakbuf);
813                                                 soffset = 0;
814                                 } else {
815                                         proto_tree_add_bytes_format(opt_tree,
816                                                 hf_pgm_opt_nak_list, tvb, offset+4, optdata.len,
817                                                 nakbuf, "List: %s", nakbuf);
818                                                 soffset = 0;
819                                 }
820                         }
821                         break;
822                 }
823                 case PGM_OPT_PGMCC_DATA:{
824                         pgm_opt_pgmcc_data_t optdata;
825
826                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_ccdata);
827
828                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type,
829                                 tvb, offset, 1, genopts.type);
830
831                         if (genopts.len < sizeof optdata) {
832                                 proto_tree_add_uint_format(opt_tree, hf_pgm_genopt_len, tvb,
833                                         offset+1, 1, genopts.len,
834                                         "Length: %u (bogus, must be >= %lu)",
835                                         genopts.len,
836                                         (unsigned long) sizeof optdata);
837                                 break;
838                         }
839                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb,
840                                 offset+1, 1, genopts.len);
841
842                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx,
843                                 tvb, offset+2, 1, genopts.opx);
844
845                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
846
847                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccdata_res, tvb,
848                                 offset+3, 1, optdata.res);
849
850                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccdata_tsp, tvb,
851                                 offset+4, 4, optdata.tsp);
852
853                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccdata_afi, tvb,
854                                 offset+8, 2, g_ntohs(optdata.acker_afi));
855
856                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccdata_res2, tvb,
857                                 offset+10, 2, g_ntohs(optdata.res2));
858
859                         switch (g_ntohs(optdata.acker_afi)) {
860
861                         case AFNUM_INET:
862                                 proto_tree_add_ipv4(opt_tree, hf_pgm_opt_ccdata_acker,
863                                     tvb, offset+12, 4, optdata.acker);
864                                 break;
865
866                         default:
867                                 /*
868                                  * XXX - the header is variable-length,
869                                  * as the length of the NLA depends on
870                                  * its AFI.
871                                  *
872                                  * However, our structure for it is
873                                  * fixed-length, and assumes it's a 4-byte
874                                  * IPv4 address.
875                                  */
876                                 break;
877                         }
878
879                         break;
880                 }
881                 case PGM_OPT_PGMCC_FEEDBACK:{
882                         pgm_opt_pgmcc_feedback_t optdata;
883
884                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_ccdata);
885
886                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type,
887                                 tvb, offset, 1, genopts.type);
888
889                         if (genopts.len < sizeof optdata) {
890                                 proto_tree_add_uint_format(opt_tree, hf_pgm_genopt_len, tvb,
891                                         offset+1, 1, genopts.len,
892                                         "Length: %u (bogus, must be >= %lu)",
893                                         genopts.len,
894                                         (unsigned long) sizeof optdata);
895                                 break;
896                         }
897                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb,
898                                 offset+1, 1, genopts.len);
899
900                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx,
901                                 tvb, offset+2, 1, genopts.opx);
902
903                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
904
905                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccfeedbk_res, tvb,
906                                 offset+3, 1, optdata.res);
907
908                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccfeedbk_tsp, tvb,
909                                 offset+4, 4, optdata.tsp);
910
911                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccfeedbk_afi, tvb,
912                                 offset+8, 2, g_ntohs(optdata.acker_afi));
913
914                         proto_tree_add_uint(opt_tree, hf_pgm_opt_ccfeedbk_lossrate, tvb,
915                                 offset+10, 2, g_ntohs(optdata.loss_rate));
916
917                         switch (g_ntohs(optdata.acker_afi)) {
918
919                         case AFNUM_INET:
920                                 proto_tree_add_ipv4(opt_tree, hf_pgm_opt_ccfeedbk_acker,
921                                     tvb, offset+12, 4, optdata.acker);
922                                 break;
923
924                         default:
925                                 /*
926                                  * XXX - the header is variable-length,
927                                  * as the length of the NLA depends on
928                                  * its AFI.
929                                  *
930                                  * However, our structure for it is
931                                  * fixed-length, and assumes it's a 4-byte
932                                  * IPv4 address.
933                                  */
934                                 break;
935                         }
936
937                         break;
938                 }
939                 case PGM_OPT_NAK_BO_IVL:{
940                         pgm_opt_nak_bo_ivl_t optdata;
941
942                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_nak_bo_ivl);
943
944                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type,
945                                 tvb, offset, 1, genopts.type);
946
947                         if (genopts.len < sizeof optdata) {
948                                 proto_tree_add_uint_format(opt_tree, hf_pgm_genopt_len, tvb,
949                                         offset+1, 1, genopts.len,
950                                         "Length: %u (bogus, must be >= %lu)",
951                                         genopts.len,
952                                         (unsigned long) sizeof optdata);
953                                 break;
954                         }
955                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb,
956                                 offset+1, 1, genopts.len);
957
958                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx, tvb,
959                                 offset+2, 1, genopts.opx);
960
961                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
962
963                         proto_tree_add_uint(opt_tree, hf_pgm_opt_nak_bo_ivl_res, tvb,
964                                 offset+3, 1, optdata.res);
965
966                         proto_tree_add_uint(opt_tree, hf_pgm_opt_nak_bo_ivl_bo_ivl, tvb,
967                                 offset+4, 4, g_ntohl(optdata.bo_ivl));
968
969                         proto_tree_add_uint(opt_tree, hf_pgm_opt_nak_bo_ivl_bo_ivl_sqn, tvb,
970                                 offset+8, 4, g_ntohl(optdata.bo_ivl_sqn));
971
972                         break;
973                 }
974                 case PGM_OPT_NAK_BO_RNG:{
975                         pgm_opt_nak_bo_rng_t optdata;
976
977                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_nak_bo_rng);
978
979                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type,
980                                 tvb, offset, 1, genopts.type);
981
982                         if (genopts.len < sizeof optdata) {
983                                 proto_tree_add_uint_format(opt_tree, hf_pgm_genopt_len, tvb,
984                                         offset+1, 1, genopts.len,
985                                         "Length: %u (bogus, must be >= %lu)",
986                                         genopts.len,
987                                         (unsigned long) sizeof optdata);
988                                 break;
989                         }
990                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb,
991                                 offset+1, 1, genopts.len);
992
993                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx, tvb,
994                                 offset+2, 1, genopts.opx);
995
996                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
997
998                         proto_tree_add_uint(opt_tree, hf_pgm_opt_nak_bo_rng_res, tvb,
999                                 offset+3, 1, optdata.res);
1000
1001                         proto_tree_add_uint(opt_tree, hf_pgm_opt_nak_bo_rng_min_bo_ivl, tvb,
1002                                 offset+4, 4, g_ntohl(optdata.min_bo_ivl));
1003
1004                         proto_tree_add_uint(opt_tree, hf_pgm_opt_nak_bo_rng_max_bo_ivl, tvb,
1005                                 offset+8, 4, g_ntohl(optdata.max_bo_ivl));
1006
1007                         break;
1008                 }
1009                 case PGM_OPT_REDIRECT:{
1010                         pgm_opt_redirect_t optdata;
1011
1012                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_redirect);
1013
1014                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type,
1015                                 tvb, offset, 1, genopts.type);
1016
1017                         if (genopts.len < sizeof optdata) {
1018                                 proto_tree_add_uint_format(opt_tree, hf_pgm_genopt_len, tvb,
1019                                         offset+1, 1, genopts.len,
1020                                         "Length: %u (bogus, must be >= %lu)",
1021                                         genopts.len,
1022                                         (unsigned long) sizeof optdata);
1023                                 break;
1024                         }
1025                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb,
1026                                 offset+1, 1, genopts.len);
1027
1028                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx,
1029                                 tvb, offset+2, 1, genopts.opx);
1030
1031                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
1032
1033                         proto_tree_add_uint(opt_tree, hf_pgm_opt_redirect_res, tvb,
1034                                 offset+3, 1, optdata.res);
1035
1036                         proto_tree_add_uint(opt_tree, hf_pgm_opt_redirect_afi, tvb,
1037                                 offset+4, 2, g_ntohs(optdata.afi));
1038
1039                         proto_tree_add_uint(opt_tree, hf_pgm_opt_redirect_res2, tvb,
1040                                 offset+6, 2, g_ntohs(optdata.res2));
1041
1042                         switch (g_ntohs(optdata.afi)) {
1043
1044                         case AFNUM_INET:
1045                                 proto_tree_add_ipv4(opt_tree, hf_pgm_opt_redirect_dlr,
1046                                     tvb, offset+8, 4, optdata.dlr);
1047                                 break;
1048
1049                         default:
1050                                 /*
1051                                  * XXX - the header is variable-length,
1052                                  * as the length of the NLA depends on
1053                                  * its AFI.
1054                                  *
1055                                  * However, our structure for it is
1056                                  * fixed-length, and assumes it's a 4-byte
1057                                  * IPv4 address.
1058                                  */
1059                                 break;
1060                         }
1061
1062                         break;
1063                 }
1064                 case PGM_OPT_FRAGMENT:{
1065                         pgm_opt_fragment_t optdata;
1066
1067                         opt_tree = proto_item_add_subtree(tf, ett_pgm_opts_fragment);
1068
1069                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_type,
1070                                 tvb, offset, 1, genopts.type);
1071
1072                         if (genopts.len < sizeof optdata) {
1073                                 proto_tree_add_uint_format(opt_tree, hf_pgm_genopt_len, tvb,
1074                                         offset+1, 1, genopts.len,
1075                                         "Length: %u (bogus, must be >= %lu)",
1076                                         genopts.len,
1077                                         (unsigned long) sizeof optdata);
1078                                 break;
1079                         }
1080                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_len, tvb,
1081                                 offset+1, 1, genopts.len);
1082
1083                         proto_tree_add_uint(opt_tree, hf_pgm_genopt_opx, tvb,
1084                                 offset+2, 1, genopts.opx);
1085
1086                         tvb_memcpy(tvb, (guint8 *)&optdata, offset, sizeof(optdata));
1087
1088                         proto_tree_add_uint(opt_tree, hf_pgm_opt_fragment_res, tvb,
1089                                 offset+3, 1, optdata.res);
1090
1091                         proto_tree_add_uint(opt_tree, hf_pgm_opt_fragment_first_sqn, tvb,
1092                                 offset+4, 4, g_ntohl(optdata.first_sqn));
1093
1094                         proto_tree_add_uint(opt_tree, hf_pgm_opt_fragment_offset, tvb,
1095                                 offset+8, 4, g_ntohl(optdata.offset));
1096
1097                         proto_tree_add_uint(opt_tree, hf_pgm_opt_fragment_total_length, tvb,
1098                                 offset+12, 4, g_ntohl(optdata.total_length));
1099
1100                         break;
1101                 }
1102                 }
1103                 offset += genopts.len;
1104                 opts.total_len -= genopts.len;
1105
1106         }
1107         return ;
1108 }
1109
1110 static const value_string type_vals[] = {
1111         { PGM_SPM_PCKT,   "SPM" },
1112         { PGM_RDATA_PCKT, "RDATA" },
1113         { PGM_ODATA_PCKT, "ODATA" },
1114         { PGM_NAK_PCKT,   "NAK" },
1115         { PGM_NNAK_PCKT,  "NNAK" },
1116         { PGM_NCF_PCKT,   "NCF" },
1117         { PGM_POLL_PCKT,  "POLL" },
1118         { PGM_POLR_PCKT,  "POLR" },
1119         { PGM_ACK_PCKT,   "ACK" },
1120         { 0,              NULL }
1121 };
1122
1123 static const value_string poll_subtype_vals[] = {
1124         { PGM_POLL_GENERAL,   "General" },
1125         { PGM_POLL_DLR,       "DLR" },
1126         { 0,                  NULL }
1127 };
1128 /* Determine if there is a sub-dissector and call it.  This has been */
1129 /* separated into a stand alone routine to other protocol dissectors */
1130 /* can call to it, ie. socks    */
1131
1132 void
1133 decode_pgm_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,
1134         proto_tree *tree, pgm_type *pgmhdr)
1135 {
1136   tvbuff_t *next_tvb;
1137   int found = 0;
1138
1139   next_tvb = tvb_new_subset(tvb, offset, -1, -1);
1140
1141   /* do lookup with the subdissector table */
1142   found = dissector_try_port(subdissector_table, pgmhdr->sport,
1143                         next_tvb, pinfo, tree);
1144   if (found)
1145         return;
1146
1147   found = dissector_try_port(subdissector_table, pgmhdr->dport,
1148                         next_tvb, pinfo, tree);
1149   if (found)
1150         return;
1151
1152   /* do lookup with the heuristic subdissector table */
1153   if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree))
1154     return;
1155
1156   /* Oh, well, we don't know this; dissect it as data. */
1157   call_dissector(data_handle,next_tvb, pinfo, tree);
1158
1159 }
1160 int
1161 total_size(tvbuff_t *tvb, pgm_type *hdr)
1162 {
1163         int bytes = sizeof(pgm_type);
1164         pgm_opt_length_t opts;
1165
1166         switch(hdr->type) {
1167         case PGM_SPM_PCKT:
1168                 bytes += sizeof(pgm_spm_t);
1169                 break;
1170
1171         case PGM_RDATA_PCKT:
1172         case PGM_ODATA_PCKT:
1173                 bytes += sizeof(pgm_data_t);
1174                 break;
1175
1176         case PGM_NAK_PCKT:
1177         case PGM_NNAK_PCKT:
1178         case PGM_NCF_PCKT:
1179                 bytes += sizeof(pgm_nak_t);
1180                 break;
1181         case PGM_POLL_PCKT:
1182                 bytes += sizeof(pgm_poll_t);
1183                 break;
1184         case PGM_POLR_PCKT:
1185                 bytes += sizeof(pgm_polr_t);
1186                 break;
1187         case PGM_ACK_PCKT:
1188                 bytes += sizeof(pgm_ack_t);
1189                 break;
1190         }
1191         if ((hdr->opts & PGM_OPT)) {
1192                 tvb_memcpy(tvb, (guint8 *)&opts, bytes, sizeof(opts));
1193                 bytes += g_ntohs(opts.total_len);
1194         }
1195         return(bytes);
1196 }
1197 /*
1198  * dissect_pgm - The dissector for Pragmatic General Multicast
1199  */
1200 static void
1201 dissect_pgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1202 {
1203         proto_tree *pgm_tree = NULL;
1204         proto_tree *opt_tree = NULL;
1205         proto_tree *type_tree = NULL;
1206         proto_item *tf;
1207         pgm_type pgmhdr;
1208         pgm_spm_t spm;
1209         pgm_data_t data;
1210         pgm_nak_t nak;
1211         pgm_poll_t poll;
1212         pgm_polr_t polr;
1213         pgm_ack_t ack;
1214         int offset = 0;
1215         guint hlen, plen;
1216         proto_item *ti;
1217         const char *pktname;
1218         const char *pollstname;
1219         char *gsi;
1220         int isdata = 0;
1221         guint pgmlen, reportedlen;
1222
1223         if (check_col(pinfo->cinfo, COL_PROTOCOL))
1224                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PGM");
1225
1226         /* Clear out the Info column. */
1227         if (check_col(pinfo->cinfo, COL_INFO))
1228                 col_clear(pinfo->cinfo, COL_INFO);
1229
1230         tvb_memcpy(tvb, (guint8 *)&pgmhdr, offset, sizeof(pgm_type));
1231         hlen = sizeof(pgm_type);
1232         pgmhdr.sport = g_ntohs(pgmhdr.sport);
1233         pgmhdr.dport = g_ntohs(pgmhdr.dport);
1234         pgmhdr.tsdulen = g_ntohs(pgmhdr.tsdulen);
1235         pgmhdr.cksum = g_ntohs(pgmhdr.cksum);
1236
1237         pktname = val_to_str(pgmhdr.type, type_vals, "Unknown (0x%02x)");
1238
1239         gsi = bytes_to_str(pgmhdr.gsi, 6);
1240         switch(pgmhdr.type) {
1241         case PGM_SPM_PCKT:
1242                 plen = sizeof(pgm_spm_t);
1243                 tvb_memcpy(tvb, (guint8 *)&spm, sizeof(pgm_type), plen);
1244                 spm_ntoh(&spm);
1245                 if (check_col(pinfo->cinfo, COL_INFO)) {
1246                         col_add_fstr(pinfo->cinfo, COL_INFO,
1247                                 "%-5s sqn 0x%x gsi %s", pktname, spm.sqn, gsi);
1248                 }
1249                 break;
1250
1251         case PGM_RDATA_PCKT:
1252         case PGM_ODATA_PCKT:
1253                 plen = sizeof(pgm_data_t);
1254                 tvb_memcpy(tvb, (guint8 *)&data, sizeof(pgm_type), plen);
1255                 data_ntoh(&data);
1256                 if (check_col(pinfo->cinfo, COL_INFO)) {
1257                         col_add_fstr(pinfo->cinfo, COL_INFO,
1258                             "%-5s sqn 0x%x gsi %s tsdulen %d", pktname, data.sqn, gsi,
1259                             pgmhdr.tsdulen);
1260                 }
1261                 isdata = 1;
1262                 break;
1263
1264         case PGM_NAK_PCKT:
1265         case PGM_NNAK_PCKT:
1266         case PGM_NCF_PCKT:
1267                 plen = sizeof(pgm_nak_t);
1268                 tvb_memcpy(tvb, (guint8 *)&nak, sizeof(pgm_type), plen);
1269                 nak_ntoh(&nak);
1270                 if (check_col(pinfo->cinfo, COL_INFO)) {
1271                         col_add_fstr(pinfo->cinfo, COL_INFO,
1272                                 "%-5s sqn 0x%x gsi %s", pktname, nak.sqn, gsi);
1273                 }
1274                 break;
1275         case PGM_POLL_PCKT:
1276                 plen = sizeof(pgm_poll_t);
1277                 tvb_memcpy(tvb, (guint8 *)&poll, sizeof(pgm_type), plen);
1278                 poll_ntoh(&poll);
1279                 pollstname = val_to_str(poll.subtype, poll_subtype_vals, "Unknown (0x%02x)");
1280                 if (check_col(pinfo->cinfo, COL_INFO)) {
1281                         col_add_fstr(pinfo->cinfo, COL_INFO,
1282                                 "%-5s sqn 0x%x gsi %s subtype %s", pktname, poll.sqn, gsi, pollstname);
1283                 }
1284                 break;
1285         case PGM_POLR_PCKT:
1286                 plen = sizeof(pgm_polr_t);
1287                 tvb_memcpy(tvb, (guint8 *)&polr, sizeof(pgm_type), plen);
1288                 polr_ntoh(&polr);
1289                 if (check_col(pinfo->cinfo, COL_INFO)) {
1290                         col_add_fstr(pinfo->cinfo, COL_INFO,
1291                                 "%-5s sqn 0x%x gsi %s", pktname, polr.sqn, gsi);
1292                 }
1293                 break;
1294         case PGM_ACK_PCKT:
1295                 plen = sizeof(pgm_ack_t);
1296                 tvb_memcpy(tvb, (guint8 *)&ack, sizeof(pgm_type), plen);
1297                 ack_ntoh(&ack);
1298                 if (check_col(pinfo->cinfo, COL_INFO)) {
1299                         col_add_fstr(pinfo->cinfo, COL_INFO,
1300                             "%-5s sqn 0x%x gsi %s", pktname, ack.rx_max_sqn, gsi);
1301                 }
1302                 break;
1303
1304         default:
1305                 return;
1306         }
1307
1308         if (tree) {
1309                 ti = proto_tree_add_protocol_format(tree, proto_pgm,
1310                         tvb, offset, total_size(tvb, &pgmhdr),
1311                         "Pragmatic General Multicast: Type %s"
1312                             " SrcPort %u, DstPort %u, GSI %s", pktname,
1313                         pgmhdr.sport, pgmhdr.dport,
1314                         bytes_to_str(pgmhdr.gsi, 6));
1315
1316                 pgm_tree = proto_item_add_subtree(ti, ett_pgm);
1317                 proto_tree_add_uint(pgm_tree, hf_pgm_main_sport, tvb, offset, 2,
1318                         pgmhdr.sport);
1319                 proto_tree_add_uint(pgm_tree, hf_pgm_main_dport, tvb, offset+2,
1320                         2, pgmhdr.dport);
1321                 proto_tree_add_uint(pgm_tree, hf_pgm_main_type, tvb,
1322                         offset+4, 1, pgmhdr.type);
1323
1324                 tf = proto_tree_add_uint_format(pgm_tree, hf_pgm_main_opts, tvb,
1325                         offset+5, 1, pgmhdr.opts, "Options: %s (0x%x)",
1326                         optsstr(pgmhdr.opts), pgmhdr.opts);
1327                 opt_tree = proto_item_add_subtree(tf, ett_pgm_optbits);
1328
1329                 proto_tree_add_boolean(opt_tree, hf_pgm_main_opts_opt, tvb,
1330                         offset+5, 1, (pgmhdr.opts & PGM_OPT));
1331                 proto_tree_add_boolean(opt_tree, hf_pgm_main_opts_netsig, tvb,
1332                         offset+5, 1, (pgmhdr.opts & PGM_OPT_NETSIG));
1333                 proto_tree_add_boolean(opt_tree, hf_pgm_main_opts_varlen, tvb,
1334                         offset+5, 1, (pgmhdr.opts & PGM_OPT_VAR_PKTLEN));
1335                 proto_tree_add_boolean(opt_tree, hf_pgm_main_opts_parity, tvb,
1336                         offset+5, 1, (pgmhdr.opts & PGM_OPT_PARITY));
1337
1338                 reportedlen = tvb_reported_length(tvb);
1339                 pgmlen = tvb_length(tvb);
1340                 if (pgm_check_checksum && pgmlen >= reportedlen) {
1341                         vec_t cksum_vec[1];
1342                         guint16 computed_cksum;
1343
1344                         cksum_vec[0].ptr = tvb_get_ptr(tvb, offset, pgmlen);
1345                         cksum_vec[0].len = pgmlen;
1346                         computed_cksum = in_cksum(&cksum_vec[0], 1);
1347                         if (computed_cksum == 0) {
1348                                 proto_tree_add_uint_format(pgm_tree, hf_pgm_main_cksum, tvb,
1349                                         offset+6, 2, pgmhdr.cksum, "Checksum: 0x%04x (correct)", pgmhdr.cksum);
1350                         } else {
1351                                 proto_tree_add_boolean_hidden(pgm_tree, hf_pgm_main_cksum_bad, tvb,
1352                                     offset+6, 2, TRUE);
1353                                 proto_tree_add_uint_format(pgm_tree, hf_pgm_main_cksum, tvb,
1354                                     offset+6, 2, pgmhdr.cksum, "Checksum: 0x%04x (incorrect, should be 0x%04x)",
1355                                         pgmhdr.cksum, in_cksum_shouldbe(pgmhdr.cksum, computed_cksum));
1356                         }
1357                 } else {
1358                         proto_tree_add_uint(pgm_tree, hf_pgm_main_cksum, tvb, offset+6,
1359                                 2, pgmhdr.cksum);
1360                 }
1361
1362                 proto_tree_add_bytes(pgm_tree, hf_pgm_main_gsi, tvb, offset+8,
1363                         6, pgmhdr.gsi);
1364                 proto_tree_add_uint(pgm_tree, hf_pgm_main_tsdulen, tvb,
1365                         offset+14, 2, pgmhdr.tsdulen);
1366
1367                 offset = sizeof(pgm_type);
1368                 tf = proto_tree_add_text(pgm_tree, tvb, offset, plen, "%s Packet",
1369                         pktname);
1370                 switch(pgmhdr.type) {
1371                 case PGM_SPM_PCKT:
1372                         type_tree = proto_item_add_subtree(tf, ett_pgm_spm);
1373
1374                         proto_tree_add_uint(type_tree, hf_pgm_spm_sqn, tvb,
1375                                 offset, 4, spm.sqn);
1376                         proto_tree_add_uint(type_tree, hf_pgm_spm_trail, tvb,
1377                                 offset+4, 4, spm.trail);
1378                         proto_tree_add_uint(type_tree, hf_pgm_spm_lead, tvb,
1379                                 offset+8, 4, spm.lead);
1380                         proto_tree_add_uint(type_tree, hf_pgm_spm_pathafi, tvb,
1381                                 offset+12, 2, spm.path_afi);
1382                         proto_tree_add_uint(type_tree, hf_pgm_spm_res, tvb,
1383                                 offset+14, 2, spm.res);
1384                         switch (spm.path_afi) {
1385
1386                         case AFNUM_INET:
1387                                 proto_tree_add_ipv4(type_tree, hf_pgm_spm_path,
1388                                     tvb, offset+16, 4, spm.path);
1389                                 break;
1390
1391                         default:
1392                                 /*
1393                                  * XXX - the header is variable-length,
1394                                  * as the length of the NLA depends on
1395                                  * its AFI.
1396                                  *
1397                                  * However, our structure for it is
1398                                  * fixed-length, and assumes it's a 4-byte
1399                                  * IPv4 address.
1400                                  */
1401                                 return;
1402                         }
1403
1404                         if ((pgmhdr.opts & PGM_OPT) == FALSE)
1405                                 break;
1406                         offset += plen;
1407
1408                         dissect_pgmopts(tvb, offset, type_tree, pktname);
1409
1410                         break;
1411
1412                 case PGM_RDATA_PCKT:
1413                 case PGM_ODATA_PCKT: {
1414                         type_tree = proto_item_add_subtree(tf, ett_pgm_data);
1415
1416                         proto_tree_add_uint(type_tree, hf_pgm_spm_sqn, tvb,
1417                                 offset, 4, data.sqn);
1418                         proto_tree_add_uint(type_tree, hf_pgm_spm_trail, tvb,
1419                                 offset+4, 4, data.trail);
1420
1421                         if ((pgmhdr.opts & PGM_OPT) == FALSE)
1422                                 break;
1423                         offset += plen;
1424
1425                         dissect_pgmopts(tvb, offset, type_tree, pktname);
1426
1427                         break;
1428                 }
1429
1430
1431                 case PGM_NAK_PCKT:
1432                 case PGM_NNAK_PCKT:
1433                 case PGM_NCF_PCKT:
1434                         type_tree = proto_item_add_subtree(tf, ett_pgm_nak);
1435
1436                         proto_tree_add_uint(type_tree, hf_pgm_nak_sqn, tvb,
1437                                 offset, 4, nak.sqn);
1438                         proto_tree_add_uint(type_tree, hf_pgm_nak_srcafi, tvb,
1439                                 offset+4, 2, nak.src_afi);
1440                         proto_tree_add_uint(type_tree, hf_pgm_nak_srcres, tvb,
1441                                 offset+6, 2, nak.src_res);
1442
1443                         switch (nak.src_afi) {
1444
1445                         case AFNUM_INET:
1446                                 proto_tree_add_ipv4(type_tree, hf_pgm_nak_src,
1447                                     tvb, offset+8, 4, nak.src);
1448                                 break;
1449
1450                         default:
1451                                 /*
1452                                  * XXX - the header is variable-length,
1453                                  * as the length of the NLA depends on
1454                                  * its AFI.
1455                                  *
1456                                  * However, our structure for it is
1457                                  * fixed-length, and assumes it's a 4-byte
1458                                  * IPv4 address.
1459                                  */
1460                                 break;
1461                         }
1462
1463                         proto_tree_add_uint(type_tree, hf_pgm_nak_grpafi, tvb,
1464                                 offset+12, 2, nak.grp_afi);
1465                         proto_tree_add_uint(type_tree, hf_pgm_nak_grpres, tvb,
1466                                 offset+14, 2, nak.grp_res);
1467
1468                         switch (nak.grp_afi) {
1469
1470                         case AFNUM_INET:
1471                                 proto_tree_add_ipv4(type_tree, hf_pgm_nak_grp,
1472                                     tvb, offset+16, 4, nak.grp);
1473                                 break;
1474
1475                         default:
1476                                 /*
1477                                  * XXX - the header is variable-length,
1478                                  * as the length of the NLA depends on
1479                                  * its AFI.
1480                                  *
1481                                  * However, our structure for it is
1482                                  * fixed-length, and assumes it's a 4-byte
1483                                  * IPv4 address.
1484                                  */
1485                                 return;
1486                         }
1487
1488                         if ((pgmhdr.opts & PGM_OPT) == FALSE)
1489                                 break;
1490                         offset += plen;
1491
1492                         dissect_pgmopts(tvb, offset, type_tree, pktname);
1493
1494                         break;
1495                 case PGM_POLL_PCKT:
1496                         type_tree = proto_item_add_subtree(tf, ett_pgm_poll);
1497
1498                         proto_tree_add_uint(type_tree, hf_pgm_poll_sqn, tvb,
1499                                 offset, 4, poll.sqn);
1500                         proto_tree_add_uint(type_tree, hf_pgm_poll_round, tvb,
1501                                 offset+4, 2, poll.round);
1502                         proto_tree_add_uint(type_tree, hf_pgm_poll_subtype, tvb,
1503                                 offset+6, 2, poll.subtype);
1504                         proto_tree_add_uint(type_tree, hf_pgm_poll_pathafi, tvb,
1505                                 offset+8, 2, poll.path_afi);
1506                         proto_tree_add_uint(type_tree, hf_pgm_poll_res, tvb,
1507                                 offset+10, 2, poll.res);
1508
1509                         switch (poll.path_afi) {
1510
1511                         case AFNUM_INET:
1512                                 proto_tree_add_ipv4(type_tree, hf_pgm_poll_path,
1513                                     tvb, offset+12, 4, poll.path);
1514                                 break;
1515
1516                         default:
1517                                 /*
1518                                  * XXX - the header is variable-length,
1519                                  * as the length of the NLA depends on
1520                                  * its AFI.
1521                                  *
1522                                  * However, our structure for it is
1523                                  * fixed-length, and assumes it's a 4-byte
1524                                  * IPv4 address.
1525                                  */
1526                                 break;
1527                         }
1528
1529                         proto_tree_add_uint(type_tree, hf_pgm_poll_backoff_ivl, tvb,
1530                                 offset+16, 4, poll.backoff_ivl);
1531                         proto_tree_add_uint(type_tree, hf_pgm_poll_rand_str, tvb,
1532                                 offset+20, 4, poll.rand_str);
1533                         proto_tree_add_uint(type_tree, hf_pgm_poll_matching_bmask, tvb,
1534                                 offset+24, 4, poll.matching_bmask);
1535
1536                         if ((pgmhdr.opts & PGM_OPT) == FALSE)
1537                                 break;
1538                         offset += plen;
1539
1540                         dissect_pgmopts(tvb, offset, type_tree, pktname);
1541
1542                         break;
1543                 case PGM_POLR_PCKT:
1544                         type_tree = proto_item_add_subtree(tf, ett_pgm_polr);
1545
1546                         proto_tree_add_uint(type_tree, hf_pgm_polr_sqn, tvb,
1547                                 offset, 4, polr.sqn);
1548                         proto_tree_add_uint(type_tree, hf_pgm_polr_round, tvb,
1549                                 offset+4, 2, polr.round);
1550                         proto_tree_add_uint(type_tree, hf_pgm_polr_res, tvb,
1551                                 offset+6, 2, polr.res);
1552
1553                         if ((pgmhdr.opts & PGM_OPT) == FALSE)
1554                                 break;
1555                         offset += plen;
1556
1557                         dissect_pgmopts(tvb, offset, type_tree, pktname);
1558
1559                         break;
1560                 case PGM_ACK_PCKT:
1561                         type_tree = proto_item_add_subtree(tf, ett_pgm_ack);
1562
1563                         proto_tree_add_uint(type_tree, hf_pgm_ack_sqn, tvb,
1564                                 offset, 4, ack.rx_max_sqn);
1565                         proto_tree_add_uint(type_tree, hf_pgm_ack_bitmap, tvb,
1566                                 offset+4, 4, ack.bitmap);
1567
1568                         if ((pgmhdr.opts & PGM_OPT) == FALSE)
1569                                 break;
1570                         offset += plen;
1571
1572                         dissect_pgmopts(tvb, offset, type_tree, pktname);
1573
1574                         break;
1575                 }
1576
1577         }
1578         if (isdata) {
1579                 /*
1580                  * Now see if there are any sub-dissectors, if so call them
1581                  */
1582                 offset = total_size(tvb, &pgmhdr);
1583                 decode_pgm_ports(tvb, offset, pinfo, tree, &pgmhdr);
1584         }
1585         pktname = NULL;
1586 }
1587 static const true_false_string opts_present = {
1588         "Present",
1589         "Not Present"
1590 };
1591
1592 /* Register all the bits needed with the filtering engine */
1593 void
1594 proto_register_pgm(void)
1595 {
1596   static hf_register_info hf[] = {
1597     { &hf_pgm_main_sport,
1598       { "Source Port", "pgm.hdr.sport", FT_UINT16, BASE_DEC,
1599           NULL, 0x0, "", HFILL }},
1600     { &hf_pgm_main_dport,
1601       { "Destination Port", "pgm.hdr.dport", FT_UINT16, BASE_DEC,
1602           NULL, 0x0, "", HFILL }},
1603     { &hf_pgm_main_type,
1604       { "Type", "pgm.hdr.type", FT_UINT8, BASE_HEX,
1605           VALS(type_vals), 0x0, "", HFILL }},
1606     { &hf_pgm_main_opts,
1607       { "Options", "pgm.hdr.opts", FT_UINT8, BASE_HEX,
1608           NULL, 0x0, "", HFILL }},
1609     { &hf_pgm_main_opts_opt,
1610       { "Options", "pgm.hdr.opts.opt", FT_BOOLEAN, BASE_NONE,
1611           TFS(&opts_present), PGM_OPT, "", HFILL }},
1612     { &hf_pgm_main_opts_netsig,
1613       { "Network Significant Options", "pgm.hdr.opts.netsig",
1614           FT_BOOLEAN, BASE_NONE,
1615           TFS(&opts_present), PGM_OPT_NETSIG, "", HFILL }},
1616     { &hf_pgm_main_opts_varlen,
1617       { "Variable length Parity Packet Option", "pgm.hdr.opts.varlen",
1618           FT_BOOLEAN, BASE_NONE,
1619           TFS(&opts_present), PGM_OPT_VAR_PKTLEN, "", HFILL }},
1620     { &hf_pgm_main_opts_parity,
1621       { "Parity", "pgm.hdr.opts.parity", FT_BOOLEAN, BASE_NONE,
1622           TFS(&opts_present), PGM_OPT_PARITY, "", HFILL }},
1623     { &hf_pgm_main_cksum,
1624       { "Checksum", "pgm.hdr.cksum", FT_UINT16, BASE_HEX,
1625         NULL, 0x0, "", HFILL }},
1626     { &hf_pgm_main_cksum_bad,
1627       { "Bad Checksum", "pgm.hdr.cksum_bad", FT_BOOLEAN, BASE_NONE,
1628         NULL, 0x0, "", HFILL }},
1629     { &hf_pgm_main_gsi,
1630       { "Global Source Identifier", "pgm.hdr.gsi", FT_BYTES, BASE_HEX,
1631           NULL, 0x0, "", HFILL }},
1632     { &hf_pgm_main_tsdulen,
1633       { "Transport Service Data Unit Length", "pgm.hdr.tsdulen", FT_UINT16,
1634           BASE_DEC, NULL, 0x0, "", HFILL }},
1635     { &hf_pgm_spm_sqn,
1636       { "Sequence number", "pgm.spm.sqn", FT_UINT32, BASE_HEX,
1637           NULL, 0x0, "", HFILL }},
1638     { &hf_pgm_spm_trail,
1639       { "Trailing Edge Sequence Number", "pgm.spm.trail", FT_UINT32, BASE_HEX,
1640           NULL, 0x0, "", HFILL }},
1641     { &hf_pgm_spm_lead,
1642       { "Leading Edge Sequence Number", "pgm.spm.lead", FT_UINT32, BASE_HEX,
1643           NULL, 0x0, "", HFILL }},
1644     { &hf_pgm_spm_pathafi,
1645       { "Path NLA AFI", "pgm.spm.pathafi", FT_UINT16, BASE_DEC,
1646           VALS(afn_vals), 0x0, "", HFILL }},
1647     { &hf_pgm_spm_res,
1648       { "Reserved", "pgm.spm.res", FT_UINT16, BASE_HEX,
1649           NULL, 0x0, "", HFILL }},
1650     { &hf_pgm_spm_path,
1651       { "Path NLA", "pgm.spm.path", FT_IPv4, BASE_NONE,
1652           NULL, 0x0, "", HFILL }},
1653     { &hf_pgm_data_sqn,
1654       { "Data Packet Sequence Number", "pgm.data.sqn", FT_UINT32, BASE_HEX,
1655           NULL, 0x0, "", HFILL }},
1656     { &hf_pgm_data_trail,
1657       { "Trailing Edge Sequence Number", "pgm.data.trail", FT_UINT32, BASE_HEX,
1658           NULL, 0x0, "", HFILL }},
1659     { &hf_pgm_nak_sqn,
1660       { "Requested Sequence Number", "pgm.nak.sqn", FT_UINT32, BASE_HEX,
1661           NULL, 0x0, "", HFILL }},
1662     { &hf_pgm_nak_srcafi,
1663       { "Source NLA AFI", "pgm.nak.srcafi", FT_UINT16, BASE_DEC,
1664           VALS(afn_vals), 0x0, "", HFILL }},
1665     { &hf_pgm_nak_srcres,
1666       { "Reserved", "pgm.nak.srcres", FT_UINT16, BASE_HEX,
1667           NULL, 0x0, "", HFILL }},
1668     { &hf_pgm_nak_src,
1669       { "Source NLA", "pgm.nak.src", FT_IPv4, BASE_NONE,
1670           NULL, 0x0, "", HFILL }},
1671     { &hf_pgm_nak_grpafi,
1672       { "Multicast Group AFI", "pgm.nak.grpafi", FT_UINT16, BASE_DEC,
1673           VALS(afn_vals), 0x0, "", HFILL }},
1674     { &hf_pgm_nak_grpres,
1675       { "Reserved", "pgm.nak.grpres", FT_UINT16, BASE_HEX,
1676           NULL, 0x0, "", HFILL }},
1677     { &hf_pgm_nak_grp,
1678       { "Multicast Group NLA", "pgm.nak.grp", FT_IPv4, BASE_NONE,
1679           NULL, 0x0, "", HFILL }},
1680     { &hf_pgm_poll_sqn,
1681       { "Sequence Number", "pgm.poll.sqn", FT_UINT32, BASE_HEX,
1682           NULL, 0x0, "", HFILL }},
1683     { &hf_pgm_poll_round,
1684       { "Round", "pgm.poll.round", FT_UINT16, BASE_DEC,
1685           NULL, 0x0, "", HFILL }},
1686     { &hf_pgm_poll_subtype,
1687       { "Subtype", "pgm.poll.subtype", FT_UINT16, BASE_HEX,
1688           VALS(poll_subtype_vals), 0x0, "", HFILL }},
1689     { &hf_pgm_poll_pathafi,
1690       { "Path NLA AFI", "pgm.poll.pathafi", FT_UINT16, BASE_DEC,
1691           VALS(afn_vals), 0x0, "", HFILL }},
1692     { &hf_pgm_poll_res,
1693       { "Reserved", "pgm.poll.res", FT_UINT16, BASE_HEX,
1694           NULL, 0x0, "", HFILL }},
1695     { &hf_pgm_poll_path,
1696       { "Path NLA", "pgm.poll.path", FT_IPv4, BASE_NONE,
1697           NULL, 0x0, "", HFILL }},
1698     { &hf_pgm_poll_backoff_ivl,
1699       { "Back-off Interval", "pgm.poll.backoff_ivl", FT_UINT32, BASE_DEC,
1700           NULL, 0x0, "", HFILL }},
1701     { &hf_pgm_poll_rand_str,
1702       { "Random String", "pgm.poll.rand_str", FT_UINT32, BASE_HEX,
1703           NULL, 0x0, "", HFILL }},
1704     { &hf_pgm_poll_matching_bmask,
1705       { "Matching Bitmask", "pgm.poll.matching_bmask", FT_UINT32, BASE_HEX,
1706           NULL, 0x0, "", HFILL }},
1707     { &hf_pgm_polr_sqn,
1708       { "Sequence Number", "pgm.polr.sqn", FT_UINT32, BASE_HEX,
1709           NULL, 0x0, "", HFILL }},
1710     { &hf_pgm_polr_round,
1711       { "Round", "pgm.polr.round", FT_UINT16, BASE_DEC,
1712           NULL, 0x0, "", HFILL }},
1713     { &hf_pgm_polr_res,
1714       { "Reserved", "pgm.polr.res", FT_UINT16, BASE_HEX,
1715           NULL, 0x0, "", HFILL }},
1716     { &hf_pgm_ack_sqn,
1717       { "Maximum Received Sequence Number", "pgm.ack.maxsqn", FT_UINT32,
1718           BASE_HEX, NULL, 0x0, "", HFILL }},
1719     { &hf_pgm_ack_bitmap,
1720       { "Packet Bitmap", "pgm.ack.bitmap", FT_UINT32, BASE_HEX,
1721           NULL, 0x0, "", HFILL }},
1722     { &hf_pgm_opt_type,
1723       { "Type", "pgm.opts.type", FT_UINT8, BASE_HEX,
1724           VALS(opt_vals), 0x0, "", HFILL }},
1725     { &hf_pgm_opt_len,
1726       { "Length", "pgm.opts.len", FT_UINT8, BASE_DEC,
1727           NULL, 0x0, "", HFILL }},
1728     { &hf_pgm_opt_tlen,
1729       { "Total Length", "pgm.opts.tlen", FT_UINT16, BASE_DEC,
1730           NULL, 0x0, "", HFILL }},
1731     { &hf_pgm_genopt_type,
1732       { "Type", "pgm.genopts.type", FT_UINT8, BASE_HEX,
1733           VALS(opt_vals), 0x0, "", HFILL }},
1734     { &hf_pgm_genopt_len,
1735       { "Length", "pgm.genopts.len", FT_UINT8, BASE_DEC,
1736           NULL, 0x0, "", HFILL }},
1737     { &hf_pgm_genopt_opx,
1738       { "Option Extensibility Bits", "pgm.genopts.opx", FT_UINT8, BASE_HEX,
1739           VALS(opx_vals), 0x0, "", HFILL }},
1740     { &hf_pgm_opt_parity_prm_po,
1741       { "Parity Parameters", "pgm.opts.parity_prm.op", FT_UINT8, BASE_HEX,
1742           NULL, 0x0, "", HFILL }},
1743     { &hf_pgm_opt_parity_prm_prmtgsz,
1744       { "Transmission Group Size", "pgm.opts.parity_prm.prm_grp",
1745           FT_UINT32, BASE_HEX,
1746           NULL, 0x0, "", HFILL }},
1747     { &hf_pgm_opt_join_res,
1748       { "Reserved", "pgm.opts.join.res", FT_UINT8, BASE_HEX,
1749           NULL, 0x0, "", HFILL }},
1750     { &hf_pgm_opt_join_minjoin,
1751       { "Minimum Sequence Number", "pgm.opts.join.min_join",
1752           FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
1753     { &hf_pgm_opt_parity_grp_res,
1754       { "Reserved", "pgm.opts.parity_prm.op", FT_UINT8, BASE_HEX,
1755           NULL, 0x0, "", HFILL }},
1756     { &hf_pgm_opt_parity_grp_prmgrp,
1757       { "Transmission Group Size", "pgm.opts.parity_prm.prm_grp",
1758           FT_UINT32, BASE_HEX,
1759           NULL, 0x0, "", HFILL }},
1760     { &hf_pgm_opt_nak_res,
1761       { "Reserved", "pgm.opts.nak.op", FT_UINT8, BASE_HEX,
1762           NULL, 0x0, "", HFILL }},
1763     { &hf_pgm_opt_nak_list,
1764       { "List", "pgm.opts.nak.list", FT_BYTES, BASE_NONE,
1765           NULL, 0x0, "", HFILL }},
1766     { &hf_pgm_opt_ccdata_res,
1767       { "Reserved", "pgm.opts.ccdata.res", FT_UINT8, BASE_DEC,
1768           NULL, 0x0, "", HFILL }},
1769     { &hf_pgm_opt_ccdata_tsp,
1770       { "Time Stamp", "pgm.opts.ccdata.tstamp", FT_UINT16, BASE_HEX,
1771           NULL, 0x0, "", HFILL }},
1772     { &hf_pgm_opt_ccdata_afi,
1773       { "Acker AFI", "pgm.opts.ccdata.afi", FT_UINT16, BASE_DEC,
1774           VALS(afn_vals), 0x0, "", HFILL }},
1775     { &hf_pgm_opt_ccdata_res2,
1776       { "Reserved", "pgm.opts.ccdata.res2", FT_UINT16, BASE_DEC,
1777           NULL, 0x0, "", HFILL }},
1778     { &hf_pgm_opt_ccdata_acker,
1779       { "Acker", "pgm.opts.ccdata.acker", FT_IPv4, BASE_NONE,
1780           NULL, 0x0, "", HFILL }},
1781     { &hf_pgm_opt_ccfeedbk_res,
1782       { "Reserved", "pgm.opts.ccdata.res", FT_UINT8, BASE_DEC,
1783           NULL, 0x0, "", HFILL }},
1784     { &hf_pgm_opt_ccfeedbk_tsp,
1785       { "Time Stamp", "pgm.opts.ccdata.tstamp", FT_UINT16, BASE_HEX,
1786           NULL, 0x0, "", HFILL }},
1787     { &hf_pgm_opt_ccfeedbk_afi,
1788       { "Acker AFI", "pgm.opts.ccdata.afi", FT_UINT16, BASE_DEC,
1789           VALS(afn_vals), 0x0, "", HFILL }},
1790     { &hf_pgm_opt_ccfeedbk_lossrate,
1791       { "Loss Rate", "pgm.opts.ccdata.lossrate", FT_UINT16, BASE_HEX,
1792           NULL, 0x0, "", HFILL }},
1793     { &hf_pgm_opt_ccfeedbk_acker,
1794       { "Acker", "pgm.opts.ccdata.acker", FT_IPv4, BASE_NONE,
1795           NULL, 0x0, "", HFILL }},
1796     { &hf_pgm_opt_nak_bo_ivl_res,
1797       { "Reserved", "pgm.opts.nak_bo_ivl.res", FT_UINT8, BASE_HEX,
1798           NULL, 0x0, "", HFILL }},
1799     { &hf_pgm_opt_nak_bo_ivl_bo_ivl,
1800       { "Back-off Interval", "pgm.opts.nak_bo_ivl.bo_ivl", FT_UINT32, BASE_DEC,
1801           NULL, 0x0, "", HFILL }},
1802     { &hf_pgm_opt_nak_bo_ivl_bo_ivl_sqn,
1803       { "Back-off Interval Sequence Number", "pgm.opts.nak_bo_ivl.bo_ivl_sqn", FT_UINT32, BASE_HEX,
1804           NULL, 0x0, "", HFILL }},
1805     { &hf_pgm_opt_nak_bo_rng_res,
1806       { "Reserved", "pgm.opts.nak_bo_rng.res", FT_UINT8, BASE_HEX,
1807           NULL, 0x0, "", HFILL }},
1808     { &hf_pgm_opt_nak_bo_rng_min_bo_ivl,
1809       { "Min Back-off Interval", "pgm.opts.nak_bo_rng.min_bo_ivl", FT_UINT32, BASE_DEC,
1810           NULL, 0x0, "", HFILL }},
1811     { &hf_pgm_opt_nak_bo_rng_max_bo_ivl,
1812       { "Max Back-off Interval", "pgm.opts.nak_bo_rng.max_bo_ivl", FT_UINT32, BASE_DEC,
1813           NULL, 0x0, "", HFILL }},
1814     { &hf_pgm_opt_redirect_res,
1815       { "Reserved", "pgm.opts.redirect.res", FT_UINT8, BASE_DEC,
1816           NULL, 0x0, "", HFILL }},
1817     { &hf_pgm_opt_redirect_afi,
1818       { "DLR AFI", "pgm.opts.redirect.afi", FT_UINT16, BASE_DEC,
1819           VALS(afn_vals), 0x0, "", HFILL }},
1820     { &hf_pgm_opt_redirect_res2,
1821       { "Reserved", "pgm.opts.redirect.res2", FT_UINT16, BASE_HEX,
1822           NULL, 0x0, "", HFILL }},
1823     { &hf_pgm_opt_redirect_dlr,
1824       { "DLR", "pgm.opts.redirect.dlr", FT_IPv4, BASE_NONE,
1825           NULL, 0x0, "", HFILL }},
1826     { &hf_pgm_opt_fragment_res,
1827       { "Reserved", "pgm.opts.fragment.res", FT_UINT8, BASE_HEX,
1828           NULL, 0x0, "", HFILL }},
1829     { &hf_pgm_opt_fragment_first_sqn,
1830       { "First Sequence Number", "pgm.opts.fragment.first_sqn", FT_UINT32, BASE_HEX,
1831           NULL, 0x0, "", HFILL }},
1832     { &hf_pgm_opt_fragment_offset,
1833       { "Fragment Offset", "pgm.opts.fragment.fragment_offset", FT_UINT32, BASE_DEC,
1834           NULL, 0x0, "", HFILL }},
1835     { &hf_pgm_opt_fragment_total_length,
1836       { "Total Length", "pgm.opts.fragment.total_length", FT_UINT32, BASE_DEC,
1837           NULL, 0x0, "", HFILL }},
1838   };
1839   static gint *ett[] = {
1840     &ett_pgm,
1841         &ett_pgm_optbits,
1842         &ett_pgm_spm,
1843         &ett_pgm_data,
1844         &ett_pgm_nak,
1845         &ett_pgm_poll,
1846         &ett_pgm_polr,
1847         &ett_pgm_ack,
1848         &ett_pgm_opts,
1849         &ett_pgm_opts_join,
1850         &ett_pgm_opts_parityprm,
1851         &ett_pgm_opts_paritygrp,
1852         &ett_pgm_opts_naklist,
1853         &ett_pgm_opts_ccdata,
1854         &ett_pgm_opts_nak_bo_ivl,
1855         &ett_pgm_opts_nak_bo_rng,
1856         &ett_pgm_opts_redirect,
1857         &ett_pgm_opts_fragment,
1858   };
1859   module_t *pgm_module;
1860
1861   proto_pgm = proto_register_protocol("Pragmatic General Multicast",
1862                                        "PGM", "pgm");
1863
1864   proto_register_field_array(proto_pgm, hf, array_length(hf));
1865   proto_register_subtree_array(ett, array_length(ett));
1866
1867         /* subdissector code */
1868   subdissector_table = register_dissector_table("pgm.port",
1869                 "PGM port", FT_UINT16, BASE_DEC);
1870   register_heur_dissector_list("pgm", &heur_subdissector_list);
1871
1872   /*
1873    * Register configuration preferences for UDP encapsulation
1874    * (Note: Initially the ports are set to zero so the
1875    *        dissecting of PGM encapsulated in UPD packets
1876    *        is off by default)
1877    */
1878    pgm_module = prefs_register_protocol(proto_pgm, proto_rereg_pgm);
1879
1880    prefs_register_bool_preference(pgm_module, "check_checksum",
1881             "Check the validity of the PGM checksum when possible",
1882                 "Whether to check the validity of the PGM checksum",
1883             &pgm_check_checksum);
1884
1885    prefs_register_uint_preference(pgm_module, "udp.encap_ucast_port",
1886                 "PGM Encap Unicast Port (standard is 3055)",
1887                 "PGM Encap is PGM packets encapsulated in UDP packets"
1888                 " (Note: This option is off, i.e. port is 0, by default)",
1889                 10, &udp_encap_ucast_port);
1890    old_encap_ucast_port = udp_encap_ucast_port;
1891
1892    prefs_register_uint_preference(pgm_module, "udp.encap_mcast_port",
1893                 "PGM Encap Multicast Port (standard is 3056)",
1894                 "PGM Encap is PGM packets encapsulated in UDP packets"
1895                 " (Note: This option is off, i.e. port is 0, by default)",
1896                 10, &udp_encap_mcast_port);
1897
1898    old_encap_mcast_port = udp_encap_mcast_port;
1899 }
1900
1901 static dissector_handle_t pgm_handle;
1902
1903 /* The registration hand-off routine */
1904 void
1905 proto_reg_handoff_pgm(void)
1906 {
1907   pgm_handle = create_dissector_handle(dissect_pgm, proto_pgm);
1908
1909   /*
1910    * Set up PGM Encap dissecting, which is off by default
1911    */
1912   dissector_add("udp.port", udp_encap_ucast_port, pgm_handle);
1913   dissector_add("udp.port", udp_encap_mcast_port, pgm_handle);
1914
1915   dissector_add("ip.proto", IP_PROTO_PGM, pgm_handle);
1916
1917   data_handle = find_dissector("data");
1918 }
1919
1920 static void
1921 proto_rereg_pgm(void)
1922 {
1923         /*
1924          * Remove the old ones
1925          */
1926         dissector_delete("udp.port", old_encap_ucast_port, pgm_handle);
1927         dissector_delete("udp.port", old_encap_mcast_port, pgm_handle);
1928
1929         /*
1930          * Set the new ones
1931          */
1932         dissector_add("udp.port", udp_encap_ucast_port, pgm_handle);
1933         dissector_add("udp.port", udp_encap_mcast_port, pgm_handle);
1934 }