cb8605a3d3256a34bb71f182a3e7428f207e86e2
[obnox/wireshark/wip.git] / epan / dissectors / packet-pim.c
1 /* packet-pim.c
2  * Routines for PIM disassembly
3  * (c) Copyright Jun-ichiro itojun Hagino <itojun@itojun.org>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <glib.h>
31
32 #include <epan/packet.h>
33 #include <epan/ipproto.h>
34 #include <epan/afn.h>
35 #include <epan/in_cksum.h>
36 #include "packet-pim.h"
37
38 #define PIM_TYPE(x)     ((x) & 0x0f)
39 #define PIM_VER(x)      (((x) & 0xf0) >> 4)
40
41 enum pimv2_addrtype {
42     pimv2_unicast, pimv2_group, pimv2_source
43 };
44
45 static int proto_pim = -1;
46 static int hf_pim_version = -1;
47 static int hf_pim_type = -1;
48 static int hf_pim_code = -1;
49 static int hf_pim_cksum = -1;
50 static int hf_pim_res_bytes = -1;
51 /* PIM Hello options (RFC 4601, section 4.9.2 and RFC 3973, section 4.7.5) */
52 static int hf_pim_optiontype = -1;
53 static int hf_pim_optionlength = -1;
54 static int hf_pim_optionvalue = -1;
55 static int hf_pim_mode = -1;
56 static int hf_pim_holdtime = -1;
57 static int hf_pim_numgroups = -1;
58 static int hf_pim_numjoins = -1;
59 static int hf_pim_numprunes = -1;
60 static int hf_pim_t = -1;
61 static int hf_pim_propagation_delay = -1;
62 static int hf_pim_override_interval = -1;
63 static int hf_pim_dr_priority = -1;
64 static int hf_pim_generation_id = -1;
65 static int hf_pim_state_refresh_version = -1;
66 static int hf_pim_state_refresh_interval = -1;
67 static int hf_pim_state_refresh_reserved = -1;
68 /* Assert fields */
69 static int hf_pim_rpt = -1;
70 static int hf_pim_metric_pref = -1;
71 static int hf_pim_metric = -1;
72
73 static gint ett_pim = -1;
74 static gint ett_pim_opts = -1;
75 static gint ett_pim_opt = -1;
76
77 static dissector_handle_t ip_handle;
78 static dissector_handle_t ipv6_handle;
79
80 /*
81  * For PIM v1, see
82  *
83  *      ftp://ftp.usc.edu/pub/csinfo/tech-reports/papers/95-599.ps.Z
84  *
85  * NOTE: There is still some doubt that this is THE definitive PIMv1
86  *       specification.  Of note, the type1vals entry, { 8, "Mode" }, does
87  *       not appear as a valid code in the referenced document above.
88  *
89  *       This one is likely closer to the last PIMv1 spec:
90  *       http://tools.ietf.org/id/draft-ietf-idmr-pim-spec-02.txt
91  */
92 static const char *
93 dissect_pimv1_addr(tvbuff_t *tvb, int offset) {
94     guint16 flags_masklen;
95
96     flags_masklen = tvb_get_ntohs(tvb, offset);
97     if (flags_masklen & 0x0180) {
98         return ep_strdup_printf("(%s%s%s) ",
99                                 flags_masklen & 0x0100 ? "S" : "",
100                                 flags_masklen & 0x0080 ? "W" : "",
101                                 flags_masklen & 0x0040 ? "R" : "");
102     } else {
103         return ep_strdup_printf("%s/%u",
104                                 tvb_ip_to_str(tvb, offset + 2), flags_masklen & 0x3f);
105     }
106 }
107
108 static const value_string type1vals[] = {
109     { 0, "Query" },
110     { 1, "Register" },
111     { 2, "Register-stop" },
112     { 3, "Join/Prune" },
113     { 4, "RP-Reachable" },
114     { 5, "Assert" },
115     { 6, "Graft" },
116     { 7, "Graft-Ack" },
117     { 8, "Mode" },
118     { 0, NULL },
119 };
120
121 static const value_string pimv1_modevals[] = {
122     { 0, "Dense" },
123     { 1, "Sparse" },
124     { 2, "Sparse-Dense" },
125     { 0, NULL }
126 };
127
128 /* This function is only called from the IGMP dissector */
129 int
130 dissect_pimv1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
131               int offset) {
132     guint8 pim_type;
133     guint8 pim_ver;
134     guint length, pim_length;
135     guint16 pim_cksum, computed_cksum;
136     vec_t cksum_vec[1];
137     proto_tree *pim_tree = NULL;
138     proto_item *ti;
139     proto_tree *pimopt_tree = NULL;
140     proto_item *tiopt;
141
142     if (!proto_is_protocol_enabled(find_protocol_by_id(proto_pim))) {
143         /*
144          * We are not enabled; skip entire packet to be nice to the
145          * IGMP layer (so clicking on IGMP will display the data).
146          */
147         return offset+tvb_length_remaining(tvb, offset);
148     }
149
150     col_set_str(pinfo->cinfo, COL_PROTOCOL, "PIMv1");
151     col_clear(pinfo->cinfo, COL_INFO);
152
153     ti = proto_tree_add_item(tree, proto_pim, tvb, offset, -1, FALSE);
154     pim_tree = proto_item_add_subtree(ti, ett_pim);
155
156     /* Put IGMP type, 0x14, into the tree */
157     proto_tree_add_text(pim_tree, tvb, offset, 1,
158                         "Type: PIM (0x14)");
159     offset += 1;
160
161     pim_type = tvb_get_guint8(tvb, offset);
162     if (check_col(pinfo->cinfo, COL_INFO))
163         col_add_str(pinfo->cinfo, COL_INFO,
164                     val_to_str(pim_type, type1vals, "Unknown (%u)"));
165
166     proto_tree_add_uint(pim_tree, hf_pim_code, tvb, offset, 1, pim_type);
167     offset += 1;
168
169     pim_cksum = tvb_get_ntohs(tvb, offset);
170     pim_ver = PIM_VER(tvb_get_guint8(tvb, offset + 2));
171     if (pim_ver != 1) {
172         /*
173          * Not PIMv1 - what gives?
174          */
175         proto_tree_add_uint(pim_tree, hf_pim_cksum, tvb,
176                             offset, 2, pim_cksum);
177
178         offset += 2;
179         proto_tree_add_item(pim_tree, hf_pim_version, tvb, offset, 1, ENC_BIG_ENDIAN);
180         return offset+tvb_length_remaining(tvb, offset);
181     }
182
183     /*
184      * Well, it's PIM v1, so we can check whether this is a
185      * Register message, and thus can figure out how much to
186      * checksum and whether to make the columns read-only.
187      */
188     length = tvb_length(tvb);
189     if (pim_type == 1) {
190         /*
191          * Register message - the PIM header is 8 bytes long.
192          * Also set the columns non-writable. Otherwise the IPv4 or
193          * IPv6 dissector for the encapsulated packet that caused
194          * this register will overwrite the PIM info in the columns.
195          */
196         pim_length = 8;
197         col_set_writable(pinfo->cinfo, FALSE);
198     } else {
199         /*
200          * Other message - checksum the entire packet.
201          */
202         pim_length = tvb_reported_length(tvb);
203     }
204
205     if (!pinfo->fragmented && length >= pim_length) {
206         /*
207          * The packet isn't part of a fragmented datagram and isn't
208          * truncated, so we can checksum it.
209          */
210         cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, pim_length);
211         cksum_vec[0].len = pim_length;
212         computed_cksum = in_cksum(&cksum_vec[0], 1);
213         if (computed_cksum == 0) {
214             proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb,
215                                        offset, 2, pim_cksum,
216                                        "Checksum: 0x%04x [correct]",
217                                        pim_cksum);
218         } else {
219             proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb,
220                                        offset, 2, pim_cksum,
221                                        "Checksum: 0x%04x [incorrect, should be 0x%04x]",
222                                        pim_cksum, in_cksum_shouldbe(pim_cksum, computed_cksum));
223         }
224     } else {
225         proto_tree_add_uint(pim_tree, hf_pim_cksum, tvb,
226                             offset, 2, pim_cksum);
227     }
228     offset += 2;
229
230     proto_tree_add_item(pim_tree, hf_pim_version, tvb, offset, 1, ENC_BIG_ENDIAN);
231     offset += 1;
232
233     offset += 3;        /* skip reserved stuff */
234
235     if (tvb_reported_length_remaining(tvb, offset) > 0) {
236         tiopt = proto_tree_add_text(pim_tree, tvb, offset, -1, "PIM options");
237         pimopt_tree = proto_item_add_subtree(tiopt, ett_pim_opts);
238     } else
239         goto done;
240
241     /* version 1 decoder */
242     switch (pim_type) {
243     case 0:     /* query */
244     {
245         guint16 holdtime;
246
247         proto_tree_add_item(pimopt_tree, hf_pim_mode, tvb, offset, 1, ENC_BIG_ENDIAN);
248         offset += 2;
249
250         holdtime = tvb_get_ntohs(tvb, offset);
251         proto_tree_add_uint_format(pimopt_tree, hf_pim_holdtime, tvb,
252                                    offset, 2, holdtime,
253                                    "Holdtime: %us %s", holdtime,
254                                    holdtime == 0xffff ? "(infinity)": "");
255         offset += 2;
256         break;
257     }
258
259     case 1:     /* register */
260     {
261         guint8 v_hl;
262         tvbuff_t *next_tvb;
263
264         /*
265          * The rest of the packet is a multicast data packet.
266          */
267         next_tvb = tvb_new_subset_remaining(tvb, offset);
268
269         /*
270          * It's an IP packet - determine whether it's IPv4 or IPv6.
271          */
272         v_hl = tvb_get_guint8(tvb, offset);
273         switch((v_hl & 0xf0) >> 4) {
274         case 0:     /* Null-Register dummy header.
275                      * Has the same address family as the encapsulating PIM packet,
276                      * e.g. an IPv6 data packet is encapsulated in IPv6 PIM packet.
277                      */
278             if (pinfo->src.type == AT_IPv4) {
279                 proto_tree_add_text(pimopt_tree, tvb, offset, -1,
280                                     "IPv4 dummy header");
281                 proto_tree_add_text(pimopt_tree, tvb, offset + 12, 4,
282                                     "Source: %s",
283                                     tvb_ip_to_str(tvb, offset + 12));
284                 proto_tree_add_text(pimopt_tree, tvb, offset + 16, 4,
285                                     "Group: %s",
286                                     tvb_ip_to_str(tvb, offset + 16));
287             } else if (pinfo->src.type == AT_IPv6) {
288                 proto_tree_add_text(pimopt_tree, tvb, offset, -1,
289                                     "IPv6 dummy header");
290                 proto_tree_add_text(pimopt_tree, tvb,
291                                     offset + 8, 16,
292                                     "Source: %s",
293                                     tvb_ip6_to_str(tvb, offset + 8));
294                 proto_tree_add_text(pimopt_tree, tvb,
295                                     offset + 8 + 16, 16,
296                                     "Group: %s",
297                                     tvb_ip6_to_str(tvb, offset + 8));
298             } else
299                 proto_tree_add_text(pimopt_tree, tvb, offset, -1,
300                                     "Dummy header for an unknown protocol");
301             break;
302         case 4: /* IPv4 */
303 #if 0
304             call_dissector(ip_handle, next_tvb, pinfo, tree);
305 #else
306             call_dissector(ip_handle, next_tvb, pinfo, pimopt_tree);
307 #endif
308             break;
309         case 6: /* IPv6 */
310 #if 0
311             call_dissector(ipv6_handle, next_tvb, pinfo, tree);
312 #else
313             call_dissector(ipv6_handle, next_tvb, pinfo, pimopt_tree);
314 #endif
315             break;
316         default:
317             proto_tree_add_text(pimopt_tree, tvb, offset, -1,
318                                 "Unknown IP version %d", (v_hl & 0xf0) >> 4);
319             break;
320         }
321         break;
322     }
323
324     case 2:     /* register-stop */
325     {
326         proto_tree_add_text(pimopt_tree, tvb, offset, 4,
327                             "Group: %s",
328                             tvb_ip_to_str(tvb, offset));
329         offset += 4;
330         proto_tree_add_text(pimopt_tree, tvb, offset, 4,
331                             "Source: %s",
332                             tvb_ip_to_str(tvb, offset));
333         offset += 4;
334         break;
335     }
336
337     case 3:     /* join/prune */
338     case 6:     /* graft */
339     case 7:     /* graft-ack */
340     {
341         int off;
342         const char *s;
343         int ngroup, i, njoin, nprune, j;
344         guint16 holdtime;
345         guint8 mask_len;
346         guint8 adr_len;
347         proto_tree *grouptree = NULL;
348         proto_item *tigroup;
349         proto_tree *subtree = NULL;
350         proto_item *tisub;
351
352         proto_tree_add_text(pimopt_tree, tvb, offset, 4,
353                             "Upstream-neighbor: %s",
354                             tvb_ip_to_str(tvb, offset));
355         offset += 4;
356
357         offset += 2;    /* skip reserved stuff */
358
359         holdtime = tvb_get_ntohs(tvb, offset);
360         proto_tree_add_uint_format(pimopt_tree, hf_pim_holdtime, tvb,
361                                    offset, 2, holdtime,
362                                    "Holdtime: %us %s", holdtime,
363                                    holdtime == 0xffff ? "(infinity)": "");
364         offset += 2;
365
366         offset += 1;    /* skip reserved stuff */
367
368         mask_len = tvb_get_guint8(tvb, offset);
369         proto_tree_add_text(pimopt_tree, tvb, offset, 1,
370                             "Mask length: %u", mask_len);
371         offset += 1;
372
373         adr_len = tvb_get_guint8(tvb, offset);
374         proto_tree_add_text(pimopt_tree, tvb, offset, 1,
375                             "Address length: %u", adr_len);
376         offset += 1;
377
378         ngroup = tvb_get_guint8(tvb, offset);
379         proto_tree_add_item(pimopt_tree, hf_pim_numgroups, tvb, offset, 1, ENC_BIG_ENDIAN);
380         offset += 1;
381
382         for (i = 0; i < ngroup; i++) {
383             /*
384              * XXX - does the group address have the length "adr_len"
385              * and the group mask the length "mask_len"?
386              */
387             tigroup = proto_tree_add_text(pimopt_tree, tvb, offset, 4,
388                                           "Group %d: %s", i,
389                                           tvb_ip_to_str(tvb, offset));
390             grouptree = proto_item_add_subtree(tigroup, ett_pim);
391             offset += 4;
392
393             proto_tree_add_text(grouptree, tvb, offset, 4,
394                                 "Group %d Mask: %s", i,
395                                 tvb_ip_to_str(tvb, offset));
396             offset += 4;
397
398             njoin = tvb_get_ntohs(tvb, offset);
399             nprune = tvb_get_ntohs(tvb, offset + 2);
400             tisub = proto_tree_add_item(grouptree, hf_pim_numjoins, tvb,
401                                         offset, 2, ENC_BIG_ENDIAN);
402             subtree = proto_item_add_subtree(tisub, ett_pim);
403             off = offset + 4;
404             for (j = 0; j < njoin; j++) {
405                 s = dissect_pimv1_addr(tvb, off);
406                 proto_tree_add_text(subtree, tvb, off, 6,
407                                     "IP address: %s", s);
408                 off += 6;
409             }
410
411             tisub = proto_tree_add_item(grouptree, hf_pim_numprunes, tvb,
412                                         offset + 2, 2, ENC_BIG_ENDIAN);
413             subtree = proto_item_add_subtree(tisub, ett_pim);
414             for (j = 0; j < nprune; j++) {
415                 s = dissect_pimv1_addr(tvb, off);
416                 proto_tree_add_text(subtree, tvb, off, 6,
417                                     "IP address: %s", s);
418                 off += 6;
419             }
420             offset = off;
421         }
422         break;
423     }
424
425     case 4:     /* rp-reachability */
426     {
427         guint16 holdtime;
428
429         proto_tree_add_text(pimopt_tree, tvb, offset, 4,
430                             "Group Address: %s",
431                             tvb_ip_to_str(tvb, offset));
432         offset += 4;
433
434         proto_tree_add_text(pimopt_tree, tvb, offset, 4,
435                             "Group Mask: %s",
436                             tvb_ip_to_str(tvb, offset));
437         offset += 4;
438
439         proto_tree_add_text(pimopt_tree, tvb, offset, 4,
440                             "RP Address: %s",
441                             tvb_ip_to_str(tvb, offset));
442         offset += 4;
443
444         offset += 2;    /* skip reserved stuff */
445
446         holdtime = tvb_get_ntohs(tvb, offset);
447         proto_tree_add_uint_format(pimopt_tree, hf_pim_holdtime, tvb,
448                                    offset, 2, holdtime,
449                                    "Holdtime: %us %s", holdtime,
450                                    holdtime == 0xffff ? "(infinity)": "");
451         offset += 2;
452         break;
453     }
454
455     case 5:     /* assert */
456     {
457         guint32 pref;
458
459         proto_tree_add_text(pimopt_tree, tvb, offset, 4,
460                             "Group Address: %s",
461                             tvb_ip_to_str(tvb, offset));
462         offset += 4;
463
464         proto_tree_add_text(pimopt_tree, tvb, offset, 4,
465                             "Group Mask: %s",
466                             tvb_ip_to_str(tvb, offset));
467         offset += 4;
468
469         proto_tree_add_item(pimopt_tree, hf_pim_rpt, tvb, offset, 1, ENC_BIG_ENDIAN);
470         pref = tvb_get_ntohl(tvb, offset) & 0x7fffffff;
471         proto_tree_add_uint_format(pimopt_tree, hf_pim_metric_pref, tvb,
472                                    offset, 4, pref,
473                                    "Metric Preference: %u", pref);
474         offset += 4;
475
476         proto_tree_add_item(pimopt_tree, hf_pim_metric, tvb, offset, 4, ENC_BIG_ENDIAN);
477         offset += 4;
478         break;
479     }
480
481     default:
482         break;
483     }
484 done:;
485
486     return offset+tvb_length_remaining(tvb, offset);
487 }
488
489 static const char *
490 dissect_pim_addr(tvbuff_t *tvb, int offset, enum pimv2_addrtype at,
491                  int *advance) {
492     emem_strbuf_t *strbuf;
493     guint8 af;
494     guint8 et;
495     guint8 flags;
496     guint8 mask_len;
497     int len = 0;
498
499     af = tvb_get_guint8(tvb, offset);
500     if (af != AFNUM_INET && af != AFNUM_INET6) {
501         /*
502          * We don't handle the other formats, and addresses don't include
503          * a length field, so we can't even show them as raw bytes.
504          */
505         return NULL;
506     }
507
508     et = tvb_get_guint8(tvb, offset + 1);
509     if (et != 0) {
510         /*
511          * The only defined encoding type is 0, for the native encoding;
512          * again, as addresses don't include a length field, we can't
513          * even show addresses with a different encoding type as raw
514          * bytes.
515          */
516         return NULL;
517     }
518
519     strbuf = ep_strbuf_new_label(NULL);
520     switch (at) {
521     case pimv2_unicast:
522         switch (af) {
523         case AFNUM_INET:
524             len = 4;
525             ep_strbuf_printf(strbuf, "%s", tvb_ip_to_str(tvb, offset + 2));
526             break;
527
528         case AFNUM_INET6:
529             len = 16;
530             ep_strbuf_printf(strbuf, "%s", tvb_ip6_to_str(tvb, offset + 2));
531             break;
532         }
533         if (advance)
534             *advance = 2 + len;
535         break;
536
537     case pimv2_group:
538         mask_len = tvb_get_guint8(tvb, offset + 3);
539         switch (af) {
540         case AFNUM_INET:
541             len = 4;
542             ep_strbuf_printf(strbuf, "%s/%u",
543                              tvb_ip_to_str(tvb, offset + 4), mask_len);
544             break;
545
546         case AFNUM_INET6:
547             len = 16;
548             ep_strbuf_printf(strbuf, "%s/%u",
549                              tvb_ip6_to_str(tvb, offset + 4), mask_len);
550             break;
551         }
552         if (advance)
553             *advance = 4 + len;
554         break;
555
556     case pimv2_source:
557         flags = tvb_get_guint8(tvb, offset + 2);
558         mask_len = tvb_get_guint8(tvb, offset + 3);
559         switch (af) {
560         case AFNUM_INET:
561             len = 4;
562             ep_strbuf_printf(strbuf, "%s/%u",
563                              tvb_ip_to_str(tvb, offset + 4), mask_len);
564             break;
565
566         case AFNUM_INET6:
567             len = 16;
568             ep_strbuf_printf(strbuf, "%s/%u",
569                              tvb_ip6_to_str(tvb, offset + 4), mask_len);
570             break;
571         }
572         if (flags) {
573             ep_strbuf_append_printf(strbuf,
574                                     " (%s%s%s)",
575                                     flags & 0x04 ? "S" : "",
576                                     flags & 0x02 ? "W" : "",
577                                     flags & 0x01 ? "R" : "");
578         }
579         if (advance)
580             *advance = 4 + len;
581         break;
582     default:
583         return NULL;
584     }
585
586     return strbuf->str;
587 }
588
589 static const value_string type2vals[] = {
590     { 0, "Hello" },
591     { 1, "Register" },
592     { 2, "Register-stop" },
593     { 3, "Join/Prune" },
594     { 4, "Bootstrap" },
595     { 5, "Assert" },
596     { 6, "Graft" },
597     { 7, "Graft-Ack" },
598     { 8, "Candidate-RP-Advertisement" },
599     { 9, "State-Refresh" },
600     { 0, NULL }
601 };
602
603 static const value_string pim_opt_vals[] = {
604     {1, "Hold Time"},
605     {2, "LAN Prune Delay"},
606     {18, "Deprecated and should not be used"},
607     {19, "DR Priority"},
608     {20, "Generation ID"},
609     {21, "State Refresh Capable"},
610     {22, "Bidir Capable"},
611     {24, "Address List"},
612     {65001, "Address List"},    /* old implementation */
613     {0, NULL}
614 };
615
616 /*
617  * For PIM v2, see RFC 4601, RFC 3973 and draft-ietf-pim-sm-v2-new-03
618  * (when PIM is run over IPv6, the rules for computing the PIM checksum
619  * from the draft in question, not from RFC 2362, should be used).
620  */
621 static void
622 dissect_pim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
623     int offset = 0;
624     guint8 pim_typever;
625     guint length, pim_length;
626     guint16 pim_cksum, computed_cksum;
627     vec_t cksum_vec[4];
628     guint32 phdr[2];
629     const char *typestr;
630     proto_tree *pim_tree = NULL;
631     proto_item *ti;
632     proto_tree *pimopt_tree = NULL;
633     proto_item *tiopt;
634
635     col_set_str(pinfo->cinfo, COL_PROTOCOL, "PIM");
636     col_clear(pinfo->cinfo, COL_INFO);
637
638     pim_typever = tvb_get_guint8(tvb, 0);
639
640     switch (PIM_VER(pim_typever)) {
641     case 2:
642         typestr = val_to_str(PIM_TYPE(pim_typever), type2vals, "Unknown (%u)");
643         break;
644     case 1:     /* PIMv1 - we should never see this */
645     default:
646         typestr = "Unknown";
647         break;
648     }
649
650     if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
651         col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "PIMv%d",
652                      PIM_VER(pim_typever));
653     }
654     if (check_col(pinfo->cinfo, COL_INFO))
655         col_add_str(pinfo->cinfo, COL_INFO, typestr);
656
657     ti = proto_tree_add_item(tree, proto_pim, tvb, offset, -1, FALSE);
658     pim_tree = proto_item_add_subtree(ti, ett_pim);
659
660     proto_tree_add_item(pim_tree, hf_pim_version, tvb, offset, 1, ENC_BIG_ENDIAN);
661     proto_tree_add_item(pim_tree, hf_pim_type, tvb, offset, 1, ENC_BIG_ENDIAN);
662     proto_tree_add_item(pim_tree, hf_pim_res_bytes, tvb, offset + 1, 1, ENC_NA);
663     pim_cksum = tvb_get_ntohs(tvb, offset + 2);
664     length = tvb_length(tvb);
665     if (PIM_VER(pim_typever) == 2) {
666         /*
667          * Well, it's PIM v2, so we can check whether this is a Register
668          * message, and thus can figure out how much to checksum and
669          * whether to make the columns read-only.
670          */
671         if (PIM_TYPE(pim_typever) == 1) {
672             /*
673              * Register message - the PIM header is 8 bytes long.
674              * Also set the columns non-writable. Otherwise the IPv4 or
675              * IPv6 dissector for the encapsulated packet that caused
676              * this register will overwrite the PIM info in the columns.
677              */
678             pim_length = 8;
679             col_set_writable(pinfo->cinfo, FALSE);
680         } else {
681             /*
682              * Other message - checksum the entire packet.
683              */
684             pim_length = tvb_reported_length(tvb);
685         }
686     } else {
687         /*
688          * We don't know what type of message this is, so say that
689          * the length is 0, to force it not to be checksummed.
690          */
691         pim_length = 0;
692     }
693     if (!pinfo->fragmented && length >= pim_length) {
694         /*
695          * The packet isn't part of a fragmented datagram and isn't
696          * truncated, so we can checksum it.
697          */
698
699         switch (pinfo->src.type) {
700         case AT_IPv4:
701             cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, pim_length);
702             cksum_vec[0].len = pim_length;
703             computed_cksum = in_cksum(&cksum_vec[0], 1);
704             break;
705         case AT_IPv6:
706             /* Set up the fields of the pseudo-header. */
707             cksum_vec[0].ptr = pinfo->src.data;
708             cksum_vec[0].len = pinfo->src.len;
709             cksum_vec[1].ptr = pinfo->dst.data;
710             cksum_vec[1].len = pinfo->dst.len;
711             cksum_vec[2].ptr = (const guint8 *)&phdr;
712             phdr[0] = g_htonl(pim_length);
713             phdr[1] = g_htonl(IP_PROTO_PIM);
714             cksum_vec[2].len = 8;
715             cksum_vec[3].ptr = tvb_get_ptr(tvb, 0, pim_length);
716             cksum_vec[3].len = pim_length;
717             computed_cksum = in_cksum(&cksum_vec[0], 4);
718             break;
719         default:
720             /* PIM is available for IPv4 and IPv6 right now */
721             computed_cksum = 0; /* squelch GCC complaints */
722             DISSECTOR_ASSERT_NOT_REACHED();
723             break;
724         }
725
726         if (computed_cksum == 0) {
727             proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb,
728                                        offset + 2, 2, pim_cksum,
729                                        "Checksum: 0x%04x [correct]",
730                                        pim_cksum);
731         } else {
732             proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb,
733                                        offset + 2, 2, pim_cksum,
734                                        "Checksum: 0x%04x [incorrect, should be 0x%04x]",
735                                        pim_cksum, in_cksum_shouldbe(pim_cksum, computed_cksum));
736         }
737     } else {
738         proto_tree_add_uint(pim_tree, hf_pim_cksum, tvb,
739                             offset + 2, 2, pim_cksum);
740     }
741
742     offset += 4;
743
744     if (tvb_reported_length_remaining(tvb, offset) > 0) {
745         tiopt = proto_tree_add_text(pim_tree, tvb, offset, -1, "PIM options");
746         pimopt_tree = proto_item_add_subtree(tiopt, ett_pim_opts);
747     } else
748         goto done;
749
750     if (PIM_VER(pim_typever) != 2)
751         goto done;
752
753     /* version 2 decoder */
754     switch (PIM_TYPE(pim_typever)) {
755     case 0:     /*hello*/
756     {
757         int opt_count = 0;
758
759         while (tvb_reported_length_remaining(tvb, offset) >= 2) {
760             guint16 hello_opt, opt_len;
761             guint16 opt_value;
762             proto_item *opt_item;
763             proto_tree *opt_tree;
764
765             opt_count++;
766             hello_opt = tvb_get_ntohs(tvb, offset);
767             opt_len = tvb_get_ntohs(tvb, offset + 2);
768             opt_item = proto_tree_add_text(pimopt_tree, tvb, offset, 4 + opt_len,
769                                            "Option %u: %s", hello_opt,
770                                            val_to_str(hello_opt, pim_opt_vals, "Unknown: %u"));
771             opt_tree = proto_item_add_subtree(opt_item, ett_pim_opt);
772             proto_tree_add_item(opt_tree, hf_pim_optiontype, tvb, offset, 2, ENC_BIG_ENDIAN);
773             proto_tree_add_item(opt_tree, hf_pim_optionlength, tvb, offset + 2, 2, ENC_BIG_ENDIAN);
774
775             switch(hello_opt) {
776             case 1: /* Hello Hold Time Option */
777                 opt_value = tvb_get_ntohs(tvb, offset + 4);
778                 proto_tree_add_uint_format(opt_tree, hf_pim_holdtime, tvb,
779                                            offset + 4, opt_len, opt_value,
780                                            "Holdtime: %us %s", opt_value, opt_value == 0 ? "(goodbye)" :
781                                            opt_value == 0xffff ? "(infinity)": "");
782                 proto_item_append_text(opt_item, ": %us %s", opt_value,
783                                        opt_value == 0 ? "(goodbye)" :
784                                        opt_value == 0xffff ? "(infinity)": "");
785                 break;
786
787             case 2: /* LAN Prune Delay Option */
788                 proto_tree_add_item(opt_tree, hf_pim_t, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
789                 proto_tree_add_item(opt_tree, hf_pim_propagation_delay, tvb, offset + 4, 2, ENC_BIG_ENDIAN);
790                 proto_tree_add_item(opt_tree, hf_pim_override_interval, tvb, offset + 6, 2, ENC_BIG_ENDIAN);
791                 proto_item_append_text(opt_item,
792                                        ": T = %u, Propagation Delay = %ums, Override Interval = %ums",
793                                        tvb_get_guint8(tvb, offset + 4) & 0x80 ? 1 : 0,
794                                        tvb_get_ntohs(tvb, offset + 4) & 0x7fff,
795                                        tvb_get_ntohs(tvb, offset + 6));
796                 break;
797
798             case 19: /* DR priority */
799                 proto_tree_add_item(opt_tree, hf_pim_dr_priority, tvb, offset + 4, 4, ENC_BIG_ENDIAN);
800                 proto_item_append_text(opt_item, ": %u", tvb_get_ntohl(tvb, offset + 4));
801                 break;
802
803             case 20: /* Generation ID */
804                 proto_tree_add_item(opt_tree, hf_pim_generation_id, tvb, offset + 4, 4, ENC_BIG_ENDIAN);
805                 proto_item_append_text(opt_item, ": %u", tvb_get_ntohl(tvb, offset + 4));
806                 break;
807
808             case 21: /* State Refresh Capable Option */
809                 proto_tree_add_item(opt_tree, hf_pim_state_refresh_version, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
810                 proto_tree_add_item(opt_tree, hf_pim_state_refresh_interval, tvb, offset + 5, 1, ENC_BIG_ENDIAN);
811                 proto_tree_add_item(opt_tree, hf_pim_state_refresh_reserved, tvb, offset + 6, 2, ENC_BIG_ENDIAN);
812                 proto_item_append_text(opt_item, ": Version = %u, Interval = %us",
813                                        tvb_get_guint8(tvb, offset + 4),
814                                        tvb_get_guint8(tvb, offset + 5));
815                 break;
816
817             case 24: /* address list */
818             case 65001: /* address list (old implementations) */
819             {
820                 int i;
821                 proto_tree *sub_tree = NULL;
822                 proto_item *addrlist_option;
823
824                 addrlist_option = proto_tree_add_text(opt_tree, tvb, offset, 4 + opt_len,
825                                                       "%sAddress List (%u)",
826                                                       hello_opt == 65001 ? "old " : "",
827                                                       hello_opt);
828                 sub_tree = proto_item_add_subtree(addrlist_option, ett_pim_opt);
829                 for (i = offset + 4; i < offset + 4 + opt_len; ) {
830                     int advance;
831                     const char *s;
832
833                     s = dissect_pim_addr(tvb, i, pimv2_unicast, &advance);
834                     if (s == NULL)
835                         break;
836                     proto_tree_add_text(sub_tree, tvb, offset,
837                                         advance, "Address: %s", s);
838                     i += advance;
839                 }
840                 break;
841             }
842
843             default:
844                 if (opt_len)
845                     proto_tree_add_item(opt_tree, hf_pim_optionvalue, tvb,
846                                         offset + 4, opt_len, ENC_NA);
847                 break;
848             }
849             offset += 4 + opt_len;
850         }
851         proto_item_append_text(tiopt, ": %u", opt_count);
852         break;
853     }
854
855     case 1:     /* register */
856     {
857         guint32 flags;
858         guint8 v_hl;
859         tvbuff_t *next_tvb;
860         proto_tree *flag_tree = NULL;
861         proto_item *tiflag;
862
863         flags = tvb_get_ntohl(tvb, offset);
864         tiflag = proto_tree_add_text(pimopt_tree, tvb, offset, 4,
865                                      "Flags: 0x%08x", flags);
866         flag_tree = proto_item_add_subtree(tiflag, ett_pim);
867         proto_tree_add_text(flag_tree, tvb, offset, 1, "%s",
868                             decode_boolean_bitfield(flags, 0x80000000, 32,
869                                                     "Border", "Not border"));
870         proto_tree_add_text(flag_tree, tvb, offset, 1, "%s",
871                             decode_boolean_bitfield(flags, 0x40000000, 32,
872                                                     "Null-Register", "Not Null-Register"));
873         offset += 4;
874
875         /*
876          * The rest of the packet is a multicast data packet.
877          */
878         next_tvb = tvb_new_subset_remaining(tvb, offset);
879
880         /*
881          * It's an IP packet - determine whether it's IPv4 or IPv6.
882          */
883         v_hl = tvb_get_guint8(tvb, offset);
884         switch((v_hl & 0xf0) >> 4) {
885         case 0:     /* Null-Register dummy header.
886                      * Has the same address family as the encapsulating PIM packet,
887                      * e.g. an IPv6 data packet is encapsulated in IPv6 PIM packet.
888                      */
889             if (pinfo->src.type == AT_IPv4) {
890                 proto_tree_add_text(pimopt_tree, tvb, offset, -1,
891                                     "IPv4 dummy header");
892                 proto_tree_add_text(pimopt_tree, tvb, offset + 12, 4,
893                                     "Source: %s",
894                                     tvb_ip_to_str(tvb, offset + 12));
895                 proto_tree_add_text(pimopt_tree, tvb, offset + 16, 4,
896                                     "Group: %s",
897                                     tvb_ip_to_str(tvb, offset + 16));
898             } else if (pinfo->src.type == AT_IPv6) {
899                 proto_tree_add_text(pimopt_tree, tvb, offset, -1,
900                                     "IPv6 dummy header");
901                 proto_tree_add_text(pimopt_tree, tvb,
902                                     offset + 8, 16,
903                                     "Source: %s",
904                                     tvb_ip6_to_str(tvb, offset + 8));
905                 proto_tree_add_text(pimopt_tree, tvb,
906                                     offset + 8 + 16, 16,
907                                     "Group: %s",
908                                     tvb_ip6_to_str(tvb, offset + 8 + 16));
909             } else
910                 proto_tree_add_text(pimopt_tree, tvb, offset, -1,
911                                     "Dummy header for an unknown protocol");
912             break;
913         case 4: /* IPv4 */
914 #if 0
915             call_dissector(ip_handle, next_tvb, pinfo, tree);
916 #else
917             call_dissector(ip_handle, next_tvb, pinfo, pimopt_tree);
918 #endif
919             break;
920         case 6: /* IPv6 */
921 #if 0
922             call_dissector(ipv6_handle, next_tvb, pinfo, tree);
923 #else
924             call_dissector(ipv6_handle, next_tvb, pinfo, pimopt_tree);
925 #endif
926             break;
927         default:
928             proto_tree_add_text(pimopt_tree, tvb, offset, -1,
929                                 "Unknown IP version %d", (v_hl & 0xf0) >> 4);
930             break;
931         }
932         break;
933     }
934
935     case 2:     /* register-stop */
936     {
937         int advance;
938         const char *s;
939
940         s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
941         if (s == NULL)
942             break;
943         proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group: %s", s);
944         offset += advance;
945         s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
946         if (s == NULL)
947             break;
948         proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Source: %s", s);
949         break;
950     }
951
952     case 3:     /* join/prune */
953     case 6:     /* graft */
954     case 7:     /* graft-ack */
955     {
956         int advance;
957         int off;
958         const char *s;
959         int ngroup, i, njoin, nprune, j;
960         guint16 holdtime;
961         proto_tree *grouptree = NULL;
962         proto_item *tigroup;
963         proto_tree *subtree = NULL;
964         proto_item *tisub;
965
966         s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
967         if (s == NULL)
968             break;
969         proto_tree_add_text(pimopt_tree, tvb, offset, advance,
970                             "Upstream-neighbor: %s", s);
971         offset += advance;
972
973         proto_tree_add_item(pimopt_tree, hf_pim_res_bytes, tvb, offset, 1, ENC_NA);
974         offset += 1;    /* skip reserved field */
975
976         ngroup = tvb_get_guint8(tvb, offset);
977         proto_tree_add_item(pimopt_tree, hf_pim_numgroups, tvb, offset, 1, ENC_BIG_ENDIAN);
978         offset += 1;
979
980         holdtime = tvb_get_ntohs(tvb, offset);
981         proto_tree_add_uint_format(pimopt_tree, hf_pim_holdtime, tvb,
982                                    offset, 2, holdtime,
983                                    "Holdtime: %us %s", holdtime,
984                                    holdtime == 0xffff ? "(infinity)": "");
985         offset += 2;
986
987         for (i = 0; i < ngroup; i++) {
988             s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
989             if (s == NULL)
990                 goto breakbreak3;
991             tigroup = proto_tree_add_text(pimopt_tree, tvb, offset, advance,
992                                           "Group %d: %s", i, s);
993             grouptree = proto_item_add_subtree(tigroup, ett_pim);
994             offset += advance;
995
996             njoin = tvb_get_ntohs(tvb, offset);
997             nprune = tvb_get_ntohs(tvb, offset + 2);
998             tisub = proto_tree_add_item(grouptree, hf_pim_numjoins, tvb,
999                                         offset, 2, ENC_BIG_ENDIAN);
1000             subtree = proto_item_add_subtree(tisub, ett_pim);
1001             off = offset + 4;
1002             for (j = 0; j < njoin; j++) {
1003                 s = dissect_pim_addr(tvb, off, pimv2_source, &advance);
1004                 if (s == NULL)
1005                     goto breakbreak3;
1006                 proto_tree_add_text(subtree, tvb, off, advance,
1007                                     "IP address: %s", s);
1008                 off += advance;
1009             }
1010
1011             tisub = proto_tree_add_item(grouptree, hf_pim_numprunes, tvb,
1012                                         offset + 2, 2, ENC_BIG_ENDIAN);
1013             subtree = proto_item_add_subtree(tisub, ett_pim);
1014             for (j = 0; j < nprune; j++) {
1015                 s = dissect_pim_addr(tvb, off, pimv2_source, &advance);
1016                 if (s == NULL)
1017                     goto breakbreak3;
1018                 proto_tree_add_text(subtree, tvb, off, advance,
1019                                     "IP address: %s", s);
1020                 off += advance;
1021             }
1022             offset = off;
1023         }
1024     breakbreak3:
1025         break;
1026     }
1027
1028     case 4:     /* bootstrap */
1029     {
1030         const char *s;
1031         int advance;
1032         int i, j;
1033         int frpcnt;
1034         guint16 holdtime;
1035         proto_tree *grouptree = NULL;
1036         proto_item *tigroup;
1037
1038         proto_tree_add_text(pimopt_tree, tvb, offset, 2,
1039                             "Fragment tag: 0x%04x", tvb_get_ntohs(tvb, offset));
1040         offset += 2;
1041
1042         proto_tree_add_text(pimopt_tree, tvb, offset, 1,
1043                             "Hash mask len: %u", tvb_get_guint8(tvb, offset));
1044         offset += 1;
1045         proto_tree_add_text(pimopt_tree, tvb, offset, 1,
1046                             "BSR priority: %u", tvb_get_guint8(tvb, offset));
1047         offset += 1;
1048
1049         s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
1050         if (s == NULL)
1051             break;
1052         proto_tree_add_text(pimopt_tree, tvb, offset, advance, "BSR: %s", s);
1053         offset += advance;
1054
1055         for (i = 0; tvb_reported_length_remaining(tvb, offset) > 0; i++) {
1056             s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
1057             if (s == NULL)
1058                 goto breakbreak4;
1059             tigroup = proto_tree_add_text(pimopt_tree, tvb, offset, advance,
1060                                           "Group %d: %s", i, s);
1061             grouptree = proto_item_add_subtree(tigroup, ett_pim);
1062             offset += advance;
1063
1064             proto_tree_add_text(grouptree, tvb, offset, 1,
1065                                 "RP count: %u", tvb_get_guint8(tvb, offset));
1066             offset += 1;
1067             frpcnt = tvb_get_guint8(tvb, offset);
1068             proto_tree_add_text(grouptree, tvb, offset, 1,
1069                                 "FRP count: %u", frpcnt);
1070             offset += 3;
1071
1072             for (j = 0; j < frpcnt; j++) {
1073                 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
1074                 if (s == NULL)
1075                     goto breakbreak4;
1076                 proto_tree_add_text(grouptree, tvb, offset, advance,
1077                                     "RP %d: %s", j, s);
1078                 offset += advance;
1079
1080                 holdtime = tvb_get_ntohs(tvb, offset);
1081                 proto_tree_add_uint_format(grouptree, hf_pim_holdtime, tvb,
1082                                    offset, 2, holdtime,
1083                                    "Holdtime: %us %s", holdtime,
1084                                    holdtime == 0xffff ? "(infinity)": "");
1085                 offset += 2;
1086                 proto_tree_add_text(grouptree, tvb, offset, 1,
1087                                     "Priority: %u", tvb_get_guint8(tvb, offset));
1088                 offset += 2;    /* also skips reserved field */
1089             }
1090         }
1091
1092     breakbreak4:
1093         break;
1094     }
1095
1096     case 5:     /* assert */
1097     {
1098         const char *s;
1099         int advance;
1100         guint32 pref;
1101
1102         s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
1103         if (s == NULL)
1104             break;
1105         proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group: %s", s);
1106         offset += advance;
1107
1108         s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
1109         if (s == NULL)
1110             break;
1111         proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Source: %s", s);
1112         offset += advance;
1113
1114         proto_tree_add_item(pimopt_tree, hf_pim_rpt, tvb, offset, 1, ENC_BIG_ENDIAN);
1115         pref = tvb_get_ntohl(tvb, offset) & 0x7fffffff;
1116         proto_tree_add_uint_format(pimopt_tree, hf_pim_metric_pref, tvb,
1117                                    offset, 4, pref,
1118                                    "Metric Preference: %u", pref);
1119         offset += 4;
1120
1121         proto_tree_add_item(pimopt_tree, hf_pim_metric, tvb, offset, 4, ENC_BIG_ENDIAN);
1122         offset += 4;
1123         break;
1124     }
1125
1126     case 8:     /* Candidate-RP-Advertisement */
1127     {
1128         const char *s;
1129         int advance;
1130         int pfxcnt;
1131         guint16 holdtime;
1132         int i;
1133
1134         pfxcnt = tvb_get_guint8(tvb, offset);
1135         proto_tree_add_text(pimopt_tree, tvb, offset, 1,
1136                             "Prefix-count: %u", pfxcnt);
1137         offset += 1;
1138         proto_tree_add_text(pimopt_tree, tvb, offset, 1,
1139                             "Priority: %u", tvb_get_guint8(tvb, offset));
1140         offset += 1;
1141         holdtime = tvb_get_ntohs(tvb, offset);
1142         proto_tree_add_uint_format(pimopt_tree, hf_pim_holdtime, tvb,
1143                                    offset, 2, holdtime,
1144                                    "Holdtime: %us %s", holdtime,
1145                                    holdtime == 0xffff ? "(infinity)": "");
1146         offset += 2;
1147
1148         s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
1149         if (s == NULL)
1150             break;
1151         proto_tree_add_text(pimopt_tree, tvb, offset, advance, "RP: %s", s);
1152         offset += advance;
1153
1154         for (i = 0; i < pfxcnt; i++) {
1155             s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
1156             if (s == NULL)
1157                 goto breakbreak8;
1158             proto_tree_add_text(pimopt_tree, tvb, offset, advance,
1159                                 "Group %d: %s", i, s);
1160             offset += advance;
1161         }
1162     breakbreak8:
1163         break;
1164     }
1165
1166     case 9:     /* State-Refresh */
1167     {
1168         const char *s;
1169         int advance;
1170         guint32 pref;
1171
1172         s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
1173         if (s == NULL)
1174             break;
1175         proto_tree_add_text(pimopt_tree, tvb, offset, advance,
1176                             "Group: %s", s);
1177         offset += advance;
1178
1179         s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
1180         if (s == NULL)
1181             break;
1182         proto_tree_add_text(pimopt_tree, tvb, offset, advance,
1183                             "Source: %s", s);
1184         offset += advance;
1185
1186         s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
1187         if (s == NULL)
1188             break;
1189         proto_tree_add_text(pimopt_tree, tvb, offset, advance,
1190                             "Originator: %s", s);
1191         offset += advance;
1192
1193         proto_tree_add_item(pimopt_tree, hf_pim_rpt, tvb, offset, 1, ENC_BIG_ENDIAN);
1194         pref = tvb_get_ntohl(tvb, offset) & 0x7fffffff;
1195         proto_tree_add_uint_format(pimopt_tree, hf_pim_metric_pref, tvb,
1196                                    offset, 4, pref,
1197                                    "Metric Preference: %u", pref);
1198         offset += 4;
1199
1200         proto_tree_add_item(pimopt_tree, hf_pim_metric, tvb, offset, 4, ENC_BIG_ENDIAN);
1201         offset += 4;
1202
1203         proto_tree_add_text(pimopt_tree, tvb, offset, 1,
1204                             "Masklen: %u", tvb_get_guint8(tvb, offset));
1205         offset += 1;
1206
1207         proto_tree_add_text(pimopt_tree, tvb, offset, 1,
1208                             "TTL: %u", tvb_get_guint8(tvb, offset));
1209         offset += 1;
1210
1211         proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Prune indicator %s",
1212                             decode_boolean_bitfield(tvb_get_guint8(tvb, offset), 0x80, 8,
1213                                                     "set", "clear"));
1214         proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Prune now %s",
1215                             decode_boolean_bitfield(tvb_get_guint8(tvb, offset), 0x40, 8,
1216                                                     "set", "clear"));
1217         proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Assert override %s",
1218                             decode_boolean_bitfield(tvb_get_guint8(tvb, offset), 0x20, 8,
1219                                                     "set", "clear"));
1220         offset += 1;
1221
1222         proto_tree_add_text(pimopt_tree, tvb, offset, 1,
1223                             "Interval: %u", tvb_get_guint8(tvb, offset));
1224         offset += 1;
1225
1226         break;
1227     }
1228
1229     default:
1230         break;
1231     }
1232 done:;
1233 }
1234
1235 void
1236 proto_register_pim(void)
1237 {
1238     static hf_register_info hf[] =
1239         {
1240             { &hf_pim_version,
1241               { "Version", "pim.version",
1242                 FT_UINT8, BASE_DEC, NULL, 0xf0,
1243                 NULL, HFILL }
1244             },
1245             { &hf_pim_type,
1246               { "Type", "pim.type",
1247                 FT_UINT8, BASE_DEC, VALS(type2vals), 0x0f,
1248                 NULL, HFILL }
1249             },
1250             { &hf_pim_code,
1251               { "Code", "pim.code",
1252                 FT_UINT8, BASE_DEC, VALS(type1vals), 0x0,
1253                 NULL, HFILL }
1254             },
1255             { &hf_pim_cksum,
1256               { "Checksum", "pim.cksum",
1257                 FT_UINT16, BASE_HEX, NULL, 0x0,
1258                 NULL, HFILL }
1259             },
1260             { &hf_pim_res_bytes,
1261               { "Reserved byte(s)", "pim.res_bytes",
1262                 FT_BYTES, BASE_NONE, NULL, 0x0,
1263                 NULL, HFILL }
1264             },
1265             { &hf_pim_optiontype,
1266               { "Type", "pim.optiontype",
1267                 FT_UINT16, BASE_DEC, NULL, 0x0,
1268                 NULL, HFILL }
1269             },
1270             { &hf_pim_optionlength,
1271               { "Length", "pim.optionlength",
1272                 FT_UINT16, BASE_DEC, NULL, 0x0,
1273                 NULL, HFILL }
1274             },
1275             { &hf_pim_optionvalue,
1276               { "Unknown", "pim.optionvalue",
1277                 FT_BYTES, BASE_NONE, NULL, 0x0,
1278                 NULL, HFILL }
1279             },
1280             { &hf_pim_mode,
1281               { "Mode", "pim.mode",
1282                 FT_UINT8, BASE_DEC, VALS(pimv1_modevals), 0xf0,
1283                 NULL, HFILL }
1284             },
1285             { &hf_pim_holdtime,
1286               { "Holdtime", "pim.holdtime",
1287                 FT_UINT16, BASE_DEC, NULL, 0x0,
1288                 "The amount of time a receiver must keep the neighbor "
1289                 "reachable, in seconds.", HFILL }
1290             },
1291             { &hf_pim_numgroups,
1292               { "Num Groups", "pim.numgroups",
1293                 FT_UINT16, BASE_DEC, NULL, 0x0,
1294                 "Number of multicast group sets contained in the message.",
1295                 HFILL }
1296             },
1297             { &hf_pim_numjoins,
1298               { "Num Joins", "pim.numjoins",
1299                 FT_UINT16, BASE_DEC, NULL, 0x0,
1300                 "Number of joined sources.", HFILL }
1301             },
1302             { &hf_pim_numprunes,
1303               { "Num Prunes", "pim.numprunes",
1304                 FT_UINT16, BASE_DEC, NULL, 0x0,
1305                 "Number of pruned sources.", HFILL }
1306             },
1307             { &hf_pim_t,
1308               { "T", "pim.t",
1309                 FT_BOOLEAN, 8, NULL, 0x80,
1310                 "Specifies the ability of the sending router to disable joins "
1311                 "suppression.", HFILL }
1312             },
1313             { &hf_pim_propagation_delay,
1314               { "Propagation Delay", "pim.propagation_delay",
1315                 FT_UINT16, BASE_DEC, NULL, 0x07fff,
1316                 "Units are milli-seconds", HFILL }
1317             },
1318             { &hf_pim_override_interval,
1319               { "Override Interval", "pim.override_interval",
1320                 FT_UINT16, BASE_DEC, NULL, 0x0,
1321                 "Units are milli-seconds", HFILL }
1322             },
1323             { &hf_pim_dr_priority,
1324               { "DR Priority", "pim.dr_priority",
1325                 FT_UINT32, BASE_DEC, NULL, 0x0,
1326                 NULL, HFILL }
1327             },
1328             { &hf_pim_generation_id,
1329               { "Generation ID", "pim.generation_id",
1330                 FT_UINT32, BASE_DEC, NULL, 0x0,
1331                 NULL, HFILL }
1332             },
1333             { &hf_pim_state_refresh_version,
1334               { "Version", "pim.state_refresh_version",
1335                 FT_UINT8, BASE_DEC, NULL, 0x0,
1336                 NULL, HFILL }
1337             },
1338             { &hf_pim_state_refresh_interval,
1339               { "Interval", "pim.state_refresh_interval",
1340                 FT_UINT8, BASE_DEC, NULL, 0x0,
1341                 "Units in seconds.", HFILL }
1342             },
1343             { &hf_pim_state_refresh_reserved,
1344               { "Reserved", "pim.state_refresh_reserved",
1345                 FT_UINT16, BASE_DEC, NULL, 0x0,
1346                 NULL, HFILL }
1347             },
1348             { &hf_pim_rpt,
1349               { "RP Tree", "pim.rpt",
1350                 FT_BOOLEAN, 8, NULL, 0x80,
1351                 "Set to 1 for assert(*,G) messages and 0 for assert(S,G) "
1352                 "messages.", HFILL }
1353             },
1354             { &hf_pim_metric_pref ,
1355               { "Metric Preference", "pim.metric_pref",
1356                 FT_UINT32, BASE_DEC, NULL, 0x7fffffff,
1357                 NULL, HFILL }
1358             },
1359             { &hf_pim_metric ,
1360               { "Metric", "pim.metric",
1361                 FT_UINT32, BASE_DEC, NULL, 0x0,
1362                 NULL, HFILL }
1363             },
1364         };
1365
1366     static gint *ett[] = {
1367         &ett_pim,
1368         &ett_pim_opts,  /* Tree for all options */
1369         &ett_pim_opt    /* Tree for each option */
1370     };
1371
1372     proto_pim = proto_register_protocol("Protocol Independent Multicast",
1373                                         "PIM", "pim");
1374     proto_register_field_array(proto_pim, hf, array_length(hf));
1375     proto_register_subtree_array(ett, array_length(ett));
1376 }
1377
1378 void
1379 proto_reg_handoff_pim(void)
1380 {
1381     dissector_handle_t pim_handle;
1382
1383     pim_handle = create_dissector_handle(dissect_pim, proto_pim);
1384     dissector_add_uint("ip.proto", IP_PROTO_PIM, pim_handle);
1385
1386     /*
1387      * Get handles for the IPv4 and IPv6 dissectors.
1388      */
1389     ip_handle = find_dissector("ip");
1390     ipv6_handle = find_dissector("ipv6");
1391 }