Add a inflateEnd() call to free up the stream in the re-init block.
[obnox/wireshark/wip.git] / epan / dissectors / packet-icmpv6.c
1 /* packet-icmpv6.c
2  * Routines for ICMPv6 packet disassembly
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * MobileIPv6 support added by Tomislav Borosa <tomislav.borosa@siemens.hr>
11  * Copyright 2006, Nicolas DICHTEL - 6WIND - <nicolas.dichtel@6wind.com>
12  *
13  * HMIPv6 support added by Martti Kuparinen <martti.kuparinen@iki.fi>
14  *
15  * FMIPv6 support added by Martin Andre <andre@clarinet.u-strasbg.fr>
16  *
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License
19  * as published by the Free Software Foundation; either version 2
20  * of the License, or (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
30  */
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <stdio.h>
37
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41
42 #include <stdlib.h>
43 #include <string.h>
44
45 #include <glib.h>
46
47 #include <epan/packet.h>
48 #include <epan/in_cksum.h>
49 #include <epan/addr_resolv.h>
50 #include <epan/ipproto.h>
51 #include <epan/emem.h>
52 #include <epan/asn1.h>
53 #include <epan/strutil.h>
54
55 #include "packet-ber.h"
56 #include "packet-ipv6.h"
57 #include "packet-dns.h"
58 #include "packet-x509af.h"
59 #include "packet-x509if.h"
60
61
62 #ifndef offsetof
63 #define offsetof(type, member)  ((size_t)(&((type *)0)->member))
64 #endif
65
66 /*
67  * See, under http://www.ietf.org/internet-drafts/
68  *
69  *      draft-ietf-mobileip-ipv6-15.txt
70  *
71  * and
72  *
73  *      draft-ietf-ipngwg-icmp-name-lookups-08.txt
74  *
75  * and
76  *
77  *      draft-ietf-mobileip-hmipv6-05.txt
78  *
79  * and
80  *
81  *      rfc4068.txt
82  */
83
84 static int proto_icmpv6 = -1;
85 static int hf_icmpv6_type = -1;
86 static int hf_icmpv6_code = -1;
87 static int hf_icmpv6_checksum = -1;
88 static int hf_icmpv6_checksum_bad = -1;
89 static int hf_icmpv6_haad_ha_addrs = -1;
90 static int hf_icmpv6_ra_cur_hop_limit = -1;
91 static int hf_icmpv6_ra_router_lifetime = -1;
92 static int hf_icmpv6_ra_reachable_time = -1;
93 static int hf_icmpv6_ra_retrans_timer = -1;
94
95 static int hf_icmpv6_option = -1;
96 static int hf_icmpv6_option_type = -1;
97 static int hf_icmpv6_option_length = -1;
98 static int hf_icmpv6_opt_cga_pad_len = -1;
99 static int hf_icmpv6_opt_cga = -1;
100 static int hf_icmpv6_opt_rsa_key_hash = -1;
101 static int hf_icmpv6_opt_name_type = -1;
102 static int hf_icmpv6_opt_name_x501 = -1;
103 static int hf_icmpv6_opt_name_fqdn = -1;
104 static int hf_icmpv6_opt_cert_type = -1;
105 static int hf_icmpv6_identifier = -1;
106 static int hf_icmpv6_all_comp = -1;
107 static int hf_icmpv6_comp = -1;
108 static int hf_icmpv6_x509if_Name = -1;
109 static int hf_icmpv6_x509af_Certificate = -1;
110
111 static gint ett_icmpv6 = -1;
112 static gint ett_icmpv6opt = -1;
113 static gint ett_icmpv6flag = -1;
114 static gint ett_nodeinfo_flag = -1;
115 static gint ett_nodeinfo_subject4 = -1;
116 static gint ett_nodeinfo_subject6 = -1;
117 static gint ett_nodeinfo_node4 = -1;
118 static gint ett_nodeinfo_node6 = -1;
119 static gint ett_nodeinfo_nodebitmap = -1;
120 static gint ett_nodeinfo_nodedns = -1;
121 static gint ett_multicastRR = -1;
122 static gint ett_icmpv6opt_name = -1;
123
124 static dissector_handle_t ipv6_handle;
125 static dissector_handle_t data_handle;
126
127 static const value_string names_nodeinfo_qtype[] = {
128     { NI_QTYPE_NOOP,            "NOOP" },
129     { NI_QTYPE_SUPTYPES,        "Supported query types" },
130     { NI_QTYPE_DNSNAME,         "DNS name" },
131     { NI_QTYPE_NODEADDR,        "Node addresses" },
132     { NI_QTYPE_IPV4ADDR,        "IPv4 node addresses" },
133     { 0,                        NULL }
134 };
135
136 static const value_string names_rrenum_matchcode[] = {
137     { RPM_PCO_ADD,              "Add" },
138     { RPM_PCO_CHANGE,           "Change" },
139     { RPM_PCO_SETGLOBAL,        "Set Global" },
140     { 0,                        NULL }
141 };
142
143 static const value_string names_router_pref[] = {
144         { ND_RA_FLAG_RTPREF_HIGH,       "High" },
145         { ND_RA_FLAG_RTPREF_MEDIUM,     "Medium" },
146         { ND_RA_FLAG_RTPREF_LOW,        "Low" },
147         { ND_RA_FLAG_RTPREF_RSV,        "Reserved" },
148         { 0, NULL}
149 };
150
151 static const value_string names_fmip6_prrtadv_code[] = {
152         { FMIP6_PRRTADV_MNTUP,  "MN should use AP-ID, AR-info tuple" },
153         { FMIP6_PRRTADV_NI_HOVER,       "Network Initiated Handover trigger" },
154         { FMIP6_PRRTADV_NORTINFO,       "No new router information" },
155         { FMIP6_PRRTADV_LIMRTINFO,      "Limited new router information" },
156         { FMIP6_PRRTADV_UNSOL,  "Unsolicited" },
157         { 0,                    NULL }
158 };
159
160 static const value_string names_fmip6_hi_code[] = {
161         { FMIP6_HI_PCOA,        "FBU sent from previous link" },
162         { FMIP6_HI_NOTPCOA,     "FBU sent from new link" },
163         { 0,                    NULL }
164 };
165
166 static const value_string names_fmip6_hack_code[] = {
167         { FMIP6_HACK_VALID,     "Handover Accepted, NCoA valid" },
168         { FMIP6_HACK_INVALID,   "Handover Accepted, NCoA not valid" },
169         { FMIP6_HACK_INUSE,     "Handover Accepted, NCoA in use" },
170         { FMIP6_HACK_ASSIGNED,  "Handover Accepted, NCoA assigned" },
171         { FMIP6_HACK_NOTASSIGNED,       "Handover Accepted, NCoA not assigned" },
172         { FMIP6_HACK_NOTACCEPTED,       "Handover Not Accepted, reason unspecified" },
173         { FMIP6_HACK_PROHIBITED,        "Administratively prohibited" },
174         { FMIP6_HACK_INSUFFICIENT,      "Insufficient resources" },
175         { 0,                    NULL }
176 };
177
178 static const value_string names_fmip6_ip_addr_opt_code[] = {
179         { FMIP6_OPT_IP_ADDRESS_OPTCODE_PCOA,    "Old Care-of Address" },
180         { FMIP6_OPT_IP_ADDRESS_OPTCODE_NCOA,    "New Care-of Address" },
181         { FMIP6_OPT_IP_ADDRESS_OPTCODE_NAR,     "NAR's IP address" },
182         { 0,                    NULL }
183 };
184
185 static const value_string names_fmip6_lla_opt_code[] = {
186         { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_WILDCARD,        "Wildcard" },
187         { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_NAP,     "Link-layer Address of the New Access Point" },
188         { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_MN,      "Link-layer Address of the MN" },
189         { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_NAR,     "Link-layer Address of the NAR" },
190         { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_SRC,     "Link-layer Address of the source" },
191         { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_CURROUTER,       "The AP belongs to the current interface of the router" },
192         { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_NOPREFIX,        "No prefix information available" },
193         { FMIP6_OPT_LINK_LAYER_ADDRESS_OPTCODE_NOSUPPORT,       "No fast handovers support available" },
194         { 0,                    NULL }
195 };
196
197 static const value_string names_fmip6_naack_opt_status[] = {
198         { FMIP6_OPT_NEIGHBOR_ADV_ACK_STATUS_INVALID,    "New CoA is invalid" },
199         { FMIP6_OPT_NEIGHBOR_ADV_ACK_STATUS_INVALID_NEW,        "New CoA is invalid, use the supplied CoA" },
200         { FMIP6_OPT_NEIGHBOR_ADV_ACK_STATUS_UNRECOGNIZED,       "LLA is unrecognized" },
201         { 0,                    NULL }
202 };
203
204 /* http://www.iana.org/assignments/icmpv6-parameters */
205 static const value_string option_vals[] = {
206         { ND_OPT_SOURCE_LINKADDR,                       "Source link-layer address" },
207         { ND_OPT_TARGET_LINKADDR,                       "Target link-layer address" },
208         { ND_OPT_PREFIX_INFORMATION,            "Prefix information" },
209         { ND_OPT_REDIRECTED_HEADER,                     "Redirected header" },
210         { ND_OPT_MTU,                                           "MTU" },
211         { ND_OPT_ADVINTERVAL,                           "Advertisement Interval" },
212         { ND_OPT_HOMEAGENT_INFO,                        "Home Agent Information" },
213         { ND_OPT_CGA,                                           "CGA" },                                                                /* [RFC3971] */
214         { ND_OPT_RSA,                                           "RSA Signature" },                                              /* [RFC3971] */
215         { ND_OPT_TIMESTAMP,                                     "Timestamp" },                                                  /* [RFC3971] */
216         { ND_OPT_NONCE,                                         "Nonce" },                                                                                                              /* [RFC3971] */
217         { ND_OPT_TRUST_ANCHOR,                          "Trust Anchor" },                                                                                               /* [RFC3971] */
218         { 16,           "Certificate" },                                                                                                /* [RFC3971] */
219         { FMIP6_OPT_IP_ADDRESS,                         "IP Address Option" },                                          /* [RFC4068] */
220         { FMIP6_OPT_NEW_ROUTER_PREFIX_INFO,     "New Router Prefix Information" },                      /* [RFC4068] */
221         { FMIP6_OPT_LINK_LAYER_ADDRESS,         "Link-layer Address" },                                         /* [RFC4068] */
222         { FMIP6_OPT_NEIGHBOR_ADV_ACK,           "Neighbor Advertisement Acknowledgment" },      /* [RFC4068] */
223         { 21,           "CARD Request" },                     /* [RFC4065] */
224         { 22,           "CARD Reply" },                       /* [RFC4065] */
225         { 23,           "MAP" },                              /* [RFC4140] */
226         { 24,           "Route Information" },                /* [RFC4191] */
227         { 25,           "Recursive DNS Server" },             /* [RFC5006] */
228         { 26,           "RA Flags Extension" },               /* [RFC5075] */
229         { 27,           "Handover Key Request" },             /* [RFC-ietf-mipshop-handover-key-03.txt] */
230         { 28,           "Handover Key Reply" },               /* [RFC-ietf-mipshop-handover-key-03.txt] */
231         { ND_OPT_MAP,                                           "HMIPv6 MAP option" },
232 /*29-252  Unassigned */
233         { 253,          "RFC3692-style Experiment 1" },          /* [RFC4727] */
234         { 254,          "RFC3692-style Experiment 2" },          /* [RFC4727] */
235         { 0,                    NULL }
236 };
237
238 static const value_string icmpv6_option_name_type_vals[] = {
239         { 1,    "DER Encoded X.501 Name" },
240         { 2,    "FQDN" },
241         { 0,                    NULL }
242 };
243
244 static const value_string icmpv6_option_cert_type_vals[] = {
245         { 1,    "X.509v3 Certificate" },
246         { 0,                    NULL }
247 };
248
249 static void
250 dissect_contained_icmpv6(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
251 {
252     gboolean save_in_error_pkt;
253     tvbuff_t *next_tvb;
254
255     /* Save the current value of the "we're inside an error packet"
256        flag, and set that flag; subdissectors may treat packets
257        that are the payload of error packets differently from
258        "real" packets. */
259     save_in_error_pkt = pinfo->in_error_pkt;
260     pinfo->in_error_pkt = TRUE;
261
262     next_tvb = tvb_new_subset(tvb, offset, -1, -1);
263
264     /* tiny sanity check */
265     if ((tvb_get_guint8(tvb, offset) & 0xf0) == 0x60) {
266         /* The contained packet is an IPv6 datagram; dissect it. */
267         call_dissector(ipv6_handle, next_tvb, pinfo, tree);
268     } else
269         call_dissector(data_handle,next_tvb, pinfo, tree);
270
271     /* Restore the "we're inside an error packet" flag. */
272     pinfo->in_error_pkt = save_in_error_pkt;
273 }
274
275 static void
276 dissect_icmpv6ndopt(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
277 {
278     proto_tree *icmp6opt_tree, *field_tree, *name_tree;
279     proto_item *ti, *tf, *name_item;
280     struct nd_opt_hdr nd_opt_hdr, *opt;
281     int len;
282     const char *typename;
283     static const guint8 nd_redirect_reserved[6] = {0, 0, 0, 0, 0, 0};
284     guint8 nd_redirect_res[6];
285         int opt_offset;
286         guint8 padd_length = 0;
287         int par_len;
288         guint8 name_type = 0;
289         guint8 cert_type = 0;
290         asn1_ctx_t asn1_ctx;
291
292
293     if (!tree)
294         return;
295
296 again:
297     if ((int)tvb_reported_length(tvb) <= offset)
298         return; /* No more options left */
299
300     opt = &nd_opt_hdr;
301     tvb_memcpy(tvb, (guint8 *)opt, offset, sizeof *opt);
302     len = opt->nd_opt_len << 3;
303
304     /* !!! specify length */
305     ti = proto_tree_add_item(tree, hf_icmpv6_option, tvb, offset, len, FALSE);
306     icmp6opt_tree = proto_item_add_subtree(ti, ett_icmpv6opt);
307
308     if (len == 0) {
309         proto_tree_add_text(icmp6opt_tree, tvb,
310                             offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
311                             "Invalid option length: %u",
312                             opt->nd_opt_len);
313         return; /* we must not try to decode this */
314     }
315
316     typename = val_to_str(opt->nd_opt_type, option_vals, "Unknown");
317
318     /* Add option name to option root label */
319     proto_item_append_text(ti, " (%s)", typename);
320
321     /* Option type */
322         proto_tree_add_item(icmp6opt_tree, hf_icmpv6_option_type, tvb,
323                 offset + offsetof(struct nd_opt_hdr, nd_opt_type), 1, FALSE);
324     /* Option length */
325     proto_tree_add_uint(icmp6opt_tree, hf_icmpv6_option_length, tvb,
326         offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
327         opt->nd_opt_len << 3);
328
329     /* decode... */
330     switch (opt->nd_opt_type) {
331     case ND_OPT_SOURCE_LINKADDR:
332     case ND_OPT_TARGET_LINKADDR:
333       {
334         int len, p;
335
336         p = offset + sizeof(*opt);
337         len = (opt->nd_opt_len << 3) - sizeof(*opt);
338         proto_tree_add_text(icmp6opt_tree, tvb,
339             offset + sizeof(*opt), len, "Link-layer address: %s",
340             bytestring_to_str(tvb_get_ptr(tvb, p, len), len, ':'));
341         break;
342       }
343     case ND_OPT_PREFIX_INFORMATION:
344       {
345         struct nd_opt_prefix_info nd_opt_prefix_info, *pi;
346         int flagoff;
347
348         pi = &nd_opt_prefix_info;
349         tvb_memcpy(tvb, (guint8 *)pi, offset, sizeof *pi);
350         proto_tree_add_text(icmp6opt_tree, tvb,
351             offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix_len),
352             1, "Prefix length: %u", pi->nd_opt_pi_prefix_len);
353
354         flagoff = offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved);
355         tf = proto_tree_add_text(icmp6opt_tree, tvb, flagoff, 1, "Flags: 0x%02x",
356             tvb_get_guint8(tvb, offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved)));
357         field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
358         proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
359             decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
360                     ND_OPT_PI_FLAG_ONLINK, 8, "Onlink", "Not onlink"));
361         proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
362             decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
363                     ND_OPT_PI_FLAG_AUTO, 8, "Auto", "Not auto"));
364         proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
365             decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
366                     ND_OPT_PI_FLAG_ROUTER, 8,
367                     "Router Address", "Not router address"));
368         proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
369             decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
370                     ND_OPT_PI_FLAG_SITEPREF, 8,
371                     "Site prefix", "Not site prefix"));
372         if (pntohl(&pi->nd_opt_pi_valid_time) == 0xffffffff)
373                 proto_tree_add_text(icmp6opt_tree, tvb,
374                                 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_valid_time),
375                                 4, "Valid lifetime: infinity");
376         else
377                 proto_tree_add_text(icmp6opt_tree, tvb,
378                                 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_valid_time),
379                                 4, "Valid lifetime: %u",
380                                 pntohl(&pi->nd_opt_pi_valid_time));
381         if (pntohl(&pi->nd_opt_pi_preferred_time) == 0xffffffff)
382                 proto_tree_add_text(icmp6opt_tree, tvb,
383                                 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_preferred_time),
384                                 4, "Preferred lifetime: infinity");
385         else
386                 proto_tree_add_text(icmp6opt_tree, tvb,
387                                 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_preferred_time),
388                                 4, "Preferred lifetime: %u",
389                                 pntohl(&pi->nd_opt_pi_preferred_time));
390         proto_tree_add_text(icmp6opt_tree, tvb,
391             offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix),
392             16, "Prefix: %s", ip6_to_str(&pi->nd_opt_pi_prefix));
393         break;
394       }
395     case ND_OPT_REDIRECTED_HEADER:
396         tvb_memcpy(tvb, (guint8 *)&nd_redirect_res, offset + 2, 6);
397         if (memcmp(nd_redirect_res, nd_redirect_reserved, 6) == 0)
398            proto_tree_add_text(icmp6opt_tree, tvb,
399             offset + 2, 6, "Reserved: 0 (correct)");
400         else
401            proto_tree_add_text(icmp6opt_tree, tvb,
402             offset +2, 6, "Reserved: MUST be 0 (incorrect!)");
403         proto_tree_add_text(icmp6opt_tree, tvb,
404             offset + 8, (opt->nd_opt_len << 3) - 8, "Redirected packet");
405         dissect_contained_icmpv6(tvb, offset + 8, pinfo, icmp6opt_tree);
406         break;
407     case ND_OPT_MTU:
408         proto_tree_add_text(icmp6opt_tree, tvb,
409             offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu), 4,
410             "MTU: %u", tvb_get_ntohl(tvb, offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu)));
411         break;
412     case ND_OPT_ADVINTERVAL:
413         proto_tree_add_text(icmp6opt_tree, tvb,
414             offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint), 4,
415             "Advertisement Interval: %u",
416             tvb_get_ntohl(tvb, offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint)));
417         break;
418     case ND_OPT_HOMEAGENT_INFO: /* 8 */
419       {
420         struct nd_opt_ha_info pibuf, *pi;
421
422         pi = &pibuf;
423         tvb_memcpy(tvb, (guint8 *)pi, offset, sizeof *pi);
424         proto_tree_add_text(icmp6opt_tree, tvb,
425             offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_pref),
426             2, "Home Agent Preference: %d",
427             (gint16)pntohs(&pi->nd_opt_ha_info_ha_pref));
428         proto_tree_add_text(icmp6opt_tree, tvb,
429             offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_life),
430             2, "Home Agent Lifetime: %u",
431             pntohs(&pi->nd_opt_ha_info_ha_life));
432         break;
433       }
434         case ND_OPT_CGA: /* 11 */
435                 /* RFC 3971 5.1.  CGA Option */
436                 /* Pad Length */
437                 opt_offset = offset +2;
438                 padd_length = tvb_get_guint8(tvb,opt_offset);
439                 proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_cga_pad_len, tvb, opt_offset, 1, FALSE);
440                 opt_offset++;
441                 /* Reserved 8 bits */
442                 proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,1,"Reserved");
443                 opt_offset++;
444                 /* CGA Parameters A variable-length field containing the CGA Parameters data
445                  * structure described in Section 4 of
446                  * "Cryptographically Generated Addresses (CGA)", RFC3972.
447                  */
448                 par_len = len-4-padd_length;
449                 proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_cga, tvb, opt_offset, par_len, FALSE);
450                 opt_offset = opt_offset + par_len;
451                 /* Padding */
452                 proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,padd_length,"Padding");
453                 break;
454         case ND_OPT_RSA: /* 12 */
455                 /*5.2.  RSA Signature Option */
456                 opt_offset = offset +2;
457                 /* Reserved, A 16-bit field reserved for future use. */
458                 proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,2,"Reserved");
459                 opt_offset = opt_offset + 2;
460                 /* Key Hash
461                  * A 128-bit field containing the most significant (leftmost) 128
462                  * bits of a SHA-1 [14] hash of the public key used for constructing
463                  * the signature.
464                  */
465                 proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_rsa_key_hash, tvb, opt_offset, 16, FALSE);
466                 opt_offset = opt_offset + 16;
467                 /* Digital Signature */
468                 par_len = len - 20;
469                 proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,par_len,"Digital Signature + Padding");
470                 /* Padding */
471                 /* TODO: Calculate padding length and exlude from the signature */
472                 break;
473         case ND_OPT_TIMESTAMP: /* 13 */
474                 opt_offset = offset +2;
475                 /* Reserved A 48-bit field reserved for future use. */
476                 proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,6,"Reserved");
477                 opt_offset = opt_offset + 6;
478                 /* Timestamp
479                  * A 64-bit unsigned integer field containing a timestamp.  The value
480                  * indicates the number of seconds since January 1, 1970, 00:00 UTC,
481                  * by using a fixed point format.  In this format, the integer number
482                  * of seconds is contained in the first 48 bits of the field, and the
483                  * remaining 16 bits indicate the number of 1/64K fractions of a
484                  * second.
485                  */
486                 proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,6,"Timestamp(number of seconds since January 1, 1970, 00:00 UTC)");
487                 opt_offset = opt_offset + 6;
488                 proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,2,"Timestamp(1/64K fractions of a second)");
489                 break;
490         case ND_OPT_NONCE:
491                 /* 5.3.2.  Nonce Option */
492                 opt_offset = offset +2;
493                 /* Nonce */
494                 break;
495         case ND_OPT_TRUST_ANCHOR:
496                 opt_offset = offset +2;
497                 /* Name Type */
498                 name_type = tvb_get_guint8(tvb,opt_offset);
499                 proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_name_type, tvb, opt_offset, 1, FALSE);
500                 opt_offset++;
501                 /* Pad Length */
502                 padd_length = tvb_get_guint8(tvb,opt_offset);
503                 proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_cga_pad_len, tvb, opt_offset, 1, FALSE);
504                 opt_offset++;
505                 par_len = len - 4 - padd_length;
506                 switch (name_type){
507                 case 1:
508                         /* DER Encoded X.501 Name */
509                         name_item =proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_name_x501, tvb, opt_offset, par_len, FALSE);
510                         name_tree = proto_item_add_subtree(name_item, ett_icmpv6opt_name);
511                         asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
512                         dissect_x509if_Name(FALSE, tvb, opt_offset, &asn1_ctx, name_tree, hf_icmpv6_x509if_Name);
513                         break;
514                 case 2:
515                         /* FQDN */
516                         proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_name_fqdn, tvb, opt_offset, par_len, FALSE);
517                         break;
518                 default:
519                         proto_tree_add_text(icmp6opt_tree, tvb,opt_offset, par_len,"Unknown name type");
520                         break;
521                 }
522                 opt_offset = opt_offset + par_len;
523                 /* Padding */
524                 proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,padd_length,"Padding");
525                 opt_offset = opt_offset + padd_length;
526                 break;
527         case ND_OPT_CERTIFICATE:
528                 opt_offset = offset +2;
529                 /* Cert Type */
530                 cert_type = tvb_get_guint8(tvb,opt_offset);
531                 proto_tree_add_item(icmp6opt_tree, hf_icmpv6_opt_cert_type, tvb, opt_offset, 1, FALSE);
532                 opt_offset++;
533                 /* Reserved */
534                 proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,1,"Reserved");
535                 opt_offset++;
536                 /* Certificate */
537
538                 if(cert_type == 1){
539                         asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
540                         opt_offset = dissect_x509af_Certificate(FALSE, tvb, opt_offset, &asn1_ctx, icmp6opt_tree, hf_icmpv6_x509af_Certificate);
541                         par_len = len - (opt_offset - offset);
542                         /* Padding */
543                         proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,par_len,"Padding");
544                 }else{
545                         par_len = len - 4;
546                         proto_tree_add_text(icmp6opt_tree, tvb,opt_offset,par_len,"Unknown Certificate + padding");
547                 }
548
549                 break;
550     case ND_OPT_MAP:
551       {
552         struct nd_opt_map_info mapbuf, *map;
553         int flagoff;
554
555         map = &mapbuf;
556         tvb_memcpy(tvb, (guint8 *)map, offset, sizeof *map);
557         proto_tree_add_text(icmp6opt_tree, tvb,
558             offset + offsetof(struct nd_opt_map_info, nd_opt_map_dist_and_pref),
559             1, "Distance: %u", (map->nd_opt_map_dist_and_pref >> 4));
560         proto_tree_add_text(icmp6opt_tree, tvb,
561             offset + offsetof(struct nd_opt_map_info, nd_opt_map_dist_and_pref),
562             1, "Preference: %u", (map->nd_opt_map_dist_and_pref & 0x0F));
563         flagoff = offset + offsetof(struct nd_opt_map_info,
564             nd_opt_map_flags);
565         tf = proto_tree_add_text(icmp6opt_tree, tvb, flagoff, 1,
566             "Flags: 0x%02x",
567             tvb_get_guint8(tvb, offset + offsetof(struct nd_opt_map_info,
568             nd_opt_map_flags)));
569         field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
570         proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
571             decode_boolean_bitfield(map->nd_opt_map_flags,
572                 ND_OPT_MAP_FLAG_R, 8, "R", "No R"));
573         proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
574             decode_boolean_bitfield(map->nd_opt_map_flags,
575                 ND_OPT_MAP_FLAG_M, 8, "M", "No M"));
576         proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
577             decode_boolean_bitfield(map->nd_opt_map_flags,
578                 ND_OPT_MAP_FLAG_I, 8, "I", "No I"));
579         proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
580             decode_boolean_bitfield(map->nd_opt_map_flags,
581                 ND_OPT_MAP_FLAG_T, 8, "T", "No T"));
582         proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
583             decode_boolean_bitfield(map->nd_opt_map_flags,
584                 ND_OPT_MAP_FLAG_P, 8, "P", "No P"));
585         proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
586             decode_boolean_bitfield(map->nd_opt_map_flags,
587                 ND_OPT_MAP_FLAG_V, 8, "V", "No V"));
588         proto_tree_add_text(icmp6opt_tree, tvb,
589             offset + offsetof(struct nd_opt_map_info, nd_opt_map_lifetime),
590             4, "Lifetime: %u", pntohl(&map->nd_opt_map_lifetime));
591
592         proto_tree_add_text(icmp6opt_tree, tvb,
593             offset + offsetof(struct nd_opt_map_info, nd_opt_map_address), 16,
594 #ifdef INET6
595             "Address of MAP: %s (%s)",
596             get_hostname6(&map->nd_opt_map_address),
597 #else
598             "Address of MAP: %s",
599 #endif
600             ip6_to_str(&map->nd_opt_map_address));
601         break;
602       }
603     case ND_OPT_ROUTE_INFO:
604       {
605         struct nd_opt_route_info ribuf, *ri;
606         struct e_in6_addr in6;
607         int l;
608         guint32 lifetime;
609
610         ri = &ribuf;
611         tvb_memcpy(tvb, (guint8 *)ri, offset, sizeof *ri);
612         memset(&in6, 0, sizeof(in6));
613         switch (ri->nd_opt_rti_len) {
614         case 1:
615             l = 0;
616             break;
617         case 2:
618             tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*ri), l = 8);
619             break;
620         case 3:
621             tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*ri), l = 16);
622             break;
623         default:
624             l = -1;
625             break;
626         }
627         if (l >= 0) {
628             proto_tree_add_text(icmp6opt_tree, tvb,
629                 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_prefixlen),
630                 1, "Prefix length: %u", ri->nd_opt_rti_prefixlen);
631             tf = proto_tree_add_text(icmp6opt_tree, tvb,
632                 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_flags),
633                 1, "Flags: 0x%02x", ri->nd_opt_rti_flags);
634             field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
635             proto_tree_add_text(field_tree, tvb,
636                 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_flags),
637                 1, "%s",
638                 decode_enumerated_bitfield(ri->nd_opt_rti_flags,
639                     ND_RA_FLAG_RTPREF_MASK, 8, names_router_pref,
640                     "Router preference: %s"));
641             lifetime = pntohl(&ri->nd_opt_rti_lifetime);
642             if (lifetime == 0xffffffff)
643                 proto_tree_add_text(icmp6opt_tree, tvb,
644                     offset + offsetof(struct nd_opt_route_info, nd_opt_rti_lifetime),
645                     sizeof(ri->nd_opt_rti_lifetime), "Lifetime: infinity");
646             else
647                 proto_tree_add_text(icmp6opt_tree, tvb,
648                     offset + offsetof(struct nd_opt_route_info, nd_opt_rti_lifetime),
649                     sizeof(ri->nd_opt_rti_lifetime), "Lifetime: %u", lifetime);
650             proto_tree_add_text(icmp6opt_tree, tvb,
651                 offset + sizeof(*ri), l, "Prefix: %s", ip6_to_str(&in6));
652         } else {
653             proto_tree_add_text(icmp6opt_tree, tvb,
654                 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
655                 "Invalid option length: %u", opt->nd_opt_len);
656         }
657         break;
658       }
659
660     case FMIP6_OPT_NEIGHBOR_ADV_ACK:
661       {
662         struct fmip6_opt_neighbor_advertisement_ack fmip6_opt_neighbor_advertisement_ack, *opt_naack;
663         struct e_in6_addr in6;
664
665         opt_naack = &fmip6_opt_neighbor_advertisement_ack;
666         tvb_memcpy(tvb, (guint8 *)opt_naack, offset, sizeof *opt_naack);
667
668         proto_tree_add_text(icmp6opt_tree, tvb,
669                         offset + offsetof(struct fmip6_opt_neighbor_advertisement_ack, fmip6_opt_optcode),
670                         1, "Option-Code: %u",
671                         opt_naack->fmip6_opt_optcode);
672
673         proto_tree_add_text(icmp6opt_tree, tvb,
674                         offset + offsetof(struct fmip6_opt_neighbor_advertisement_ack, fmip6_opt_status),
675                         1, "Status: %s",
676                         val_to_str(opt_naack->fmip6_opt_status, names_fmip6_naack_opt_status, "Unknown"));
677
678         if (opt_naack->fmip6_opt_len == 3)
679         {
680                 tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*opt_naack), 16);
681                 proto_tree_add_text(icmp6opt_tree, tvb,
682                         offset + sizeof(*opt_naack),
683                         16, "New Care-of Address: %s",
684                         ip6_to_str(&in6));
685         }
686
687         break;
688       }
689     }
690
691     offset += (opt->nd_opt_len << 3);
692
693     /* Set length of option tree */
694     proto_item_set_len(ti, opt->nd_opt_len << 3);
695     goto again;
696 }
697
698 static void
699 dissect_icmpv6fmip6opt(tvbuff_t *tvb, int offset, proto_tree *tree)
700 {
701         proto_tree *icmp6opt_tree;
702         proto_item *ti;
703         struct fmip6_opt_hdr fmip6_opt_hdr, *opt;
704         int len;
705         char *typename;
706
707         if (!tree)
708                 return;
709
710 again:
711         if ((int)tvb_reported_length(tvb) <= offset)
712                 return; /* No more options left */
713
714         opt = &fmip6_opt_hdr;
715         tvb_memcpy(tvb, (guint8 *)opt, offset, sizeof *opt);
716         len = opt->fmip6_opt_len << 3;
717
718         /* !!! specify length */
719         ti = proto_tree_add_text(tree, tvb, offset, len, "ICMPv6 options");
720         icmp6opt_tree = proto_item_add_subtree(ti, ett_icmpv6opt);
721
722         if (len == 0) {
723                 proto_tree_add_text(icmp6opt_tree, tvb,
724                                 offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_len), 1,
725                                 "Invalid option length: %u",
726                                 opt->fmip6_opt_len);
727                 return; /* we must not try to decode this */
728         }
729
730         switch (opt->fmip6_opt_type) {
731                 case FMIP6_OPT_IP_ADDRESS:
732                         typename = "IP Address";
733                         break;
734                 case FMIP6_OPT_NEW_ROUTER_PREFIX_INFO:
735                         typename = "New Router Prefix Information";
736                         break;
737                 case FMIP6_OPT_LINK_LAYER_ADDRESS:
738                         typename = "Link-layer Address";
739                         break;
740                 default:
741                         typename = "Unknown";
742                         break;
743         }
744
745         proto_tree_add_text(icmp6opt_tree, tvb,
746                         offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_type), 1,
747                         "Type: %u (%s)", opt->fmip6_opt_type, typename);
748         proto_tree_add_text(icmp6opt_tree, tvb,
749                         offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_len), 1,
750                         "Length: %u bytes (%u)", opt->fmip6_opt_len << 3, opt->fmip6_opt_len);
751
752         /* decode... */
753         switch (opt->fmip6_opt_type) {
754                 case FMIP6_OPT_IP_ADDRESS:
755                         {
756                                 struct fmip6_opt_ip_address fmip6_opt_ip_address, *opt_ip;
757
758                                 opt_ip = &fmip6_opt_ip_address;
759                                 tvb_memcpy(tvb, (guint8 *)opt_ip, offset, sizeof *opt_ip);
760
761                                 proto_tree_add_text(icmp6opt_tree, tvb,
762                                                 offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_optcode), 1, "Option-Code: %s",
763                                                 val_to_str(opt->fmip6_opt_optcode, names_fmip6_ip_addr_opt_code, "Unknown"));
764
765                                 proto_tree_add_text(icmp6opt_tree, tvb,
766                                                 offset + offsetof(struct fmip6_opt_ip_address, fmip6_opt_prefix_len),
767                                                 1, "Prefix length: %u", opt_ip->fmip6_opt_prefix_len);
768
769                                 proto_tree_add_text(icmp6opt_tree, tvb,
770                                                 offset + offsetof(struct fmip6_opt_ip_address, fmip6_opt_ip6_address),
771                                                 16, "IPv6 Address: %s",
772                                                 ip6_to_str(&opt_ip->fmip6_opt_ip6_address));
773                                 break;
774                         }
775                 case FMIP6_OPT_NEW_ROUTER_PREFIX_INFO:
776                         {
777                                 struct fmip6_opt_new_router_prefix_info fmip6_opt_new_router_prefix_info, *opt_nr;
778
779                                 opt_nr = &fmip6_opt_new_router_prefix_info;
780                                 tvb_memcpy(tvb, (guint8 *)opt_nr, offset, sizeof *opt_nr);
781
782                                 proto_tree_add_text(icmp6opt_tree, tvb,
783                                                 offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_optcode), 1, "Option-Code: %u",
784                                                 opt->fmip6_opt_optcode);
785
786                                 proto_tree_add_text(icmp6opt_tree, tvb,
787                                                 offset + offsetof(struct fmip6_opt_new_router_prefix_info, fmip6_opt_prefix_len),
788                                                 1, "Prefix length: %u", opt_nr->fmip6_opt_prefix_len);
789
790                                 proto_tree_add_text(icmp6opt_tree, tvb,
791                                                 offset + offsetof(struct fmip6_opt_new_router_prefix_info, fmip6_opt_prefix),
792                                                 16, "Prefix: %s",
793                                                 ip6_to_str(&opt_nr->fmip6_opt_prefix));
794                                 break;
795                         }
796                 case FMIP6_OPT_LINK_LAYER_ADDRESS:
797                         {
798                                 int len, p;
799
800                                 p = offset + sizeof(*opt);
801                                 proto_tree_add_text(icmp6opt_tree, tvb,
802                                                 offset + offsetof(struct fmip6_opt_hdr, fmip6_opt_optcode), 1, "Option-Code: %s",
803                                                 val_to_str(opt->fmip6_opt_optcode, names_fmip6_lla_opt_code, "Unknown"));
804                                 len = (opt->fmip6_opt_len << 3) - sizeof(*opt);
805                                 proto_tree_add_text(icmp6opt_tree, tvb,
806                                                 offset + sizeof(*opt), len, "Link-layer address: %s",
807                                                 bytestring_to_str(tvb_get_ptr(tvb, p, len), len, ':'));
808                                 break;
809                         }
810         }
811
812         offset += (opt->fmip6_opt_len << 3);
813         goto again;
814 }
815
816 /*
817  * draft-ietf-ipngwg-icmp-name-lookups-07.txt
818  * Note that the packet format was changed several times in the past.
819  */
820
821 static const char *
822 bitrange0(guint32 v, int s, char *buf, int buflen)
823 {
824         guint32 v0;
825         char *p, *ep;
826         int off;
827         int i, l;
828
829         if (buflen < 1)
830                 return NULL;
831         if (buflen == 1) {
832                 buf[0] = '\0';
833                 return NULL;
834         }
835
836         v0 = v;
837         p = buf;
838         ep = buf + buflen - 1;
839         memset(buf, 0, buflen);
840         off = 0;
841         while (off < 32) {
842                 /* shift till we have 0x01 */
843                 if ((v & 0x01) == 0) {
844                         switch (v & 0x0f) {
845                         case 0x00:
846                                 v >>= 4; off += 4; continue;
847                         case 0x08:
848                                 v >>= 3; off += 3; continue;
849                         case 0x04: case 0x0c:
850                                 v >>= 2; off += 2; continue;
851                         default:
852                                 v >>= 1; off += 1; continue;
853                         }
854                 }
855
856                 /* we have 0x01 with us */
857                 for (i = 0; i < 32 - off; i++) {
858                         if ((v & (0x01 << i)) == 0)
859                                 break;
860                 }
861                 if (i == 1)
862                         l = g_snprintf(p, ep - p, ",%d", s + off);
863                 else {
864                         l = g_snprintf(p, ep - p, ",%d-%d", s + off,
865                             s + off + i - 1);
866                 }
867                 if (l == -1 || l >= ep - p) {
868                         return NULL;
869                 }
870                 v >>= i; off += i;
871         }
872
873         return buf;
874 }
875
876 static const char *
877 bitrange(tvbuff_t *tvb, int offset, int l, int s)
878 {
879     static char buf[1024];
880     char *q, *eq;
881     int i;
882
883     memset(buf, 0, sizeof(buf));
884     q = buf;
885     eq = buf + sizeof(buf) - 1;
886     for (i = 0; i < l; i++) {
887         if (bitrange0(tvb_get_ntohl(tvb, offset + i * 4), s + i * 4, q, eq - q) == NULL) {
888             if (q != buf && q + 5 < buf + sizeof(buf))
889                 g_strlcpy(q, ",...", 5);
890             return buf;
891         }
892     }
893
894     return buf + 1;
895 }
896
897 static void
898 dissect_nodeinfo(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
899 {
900     proto_tree *field_tree;
901     proto_item *tf;
902     struct icmp6_nodeinfo icmp6_nodeinfo, *ni;
903     int off;
904     unsigned int j;
905     int i, n, l, p;
906     guint16 flags;
907     const char *dname;
908     guint32 ipaddr;
909
910     ni = &icmp6_nodeinfo;
911     tvb_memcpy(tvb, (guint8 *)ni, offset, sizeof *ni);
912     /* flags */
913     flags = pntohs(&ni->ni_flags);
914     tf = proto_tree_add_text(tree, tvb,
915         offset + offsetof(struct icmp6_nodeinfo, ni_flags),
916         sizeof(ni->ni_flags), "Flags: 0x%04x", flags);
917     field_tree = proto_item_add_subtree(tf, ett_nodeinfo_flag);
918     switch (pntohs(&ni->ni_qtype)) {
919     case NI_QTYPE_SUPTYPES:
920         if (ni->ni_type == ICMP6_NI_QUERY) {
921             proto_tree_add_text(field_tree, tvb,
922                 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
923                 sizeof(ni->ni_flags), "%s",
924                 decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
925                     "Compressed reply supported",
926                     "No compressed reply support"));
927         } else {
928             proto_tree_add_text(field_tree, tvb,
929                 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
930                 sizeof(ni->ni_flags), "%s",
931                 decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
932                     "Compressed", "Not compressed"));
933         }
934         break;
935     case NI_QTYPE_DNSNAME:
936         if (ni->ni_type == ICMP6_NI_REPLY) {
937             proto_tree_add_text(field_tree, tvb,
938                 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
939                 sizeof(ni->ni_flags), "%s",
940                 decode_boolean_bitfield(flags, NI_FQDN_FLAG_VALIDTTL, sizeof(flags) * 8,
941                     "Valid TTL field", "Meaningless TTL field"));
942         }
943         break;
944     case NI_QTYPE_NODEADDR:
945         proto_tree_add_text(field_tree, tvb,
946             offset + offsetof(struct icmp6_nodeinfo, ni_flags),
947             sizeof(ni->ni_flags), "%s",
948             decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_GLOBAL, sizeof(flags) * 8,
949                 "Global address",
950                 "Not global address"));
951         proto_tree_add_text(field_tree, tvb,
952             offset + offsetof(struct icmp6_nodeinfo, ni_flags),
953             sizeof(ni->ni_flags), "%s",
954             decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_SITELOCAL, sizeof(flags) * 8,
955                 "Site-local address",
956                 "Not site-local address"));
957         proto_tree_add_text(field_tree, tvb,
958             offset + offsetof(struct icmp6_nodeinfo, ni_flags),
959             sizeof(ni->ni_flags), "%s",
960             decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_LINKLOCAL, sizeof(flags) * 8,
961                 "Link-local address",
962                 "Not link-local address"));
963         proto_tree_add_text(field_tree, tvb,
964             offset + offsetof(struct icmp6_nodeinfo, ni_flags),
965             sizeof(ni->ni_flags), "%s",
966             decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_COMPAT, sizeof(flags) * 8,
967                 "IPv4 compatible/mapped address",
968                 "Not IPv4 compatible/mapped address"));
969         /* fall through */
970     case NI_QTYPE_IPV4ADDR:
971         proto_tree_add_text(field_tree, tvb,
972             offset + offsetof(struct icmp6_nodeinfo, ni_flags),
973             sizeof(ni->ni_flags), "%s",
974             decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_ALL, sizeof(flags) * 8,
975                 "All unicast address",
976                 "Unicast addresses on the queried interface"));
977         proto_tree_add_text(field_tree, tvb,
978             offset + offsetof(struct icmp6_nodeinfo, ni_flags),
979             sizeof(ni->ni_flags), "%s",
980             decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_TRUNCATE, sizeof(flags) * 8,
981                 "Truncated", "Not truncated"));
982         break;
983     }
984
985     /* nonce */
986     proto_tree_add_text(tree, tvb,
987         offset + offsetof(struct icmp6_nodeinfo, icmp6_ni_nonce[0]),
988         sizeof(ni->icmp6_ni_nonce), "Nonce: 0x%08x%08x",
989         pntohl(&ni->icmp6_ni_nonce[0]), pntohl(&ni->icmp6_ni_nonce[4]));
990
991     /* offset for "the rest of data" */
992     off = sizeof(*ni);
993
994     /* rest of data */
995     if (!tvb_bytes_exist(tvb, offset, sizeof(*ni)))
996         goto nodata;
997     if (ni->ni_type == ICMP6_NI_QUERY) {
998         switch (ni->ni_code) {
999         case ICMP6_NI_SUBJ_IPV6:
1000             n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
1001             n /= sizeof(struct e_in6_addr);
1002             tf = proto_tree_add_text(tree, tvb,
1003                 offset + sizeof(*ni), -1, "IPv6 subject addresses");
1004             field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject6);
1005             p = offset + sizeof *ni;
1006             for (i = 0; i < n; i++) {
1007                 struct e_in6_addr e_in6_addr;
1008                 tvb_get_ipv6(tvb, p, &e_in6_addr);
1009                 proto_tree_add_text(field_tree, tvb,
1010                     p, sizeof(struct e_in6_addr),
1011                     "%s", ip6_to_str(&e_in6_addr));
1012                 p += sizeof(struct e_in6_addr);
1013             }
1014             off = tvb_length_remaining(tvb, offset);
1015             break;
1016         case ICMP6_NI_SUBJ_FQDN:
1017             l = get_dns_name(tvb, offset + sizeof(*ni),
1018                 offset + sizeof(*ni), &dname);
1019             if (tvb_bytes_exist(tvb, offset + sizeof(*ni) + l, 1) &&
1020                 tvb_get_guint8(tvb, offset + sizeof(*ni) + l) == 0) {
1021                 l++;
1022                 proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
1023                     "DNS label: %s (truncated)", dname);
1024             } else {
1025                 proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
1026                     "DNS label: %s", dname);
1027             }
1028             off = tvb_length_remaining(tvb, offset + sizeof(*ni) + l);
1029             break;
1030         case ICMP6_NI_SUBJ_IPV4:
1031             n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
1032             n /= sizeof(guint32);
1033             tf = proto_tree_add_text(tree, tvb,
1034                 offset + sizeof(*ni), -1, "IPv4 subject addresses");
1035             field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject4);
1036             p = offset + sizeof *ni;
1037             for (i = 0; i < n; i++) {
1038                 ipaddr = tvb_get_ipv4(tvb, p);
1039                 proto_tree_add_text(field_tree, tvb,
1040                     p, sizeof(guint32), "%s", ip_to_str((guint8 *)&ipaddr));
1041                 p += sizeof(guint32);
1042             }
1043             off = tvb_length_remaining(tvb, offset);
1044             break;
1045         }
1046     } else {
1047         switch (pntohs(&ni->ni_qtype)) {
1048         case NI_QTYPE_NOOP:
1049             break;
1050         case NI_QTYPE_SUPTYPES:
1051             p = offset + sizeof *ni;
1052             tf = proto_tree_add_text(tree, tvb,
1053                 offset + sizeof(*ni), -1,
1054                 "Supported type bitmap%s",
1055                 (flags & 0x0001) ? ", compressed" : "");
1056             field_tree = proto_item_add_subtree(tf,
1057                 ett_nodeinfo_nodebitmap);
1058             n = 0;
1059             while (tvb_bytes_exist(tvb, p, sizeof(guint32))) { /* XXXX Check what? */
1060                 if ((flags & 0x0001) == 0) {
1061                     l = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
1062                     l /= sizeof(guint32);
1063                     i = 0;
1064                 } else {
1065                     l = tvb_get_ntohs(tvb, p);
1066                     i = tvb_get_ntohs(tvb, p + sizeof(guint16));        /*skip*/
1067                 }
1068                 if (n + l * 32 > (1 << 16))
1069                     break;
1070                 if (n + (l + i) * 32 > (1 << 16))
1071                     break;
1072                 if ((flags & 0x0001) == 0) {
1073                     proto_tree_add_text(field_tree, tvb, p,
1074                         l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
1075                         bitrange(tvb, p, l, n));
1076                     p += l * 4;
1077                 } else {
1078                     proto_tree_add_text(field_tree, tvb, p,
1079                         4 + l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
1080                         bitrange(tvb, p + 4, l, n));
1081                     p += (4 + l * 4);
1082                 }
1083                 n += l * 32 + i * 32;
1084             }
1085             off = tvb_length_remaining(tvb, offset);
1086             break;
1087         case NI_QTYPE_DNSNAME:
1088             proto_tree_add_text(tree, tvb, offset + sizeof(*ni),
1089                 sizeof(gint32), "TTL: %d", (gint32)tvb_get_ntohl(tvb, offset + sizeof *ni));
1090             tf = proto_tree_add_text(tree, tvb,
1091                 offset + sizeof(*ni) + sizeof(guint32), -1,
1092                 "DNS labels");
1093             field_tree = proto_item_add_subtree(tf, ett_nodeinfo_nodedns);
1094             j = offset + sizeof (*ni) + sizeof(guint32);
1095             while (j < tvb_reported_length(tvb)) {
1096                 l = get_dns_name(tvb, j,
1097                    offset + sizeof (*ni) + sizeof(guint32),
1098                    &dname);
1099                 if (tvb_bytes_exist(tvb, j + l, 1) &&
1100                     tvb_get_guint8(tvb, j + l) == 0) {
1101                     l++;
1102                     proto_tree_add_text(field_tree, tvb, j, l,
1103                         "DNS label: %s (truncated)", dname);
1104                 } else {
1105                     proto_tree_add_text(field_tree, tvb, j, l,
1106                         "DNS label: %s", dname);
1107                 }
1108                 j += l;
1109             }
1110             off = tvb_length_remaining(tvb, offset);
1111             break;
1112         case NI_QTYPE_NODEADDR:
1113             n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
1114             n /= sizeof(gint32) + sizeof(struct e_in6_addr);
1115             tf = proto_tree_add_text(tree, tvb,
1116                 offset + sizeof(*ni), -1, "IPv6 node addresses");
1117             field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node6);
1118             p = offset + sizeof (*ni);
1119             for (i = 0; i < n; i++) {
1120                 struct e_in6_addr e_in6_addr;
1121                 gint32 ttl;
1122                 ttl = (gint32)tvb_get_ntohl(tvb, p);
1123                 tvb_get_ipv6(tvb, p + sizeof ttl, &e_in6_addr);
1124                 proto_tree_add_text(field_tree, tvb,
1125                     p, sizeof(struct e_in6_addr) + sizeof(gint32),
1126                     "%s (TTL %d)", ip6_to_str(&e_in6_addr), ttl);
1127                 p += sizeof(struct e_in6_addr) + sizeof(gint32);
1128             }
1129             off = tvb_length_remaining(tvb, offset);
1130             break;
1131         case NI_QTYPE_IPV4ADDR:
1132             n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
1133             n /= sizeof(gint32) + sizeof(guint32);
1134             tf = proto_tree_add_text(tree, tvb,
1135                 offset + sizeof(*ni), -1, "IPv4 node addresses");
1136             field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node4);
1137             p = offset + sizeof *ni;
1138             for (i = 0; i < n; i++) {
1139                 ipaddr = tvb_get_ipv4(tvb, sizeof(gint32) + p);
1140                 proto_tree_add_text(field_tree, tvb,
1141                     p, sizeof(guint32), "%s (TTL %d)",
1142                     ip_to_str((guint8 *)&ipaddr), tvb_get_ntohl(tvb, p));
1143                 p += sizeof(gint32) + sizeof(guint32);
1144             }
1145             off = tvb_length_remaining(tvb, offset);
1146             break;
1147         }
1148     }
1149 nodata:;
1150
1151     /* the rest of data */
1152     call_dissector(data_handle,tvb_new_subset(tvb, offset + off, -1, -1), pinfo, tree);
1153 }
1154
1155 static void
1156 dissect_rrenum(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
1157 {
1158     proto_tree *field_tree, *opt_tree;
1159     proto_item *tf;
1160     struct icmp6_router_renum icmp6_router_renum, *rr;
1161     struct rr_pco_match rr_pco_match, *match;
1162     struct rr_pco_use rr_pco_use, *use;
1163     int flagoff, off;
1164     unsigned int l;
1165     guint8 flags;
1166
1167     rr = &icmp6_router_renum;
1168     tvb_memcpy(tvb, (guint8 *)rr, offset, sizeof *rr);
1169     proto_tree_add_text(tree, tvb,
1170         offset + offsetof(struct icmp6_router_renum, rr_seqnum), 4,
1171         "Sequence number: 0x%08x", pntohl(&rr->rr_seqnum));
1172     proto_tree_add_text(tree, tvb,
1173         offset + offsetof(struct icmp6_router_renum, rr_segnum), 1,
1174         "Segment number: 0x%02x", rr->rr_segnum);
1175
1176     flagoff = offset + offsetof(struct icmp6_router_renum, rr_flags);
1177     flags = tvb_get_guint8(tvb, flagoff);
1178     tf = proto_tree_add_text(tree, tvb, flagoff, 1,
1179         "Flags: 0x%02x", flags);
1180     field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1181     proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1182         decode_boolean_bitfield(flags, 0x80, 8,
1183             "Test command", "Not test command"));
1184     proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1185         decode_boolean_bitfield(flags, 0x40, 8,
1186             "Result requested", "Result not requested"));
1187     proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1188         decode_boolean_bitfield(flags, 0x20, 8,
1189             "All interfaces", "Not all interfaces"));
1190     proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1191         decode_boolean_bitfield(flags, 0x10, 8,
1192             "Site specific", "Not site specific"));
1193     proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1194         decode_boolean_bitfield(flags, 0x08, 8,
1195             "Processed previously", "Complete result"));
1196
1197     proto_tree_add_text(tree, tvb,
1198         offset + offsetof(struct icmp6_router_renum, rr_maxdelay), 2,
1199         "Max delay: 0x%04x", pntohs(&rr->rr_maxdelay));
1200     call_dissector(data_handle,tvb_new_subset(tvb, offset + sizeof(*rr), -1, -1), pinfo, tree); /*XXX*/
1201
1202     if (rr->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
1203         off = offset + sizeof(*rr);
1204         match = &rr_pco_match;
1205         tvb_memcpy(tvb, (guint8 *)match, off, sizeof *match);
1206         tf = proto_tree_add_text(tree, tvb, off, sizeof(*match),
1207             "Match-Prefix: %s/%u (%u-%u)", ip6_to_str(&match->rpm_prefix),
1208             match->rpm_matchlen, match->rpm_minlen, match->rpm_maxlen);
1209         opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
1210         proto_tree_add_text(opt_tree, tvb,
1211             off + offsetof(struct rr_pco_match, rpm_code),
1212             sizeof(match->rpm_code), "OpCode: %s (%u)",
1213             val_to_str(match->rpm_code, names_rrenum_matchcode, "Unknown"),
1214             match->rpm_code);
1215         proto_tree_add_text(opt_tree, tvb,
1216             off + offsetof(struct rr_pco_match, rpm_len),
1217             sizeof(match->rpm_len), "OpLength: %u (%u octets)",
1218             match->rpm_len, match->rpm_len * 8);
1219         proto_tree_add_text(opt_tree, tvb,
1220             off + offsetof(struct rr_pco_match, rpm_ordinal),
1221             sizeof(match->rpm_ordinal), "Ordinal: %u", match->rpm_ordinal);
1222         proto_tree_add_text(opt_tree, tvb,
1223             off + offsetof(struct rr_pco_match, rpm_matchlen),
1224             sizeof(match->rpm_matchlen), "MatchLen: %u", match->rpm_matchlen);
1225         proto_tree_add_text(opt_tree, tvb,
1226             off + offsetof(struct rr_pco_match, rpm_minlen),
1227             sizeof(match->rpm_minlen), "MinLen: %u", match->rpm_minlen);
1228         proto_tree_add_text(opt_tree, tvb,
1229             off + offsetof(struct rr_pco_match, rpm_maxlen),
1230             sizeof(match->rpm_maxlen), "MaxLen: %u", match->rpm_maxlen);
1231         proto_tree_add_text(opt_tree, tvb,
1232             off + offsetof(struct rr_pco_match, rpm_prefix),
1233             sizeof(match->rpm_prefix), "MatchPrefix: %s",
1234             ip6_to_str(&match->rpm_prefix));
1235
1236         off += sizeof(*match);
1237         use = &rr_pco_use;
1238         for (l = match->rpm_len * 8 - sizeof(*match);
1239              l >= sizeof(*use); l -= sizeof(*use), off += sizeof(*use)) {
1240             tvb_memcpy(tvb, (guint8 *)use, off, sizeof *use);
1241             tf = proto_tree_add_text(tree, tvb, off, sizeof(*use),
1242                 "Use-Prefix: %s/%u (keep %u)", ip6_to_str(&use->rpu_prefix),
1243                 use->rpu_uselen, use->rpu_keeplen);
1244             opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
1245             proto_tree_add_text(opt_tree, tvb,
1246                 off + offsetof(struct rr_pco_use, rpu_uselen),
1247                 sizeof(use->rpu_uselen), "UseLen: %u", use->rpu_uselen);
1248             proto_tree_add_text(opt_tree, tvb,
1249                 off + offsetof(struct rr_pco_use, rpu_keeplen),
1250                 sizeof(use->rpu_keeplen), "KeepLen: %u", use->rpu_keeplen);
1251             tf = proto_tree_add_text(opt_tree, tvb,
1252                 flagoff = off + offsetof(struct rr_pco_use, rpu_ramask),
1253                 sizeof(use->rpu_ramask), "FlagMask: 0x%x", use->rpu_ramask);
1254             field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1255             flags = tvb_get_guint8(tvb, flagoff);
1256             proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1257                 decode_boolean_bitfield(flags,
1258                     ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
1259                     "Onlink", "Not onlink"));
1260             proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1261                 decode_boolean_bitfield(flags,
1262                     ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8,
1263                     "Auto", "Not auto"));
1264             tf = proto_tree_add_text(opt_tree, tvb,
1265                 flagoff = off + offsetof(struct rr_pco_use, rpu_raflags),
1266                 sizeof(use->rpu_raflags), "RAFlags: 0x%x", use->rpu_raflags);
1267             field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1268             flags = tvb_get_guint8(tvb, flagoff);
1269             proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1270                 decode_boolean_bitfield(flags,
1271                     ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
1272                     "Onlink", "Not onlink"));
1273             proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1274                 decode_boolean_bitfield(flags,
1275                     ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8, "Auto", "Not auto"));
1276             if (pntohl(&use->rpu_vltime) == 0xffffffff)
1277                 proto_tree_add_text(opt_tree, tvb,
1278                     off + offsetof(struct rr_pco_use, rpu_vltime),
1279                     sizeof(use->rpu_vltime), "Valid Lifetime: infinity");
1280             else
1281                 proto_tree_add_text(opt_tree, tvb,
1282                     off + offsetof(struct rr_pco_use, rpu_vltime),
1283                     sizeof(use->rpu_vltime), "Valid Lifetime: %u",
1284                     pntohl(&use->rpu_vltime));
1285             if (pntohl(&use->rpu_pltime) == 0xffffffff)
1286                 proto_tree_add_text(opt_tree, tvb,
1287                     off + offsetof(struct rr_pco_use, rpu_pltime),
1288                     sizeof(use->rpu_pltime), "Preferred Lifetime: infinity");
1289             else
1290                 proto_tree_add_text(opt_tree, tvb,
1291                     off + offsetof(struct rr_pco_use, rpu_pltime),
1292                     sizeof(use->rpu_pltime), "Preferred Lifetime: %u",
1293                     pntohl(&use->rpu_pltime));
1294             tf = proto_tree_add_text(opt_tree, tvb,
1295                 flagoff = off + offsetof(struct rr_pco_use, rpu_flags),
1296                 sizeof(use->rpu_flags), "Flags: 0x%08x",
1297                 pntohl(&use->rpu_flags));
1298             field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1299             flags = tvb_get_guint8(tvb, flagoff);
1300             proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1301                 decode_boolean_bitfield(flags,
1302                     ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, 32,
1303                     "Decrement valid lifetime", "No decrement valid lifetime"));
1304             proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1305                 decode_boolean_bitfield(flags,
1306                     ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, 32,
1307                     "Decrement preferred lifetime",
1308                     "No decrement preferred lifetime"));
1309             proto_tree_add_text(opt_tree, tvb,
1310                 off + offsetof(struct rr_pco_use, rpu_prefix),
1311                 sizeof(use->rpu_prefix), "UsePrefix: %s",
1312                 ip6_to_str(&use->rpu_prefix));
1313         }
1314
1315     }
1316 }
1317
1318 /*
1319  * See I-D draft-vida-mld-v2-08
1320  */
1321 static const value_string mldrv2ModesNames[] = {
1322   { 1, "Include" },
1323   { 2, "Exclude" },
1324   { 3, "Changed to include" },
1325   { 4, "Changed to exclude" },
1326   { 5, "Allow new sources" },
1327   { 6, "Block old sources" },
1328   { 0, NULL }
1329 };
1330
1331 static void
1332 dissect_mldrv2( tvbuff_t *tvb, guint32 offset, guint16 count, proto_tree *tree )
1333 {
1334   proto_tree *sub_tree;
1335   proto_item *tf;
1336
1337   guint8 recordType, auxDataLen;
1338   guint32 sourceNb, recordSize, localOffset;
1339   struct e_in6_addr addr;
1340
1341   for( ; count; count--, offset += recordSize ) {
1342     localOffset = offset;
1343     recordType = tvb_get_guint8( tvb, localOffset );
1344     localOffset += 1;
1345     auxDataLen = tvb_get_guint8( tvb, localOffset );
1346     localOffset += 1;
1347     sourceNb = tvb_get_ntohs( tvb, localOffset );
1348     localOffset += 2;
1349     recordSize = 4 + 16 + (16 * sourceNb) + (auxDataLen * 4);
1350
1351     tvb_get_ipv6(tvb, localOffset, &addr);
1352     tf = proto_tree_add_text( tree, tvb, offset, recordSize,
1353 #ifdef INET6
1354                               "%s: %s (%s)", val_to_str(recordType, mldrv2ModesNames,"Unknown mode"),
1355                               get_hostname6(&addr), ip6_to_str(&addr)
1356 #else
1357                               "%s: %s", val_to_str(recordType, mldrv2ModesNames,"Unknown mode"),
1358                               ip6_to_str(&addr)
1359 #endif
1360                               );
1361     sub_tree = proto_item_add_subtree(tf, ett_multicastRR);
1362
1363     proto_tree_add_text( sub_tree, tvb, offset,   1, "Mode: %s",
1364                          val_to_str(recordType, mldrv2ModesNames,"Unknown mode") );
1365     proto_tree_add_text( sub_tree, tvb, offset+1, 1, "Aux data len: %u", auxDataLen * 4);
1366     proto_tree_add_text( sub_tree, tvb, localOffset, 16, "Multicast Address: %s", ip6_to_str(&addr) );
1367     localOffset += 16;
1368
1369     for( ; sourceNb; sourceNb--, localOffset += 16 ) {
1370       tvb_get_ipv6(tvb, localOffset, &addr);
1371       proto_tree_add_text( sub_tree, tvb, localOffset, 16,
1372 #ifdef INET6
1373                            "Source Address: %s (%s)", get_hostname6(&addr), ip6_to_str(&addr) );
1374 #else
1375                            "Source Address: %s", ip6_to_str(&addr) );
1376 #endif
1377     }
1378   }
1379 }
1380
1381 static void
1382 dissect_mldqv2(tvbuff_t *tvb, guint32 offset, guint16 count, proto_tree *tree)
1383 {
1384   struct e_in6_addr addr;
1385
1386   for ( ; count; count--, offset += 16) {
1387       tvb_get_ipv6(tvb, offset, &addr);
1388       proto_tree_add_text(tree, tvb, offset, 16,
1389                           "Source Address: %s (%s)", get_hostname6(&addr), ip6_to_str(&addr));
1390   }
1391 }
1392
1393 static void
1394 dissect_icmpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1395 {
1396     proto_tree *icmp6_tree, *field_tree;
1397     proto_item *ti, *tf = NULL;
1398     struct icmp6_hdr icmp6_hdr, *dp;
1399     struct icmp6_nodeinfo *ni = NULL;
1400     const char *codename, *typename;
1401     const char *colcodename, *coltypename;
1402     int len;
1403     guint length, reported_length;
1404     vec_t cksum_vec[4];
1405     guint32 phdr[2];
1406     guint16 cksum, computed_cksum;
1407     int offset;
1408     tvbuff_t *next_tvb;
1409
1410     if (check_col(pinfo->cinfo, COL_PROTOCOL))
1411         col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICMPv6");
1412     if (check_col(pinfo->cinfo, COL_INFO))
1413         col_clear(pinfo->cinfo, COL_INFO);
1414
1415     offset = 0;
1416     tvb_memcpy(tvb, (guint8 *)&icmp6_hdr, offset, sizeof icmp6_hdr);
1417     dp = &icmp6_hdr;
1418     codename = typename = colcodename = coltypename = "Unknown";
1419     len = sizeof(*dp);
1420     switch (dp->icmp6_type) {
1421     case ICMP6_DST_UNREACH:
1422         typename = coltypename = "Unreachable";
1423         switch (dp->icmp6_code) {
1424         case ICMP6_DST_UNREACH_NOROUTE:
1425             codename = colcodename = "Route unreachable";
1426             break;
1427         case ICMP6_DST_UNREACH_ADMIN:
1428             codename = colcodename = "Administratively prohibited";
1429             break;
1430         case ICMP6_DST_UNREACH_NOTNEIGHBOR:
1431             codename = colcodename = "Not a neighbor";
1432             break;
1433         case ICMP6_DST_UNREACH_ADDR:
1434             codename = colcodename = "Address unreachable";
1435             break;
1436         case ICMP6_DST_UNREACH_NOPORT:
1437             codename = colcodename = "Port unreachable";
1438             break;
1439         }
1440         break;
1441     case ICMP6_PACKET_TOO_BIG:
1442         typename = coltypename = "Too big";
1443         codename = colcodename = NULL;
1444         break;
1445     case ICMP6_TIME_EXCEEDED:
1446         typename = coltypename = "Time exceeded";
1447         switch (dp->icmp6_code) {
1448         case ICMP6_TIME_EXCEED_TRANSIT:
1449             codename = colcodename = "In-transit";
1450             break;
1451         case ICMP6_TIME_EXCEED_REASSEMBLY:
1452             codename = colcodename = "Reassembly";
1453             break;
1454         }
1455         break;
1456     case ICMP6_PARAM_PROB:
1457         typename = coltypename = "Parameter problem";
1458         switch (dp->icmp6_code) {
1459         case ICMP6_PARAMPROB_HEADER:
1460             codename = colcodename = "Header";
1461             break;
1462         case ICMP6_PARAMPROB_NEXTHEADER:
1463             codename = colcodename = "Next header";
1464             break;
1465         case ICMP6_PARAMPROB_OPTION:
1466             codename = colcodename = "Option";
1467             break;
1468         }
1469         break;
1470     case ICMP6_ECHO_REQUEST:
1471         typename = coltypename = "Echo request";
1472         codename = colcodename = NULL;
1473         break;
1474     case ICMP6_ECHO_REPLY:
1475         typename = coltypename = "Echo reply";
1476         codename = colcodename = NULL;
1477         break;
1478     case ICMP6_MEMBERSHIP_QUERY:
1479         typename = coltypename = "Multicast listener query";
1480         codename = colcodename = NULL;
1481         break;
1482     case ICMP6_MEMBERSHIP_REPORT:
1483         typename = coltypename = "Multicast listener report";
1484         codename = colcodename = NULL;
1485         break;
1486     case ICMP6_MEMBERSHIP_REDUCTION:
1487         typename = coltypename = "Multicast listener done";
1488         codename = colcodename = NULL;
1489         break;
1490     case ND_ROUTER_SOLICIT:
1491         typename = coltypename = "Router solicitation";
1492         codename = colcodename = NULL;
1493         len = sizeof(struct nd_router_solicit);
1494         break;
1495     case ND_ROUTER_ADVERT:
1496         typename = coltypename = "Router advertisement";
1497         codename = colcodename = NULL;
1498         len = sizeof(struct nd_router_advert);
1499         break;
1500     case ND_NEIGHBOR_SOLICIT:
1501         typename = coltypename = "Neighbor solicitation";
1502         codename = colcodename = NULL;
1503         len = sizeof(struct nd_neighbor_solicit);
1504         break;
1505     case ND_NEIGHBOR_ADVERT:
1506         typename = coltypename = "Neighbor advertisement";
1507         codename = colcodename = NULL;
1508         len = sizeof(struct nd_neighbor_advert);
1509         break;
1510     case ND_REDIRECT:
1511         typename = coltypename = "Redirect";
1512         codename = colcodename = NULL;
1513         len = sizeof(struct nd_redirect);
1514         break;
1515     case ICMP6_ROUTER_RENUMBERING:
1516         typename = coltypename = "Router renumbering";
1517         switch (dp->icmp6_code) {
1518         case ICMP6_ROUTER_RENUMBERING_COMMAND:
1519             codename = colcodename = "Command";
1520             break;
1521         case ICMP6_ROUTER_RENUMBERING_RESULT:
1522             codename = colcodename = "Result";
1523             break;
1524         case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
1525             codename = colcodename = "Sequence number reset";
1526             break;
1527         }
1528         len = sizeof(struct icmp6_router_renum);
1529         break;
1530     case ICMP6_NI_QUERY:
1531     case ICMP6_NI_REPLY:
1532         ni = (struct icmp6_nodeinfo *)dp;
1533         if (ni->ni_type == ICMP6_NI_QUERY) {
1534             typename = coltypename = "Node information query";
1535             switch (ni->ni_code) {
1536             case ICMP6_NI_SUBJ_IPV6:
1537                 codename = "Query subject = IPv6 addresses";
1538                 break;
1539             case ICMP6_NI_SUBJ_FQDN:
1540                 if (tvb_bytes_exist(tvb, offset, sizeof(*ni)))
1541                     codename = "Query subject = DNS name";
1542                 else
1543                     codename = "Query subject = empty";
1544                 break;
1545             case ICMP6_NI_SUBJ_IPV4:
1546                 codename = "Query subject = IPv4 addresses";
1547                 break;
1548             }
1549         } else {
1550             typename = coltypename = "Node information reply";
1551             switch (ni->ni_code) {
1552             case ICMP6_NI_SUCCESS:
1553                 codename = "Successful";
1554                 break;
1555             case ICMP6_NI_REFUSED:
1556                 codename = "Refused";
1557                 break;
1558             case ICMP6_NI_UNKNOWN:
1559                 codename = "Unknown query type";
1560                 break;
1561             }
1562         }
1563         colcodename = val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1564             "Unknown");
1565         len = sizeof(struct icmp6_nodeinfo);
1566         break;
1567     case ICMP6_MIP6_DHAAD_REQUEST:
1568         typename = coltypename = "Dynamic Home Agent Address Discovery Request";
1569         codename = "Should always be zero";
1570         colcodename = NULL;
1571         break;
1572     case ICMP6_MIP6_DHAAD_REPLY:
1573         typename = coltypename = "Dynamic Home Agent Address Discovery Reply";
1574         codename = "Should always be zero";
1575         colcodename = NULL;
1576         break;
1577     case ICMP6_MIP6_MPS:
1578         typename = coltypename = "Mobile Prefix Solicitation";
1579         codename = "Should always be zero";
1580         colcodename = NULL;
1581         break;
1582     case ICMP6_MIP6_MPA:
1583         typename = coltypename = "Mobile Prefix Advertisement";
1584         codename = "Should always be zero";
1585         colcodename = NULL;
1586         break;
1587         case ICMP6_CERT_PATH_SOL:
1588                 typename = coltypename = "Certification Path Solicitation";
1589         codename = "Should always be zero";
1590         colcodename = NULL;
1591         break;
1592         case ICMP6_CERT_PATH_AD:
1593                 typename = coltypename = "Certification Path Advertisement";
1594         codename = "Should always be zero";
1595         colcodename = NULL;
1596         break;
1597     case ICMP6_MLDV2_REPORT:
1598         typename = coltypename = "Multicast Listener Report Message v2";
1599         codename = "Should always be zero";
1600         colcodename = NULL;
1601         break;
1602                 case ICMP6_EXPERIMENTAL_MOBILITY:
1603                         typename = coltypename ="Experimental Mobility";
1604                         switch (dp->icmp6_data8[0]) {
1605                                 case FMIP6_SUBTYPE_RTSOLPR:
1606                                         typename = coltypename ="RtSolPr (ICMPv6 Experimental Mobility)";
1607                                         codename = "Should always be zero";
1608                                         colcodename = NULL;
1609                                         break;
1610                                 case FMIP6_SUBTYPE_PRRTADV:
1611                                         typename = coltypename ="PrRtAdv (ICMPv6 Experimental Mobility)";
1612                                         codename = val_to_str(dp->icmp6_code, names_fmip6_prrtadv_code, "Unknown");
1613                                         colcodename = NULL;
1614                                         break;
1615                                 case FMIP6_SUBTYPE_HI:
1616                                         typename = coltypename ="HI (ICMPv6 Experimental Mobility)";
1617                                         codename = val_to_str(dp->icmp6_code, names_fmip6_hi_code, "Unknown");
1618                                         colcodename = NULL;
1619                                         break;
1620                                 case FMIP6_SUBTYPE_HACK:
1621                                         typename = coltypename ="HAck (ICMPv6 Experimental Mobility)";
1622                                         codename = val_to_str(dp->icmp6_code, names_fmip6_hack_code, "Unknown");
1623                                         colcodename = NULL;
1624                                         break;
1625                         }
1626                         break;
1627     }
1628
1629     if (check_col(pinfo->cinfo, COL_INFO)) {
1630         char typebuf[256], codebuf[256];
1631
1632         if (coltypename && strcmp(coltypename, "Unknown") == 0) {
1633             g_snprintf(typebuf, sizeof(typebuf), "Unknown (0x%02x)",
1634                 dp->icmp6_type);
1635             coltypename = typebuf;
1636         }
1637         if (colcodename && strcmp(colcodename, "Unknown") == 0) {
1638             g_snprintf(codebuf, sizeof(codebuf), "Unknown (0x%02x)",
1639                 dp->icmp6_code);
1640             colcodename = codebuf;
1641         }
1642         if (colcodename) {
1643             col_add_fstr(pinfo->cinfo, COL_INFO, "%s (%s)", coltypename, colcodename);
1644         } else {
1645             col_add_str(pinfo->cinfo, COL_INFO, coltypename);
1646         }
1647     }
1648
1649     if (tree) {
1650         /* !!! specify length */
1651         ti = proto_tree_add_item(tree, proto_icmpv6, tvb, offset, -1, FALSE);
1652         icmp6_tree = proto_item_add_subtree(ti, ett_icmpv6);
1653
1654         proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_type, tvb,
1655             offset + offsetof(struct icmp6_hdr, icmp6_type), 1,
1656             dp->icmp6_type,
1657             "Type: %u (%s)", dp->icmp6_type, typename);
1658         if (codename) {
1659             proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
1660                 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
1661                 dp->icmp6_code,
1662                 "Code: %u (%s)", dp->icmp6_code, codename);
1663         } else {
1664             proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
1665                 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
1666                 dp->icmp6_code,
1667                 "Code: %u", dp->icmp6_code);
1668         }
1669         cksum = (guint16)g_htons(dp->icmp6_cksum);
1670         length = tvb_length(tvb);
1671         reported_length = tvb_reported_length(tvb);
1672         if (!pinfo->fragmented && length >= reported_length) {
1673             /* The packet isn't part of a fragmented datagram and isn't
1674                truncated, so we can checksum it. */
1675
1676             /* Set up the fields of the pseudo-header. */
1677             cksum_vec[0].ptr = pinfo->src.data;
1678             cksum_vec[0].len = pinfo->src.len;
1679             cksum_vec[1].ptr = pinfo->dst.data;
1680             cksum_vec[1].len = pinfo->dst.len;
1681             cksum_vec[2].ptr = (const guint8 *)&phdr;
1682             phdr[0] = g_htonl(tvb_reported_length(tvb));
1683             phdr[1] = g_htonl(IP_PROTO_ICMPV6);
1684             cksum_vec[2].len = 8;
1685             cksum_vec[3].len = tvb_reported_length(tvb);
1686             cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, cksum_vec[3].len);
1687             computed_cksum = in_cksum(cksum_vec, 4);
1688             if (computed_cksum == 0) {
1689                 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1690                         tvb,
1691                         offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1692                         cksum,
1693                         "Checksum: 0x%04x [correct]", cksum);
1694             } else {
1695                 proto_tree_add_boolean_hidden(icmp6_tree, hf_icmpv6_checksum_bad,
1696                         tvb,
1697                         offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1698                         TRUE);
1699                 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1700                         tvb,
1701                         offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1702                         cksum,
1703                         "Checksum: 0x%04x [incorrect, should be 0x%04x]",
1704                         cksum, in_cksum_shouldbe(cksum, computed_cksum));
1705             }
1706         } else {
1707             proto_tree_add_uint(icmp6_tree, hf_icmpv6_checksum, tvb,
1708                 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1709                 cksum);
1710         }
1711
1712         /* decode... */
1713         switch (dp->icmp6_type) {
1714         case ICMP6_DST_UNREACH:
1715         case ICMP6_TIME_EXCEEDED:
1716             dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1717                 icmp6_tree);
1718             break;
1719         case ICMP6_PACKET_TOO_BIG:
1720             proto_tree_add_text(icmp6_tree, tvb,
1721                 offset + offsetof(struct icmp6_hdr, icmp6_mtu), 4,
1722                 "MTU: %u", pntohl(&dp->icmp6_mtu));
1723             dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1724                 icmp6_tree);
1725             break;
1726         case ICMP6_PARAM_PROB:
1727             proto_tree_add_text(icmp6_tree, tvb,
1728                 offset + offsetof(struct icmp6_hdr, icmp6_pptr), 4,
1729                 "Problem pointer: 0x%04x", pntohl(&dp->icmp6_pptr));
1730             dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1731                 icmp6_tree);
1732             break;
1733         case ICMP6_ECHO_REQUEST:
1734         case ICMP6_ECHO_REPLY:
1735             proto_tree_add_text(icmp6_tree, tvb,
1736                 offset + offsetof(struct icmp6_hdr, icmp6_id), 2,
1737                 "ID: 0x%04x", (guint16)g_ntohs(dp->icmp6_id));
1738             proto_tree_add_text(icmp6_tree, tvb,
1739                 offset + offsetof(struct icmp6_hdr, icmp6_seq), 2,
1740                 "Sequence: 0x%04x", (guint16)g_ntohs(dp->icmp6_seq));
1741             next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1742             call_dissector(data_handle,next_tvb, pinfo, icmp6_tree);
1743             break;
1744         case ICMP6_MEMBERSHIP_QUERY:
1745         case ICMP6_MEMBERSHIP_REPORT:
1746         case ICMP6_MEMBERSHIP_REDUCTION:
1747 #define MLDV2_MINLEN 28
1748 #define MLDV1_MINLEN 24
1749             if (dp->icmp6_type == ICMP6_MEMBERSHIP_QUERY) {
1750                 if (length >= MLDV2_MINLEN) {
1751                     guint32 mrc;
1752                     guint16 qqi;
1753                     guint8 flag;
1754                     guint16 nsrcs;
1755
1756                     mrc = g_ntohs(dp->icmp6_maxdelay);
1757                     flag = tvb_get_guint8(tvb, offset + sizeof(*dp) + 16);
1758                     qqi = tvb_get_guint8(tvb, offset + sizeof(*dp) + 16 + 1);
1759                     nsrcs = tvb_get_ntohs(tvb, offset + sizeof(*dp) + 16 + 2);
1760
1761                     if (mrc >= 32768)
1762                         mrc = ((mrc & 0x0fff) | 0x1000) <<
1763                                 (((mrc & 0x7000) >> 12) + 3);
1764                     proto_tree_add_text(icmp6_tree, tvb,
1765                         offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
1766                         "Maximum response delay[ms]: %u", mrc);
1767
1768                     proto_tree_add_text(icmp6_tree, tvb, offset + sizeof(*dp),
1769                         16, "Multicast Address: %s",
1770                         ip6_to_str((const struct e_in6_addr *)(tvb_get_ptr(tvb,
1771                             offset + sizeof *dp, sizeof (struct e_in6_addr)))));
1772
1773                     proto_tree_add_text(icmp6_tree, tvb,
1774                         offset + sizeof(*dp) + 16, 1, "S Flag: %s",
1775                         flag & 0x08 ? "ON" : "OFF");
1776                     proto_tree_add_text(icmp6_tree, tvb,
1777                         offset + sizeof(*dp) + 16, 1, "Robustness: %d",
1778                         flag & 0x07);
1779                     if (qqi >= 128)
1780                         qqi = ((qqi & 0x0f) | 0x10) << (((qqi & 0x70) >> 4) + 3);
1781                     proto_tree_add_text(icmp6_tree, tvb,
1782                         offset + sizeof(*dp) + 17, 1, "QQI: %d", qqi);
1783
1784                     dissect_mldqv2(tvb, offset + sizeof(*dp) + 20, nsrcs,
1785                         icmp6_tree);
1786                     break;
1787                 } else if (length > MLDV1_MINLEN) {
1788                     next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1789                     call_dissector(data_handle,next_tvb, pinfo, tree);
1790                     break;
1791                 }
1792                 /* MLDv1 Query -> FALLTHOUGH */
1793             }
1794 #undef MLDV2_MINLEN
1795 #undef MLDV1_MINLEN
1796             proto_tree_add_text(icmp6_tree, tvb,
1797                 offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
1798                 "Maximum response delay: %u",
1799                 (guint16)g_ntohs(dp->icmp6_maxdelay));
1800             proto_tree_add_text(icmp6_tree, tvb, offset + sizeof(*dp), 16,
1801                 "Multicast Address: %s",
1802                 ip6_to_str((const struct e_in6_addr *)(tvb_get_ptr(tvb, offset + sizeof *dp, sizeof (struct e_in6_addr)))));
1803             break;
1804         case ND_ROUTER_SOLICIT:
1805             dissect_icmpv6ndopt(tvb, offset + sizeof(*dp), pinfo, icmp6_tree);
1806             break;
1807         case ICMP6_MLDV2_REPORT: {
1808           guint16 nbRecords;
1809
1810           nbRecords = tvb_get_ntohs( tvb, offset+4+2 );
1811           dissect_mldrv2( tvb, offset+4+2+2, nbRecords, icmp6_tree );
1812           break;
1813         }
1814         case ND_ROUTER_ADVERT:
1815           {
1816             struct nd_router_advert nd_router_advert, *ra;
1817             int flagoff;
1818             guint32 ra_flags;
1819
1820             ra = &nd_router_advert;
1821             tvb_memcpy(tvb, (guint8 *)ra, offset, sizeof *ra);
1822
1823             /* Current hop limit */
1824             proto_tree_add_uint(icmp6_tree, hf_icmpv6_ra_cur_hop_limit, tvb,
1825                 offset + offsetof(struct nd_router_advert, nd_ra_curhoplimit),
1826                 1, ra->nd_ra_curhoplimit);
1827
1828             /* Flags */
1829             flagoff = offset + offsetof(struct nd_router_advert, nd_ra_flags_reserved);
1830             ra_flags = tvb_get_guint8(tvb, flagoff);
1831             tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 1, "Flags: 0x%02x", ra_flags);
1832             field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1833
1834             proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1835                 decode_boolean_bitfield(ra_flags,
1836                         ND_RA_FLAG_MANAGED, 8, "Managed", "Not managed"));
1837             proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1838                 decode_boolean_bitfield(ra_flags,
1839                         ND_RA_FLAG_OTHER, 8, "Other", "Not other"));
1840             proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1841                 decode_boolean_bitfield(ra_flags,
1842                         ND_RA_FLAG_HOME_AGENT, 8,
1843                         "Home Agent", "Not Home Agent"));
1844             proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1845                 decode_enumerated_bitfield(ra_flags, ND_RA_FLAG_RTPREF_MASK, 8,
1846                 names_router_pref, "Router preference: %s"));
1847
1848             /* Router lifetime */
1849             proto_tree_add_uint(icmp6_tree, hf_icmpv6_ra_router_lifetime, tvb,
1850                 offset + offsetof(struct nd_router_advert, nd_ra_router_lifetime),
1851                 2, (guint16)g_ntohs(ra->nd_ra_router_lifetime));
1852
1853             /* Reachable time */
1854             proto_tree_add_uint(icmp6_tree, hf_icmpv6_ra_reachable_time, tvb,
1855                 offset + offsetof(struct nd_router_advert, nd_ra_reachable), 4,
1856                 pntohl(&ra->nd_ra_reachable));
1857
1858             /* Retrans timer */
1859             proto_tree_add_uint(icmp6_tree, hf_icmpv6_ra_retrans_timer, tvb,
1860                 offset + offsetof(struct nd_router_advert, nd_ra_retransmit), 4,
1861                 pntohl(&ra->nd_ra_retransmit));
1862
1863             dissect_icmpv6ndopt(tvb, offset + sizeof(struct nd_router_advert), pinfo, icmp6_tree);
1864             break;
1865           }
1866         case ND_NEIGHBOR_SOLICIT:
1867           {
1868             struct nd_neighbor_solicit nd_neighbor_solicit, *ns;
1869
1870             ns = &nd_neighbor_solicit;
1871             tvb_memcpy(tvb, (guint8 *)ns, offset, sizeof *ns);
1872             proto_tree_add_text(icmp6_tree, tvb,
1873                         offset + offsetof(struct nd_neighbor_solicit, nd_ns_target), 16,
1874 #ifdef INET6
1875                         "Target: %s (%s)",
1876                         get_hostname6(&ns->nd_ns_target),
1877 #else
1878                         "Target: %s",
1879 #endif
1880                         ip6_to_str(&ns->nd_ns_target));
1881
1882             dissect_icmpv6ndopt(tvb, offset + sizeof(*ns), pinfo, icmp6_tree);
1883             break;
1884           }
1885         case ND_NEIGHBOR_ADVERT:
1886           {
1887             int flagoff, targetoff;
1888             guint32 na_flags;
1889             struct e_in6_addr na_target;
1890
1891             flagoff = offset + offsetof(struct nd_neighbor_advert, nd_na_flags_reserved);
1892             na_flags = tvb_get_ntohl(tvb, flagoff);
1893
1894             tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 4, "Flags: 0x%08x", na_flags);
1895             field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1896             proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1897                 decode_boolean_bitfield(na_flags,
1898                         ND_NA_FLAG_ROUTER, 32, "Router", "Not router"));
1899             proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1900                 decode_boolean_bitfield(na_flags,
1901                         ND_NA_FLAG_SOLICITED, 32, "Solicited", "Not adverted"));
1902             proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1903                 decode_boolean_bitfield(na_flags,
1904                         ND_NA_FLAG_OVERRIDE, 32, "Override", "Not override"));
1905
1906             targetoff = offset + offsetof(struct nd_neighbor_advert, nd_na_target);
1907             tvb_memcpy(tvb, (guint8 *)&na_target, targetoff, sizeof na_target);
1908             proto_tree_add_text(icmp6_tree, tvb, targetoff, 16,
1909 #ifdef INET6
1910                         "Target: %s (%s)",
1911                         get_hostname6(&na_target),
1912 #else
1913                         "Target: %s",
1914 #endif
1915                         ip6_to_str(&na_target));
1916
1917             dissect_icmpv6ndopt(tvb, offset + sizeof(struct nd_neighbor_advert), pinfo, icmp6_tree);
1918             break;
1919           }
1920         case ND_REDIRECT:
1921           {
1922             struct nd_redirect nd_redirect, *rd;
1923
1924             rd = &nd_redirect;
1925             tvb_memcpy(tvb, (guint8 *)rd, offset, sizeof *rd);
1926             proto_tree_add_text(icmp6_tree, tvb,
1927                         offset + offsetof(struct nd_redirect, nd_rd_target), 16,
1928 #ifdef INET6
1929                         "Target: %s (%s)",
1930                         get_hostname6(&rd->nd_rd_target),
1931 #else
1932                         "Target: %s",
1933 #endif
1934                         ip6_to_str(&rd->nd_rd_target));
1935
1936             proto_tree_add_text(icmp6_tree, tvb,
1937                         offset + offsetof(struct nd_redirect, nd_rd_dst), 16,
1938 #ifdef INET6
1939                         "Destination: %s (%s)",
1940                         get_hostname6(&rd->nd_rd_dst),
1941 #else
1942                         "Destination: %s",
1943 #endif
1944                         ip6_to_str(&rd->nd_rd_dst));
1945
1946             dissect_icmpv6ndopt(tvb, offset + sizeof(*rd), pinfo, icmp6_tree);
1947             break;
1948           }
1949         case ICMP6_ROUTER_RENUMBERING:
1950             dissect_rrenum(tvb, offset, pinfo, icmp6_tree);
1951             break;
1952         case ICMP6_NI_QUERY:
1953         case ICMP6_NI_REPLY:
1954             ni = (struct icmp6_nodeinfo *)dp;
1955             proto_tree_add_text(icmp6_tree, tvb,
1956                 offset + offsetof(struct icmp6_nodeinfo, ni_qtype),
1957                 sizeof(ni->ni_qtype),
1958                 "Query type: 0x%04x (%s)", pntohs(&ni->ni_qtype),
1959                 val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1960                 "Unknown"));
1961             dissect_nodeinfo(tvb, offset, pinfo, icmp6_tree);
1962             break;
1963         case ICMP6_MIP6_DHAAD_REQUEST:
1964             proto_tree_add_text(icmp6_tree, tvb,
1965                 offset + 4, 2, "Identifier: %d (0x%02x)",
1966                 tvb_get_ntohs(tvb, offset + 4),
1967                 tvb_get_ntohs(tvb, offset + 4));
1968             proto_tree_add_text(icmp6_tree, tvb,
1969                 offset + 6, 2, "Reserved: %d",
1970                 tvb_get_ntohs(tvb, offset + 6));
1971             break;
1972         case ICMP6_MIP6_DHAAD_REPLY:
1973             proto_tree_add_text(icmp6_tree, tvb,
1974                 offset + 4, 2, "Identifier: %d (0x%02x)",
1975                 tvb_get_ntohs(tvb, offset + 4),
1976                 tvb_get_ntohs(tvb, offset + 4));
1977             proto_tree_add_text(icmp6_tree, tvb,
1978                 offset + 6, 2, "Reserved: %d",
1979                 tvb_get_ntohs(tvb, offset + 6));
1980             /* Show all Home Agent Addresses */
1981             {
1982                 int i, suboffset;
1983                 int ha_num = (length - 8)/16;
1984
1985                 for (i = 0; i < ha_num; i++) {
1986                     suboffset = 16 * i;
1987                     proto_tree_add_ipv6(icmp6_tree, hf_icmpv6_haad_ha_addrs,
1988                         tvb, offset + 8 + suboffset, 16,
1989                         tvb_get_ptr(tvb, offset + 8 + suboffset, 16));
1990                 }
1991             }
1992             break;
1993         case ICMP6_MIP6_MPS:
1994             proto_tree_add_text(icmp6_tree, tvb,
1995                 offset + 4, 2, "Identifier: %d (0x%02x)",
1996                 tvb_get_ntohs(tvb, offset + 4),
1997                 tvb_get_ntohs(tvb, offset + 4));
1998             proto_tree_add_text(icmp6_tree, tvb,
1999                 offset + 6, 2, "Reserved: %d",
2000                 tvb_get_ntohs(tvb, offset + 6));
2001             break;
2002         case ICMP6_MIP6_MPA:
2003             proto_tree_add_text(icmp6_tree, tvb,
2004                 offset + 4, 2, "Identifier: %d (0x%02x)",
2005                 tvb_get_ntohs(tvb, offset + 4),
2006                 tvb_get_ntohs(tvb, offset + 4));
2007             proto_tree_add_text(icmp6_tree, tvb,
2008                 offset + 6, 1,
2009                 decode_boolean_bitfield(tvb_get_guint8(tvb, offset + 6),
2010                     0x80, 8,
2011                     "Managed Address Configuration",
2012                     "No Managed Address Configuration"));
2013             proto_tree_add_text(icmp6_tree, tvb,
2014                 offset + 6, 1,
2015                 decode_boolean_bitfield(tvb_get_guint8(tvb, offset + 6),
2016                     0x40, 8,
2017                     "Other Stateful Configuration",
2018                     "No Other Stateful Configuration"));
2019             proto_tree_add_text(icmp6_tree, tvb,
2020                 offset + 7, 1, "Reserved: %d",
2021                 tvb_get_guint8(tvb, offset + 7));
2022             /* Show all options */
2023             dissect_icmpv6ndopt(tvb, offset + 8, pinfo, icmp6_tree);
2024             break;
2025         case ICMP6_EXPERIMENTAL_MOBILITY:
2026                 switch (dp->icmp6_data8[0]) {
2027                         case FMIP6_SUBTYPE_RTSOLPR:
2028                                 {
2029                                         struct fmip6_rtsolpr *rtsolpr;
2030                                         rtsolpr = (struct fmip6_rtsolpr*) dp;
2031                                         proto_tree_add_text(icmp6_tree, tvb,
2032                                                         offset + 4, 1,
2033                                                         "Subtype: Router Solicitation for Proxy Advertisement");
2034                                         proto_tree_add_text(icmp6_tree, tvb,
2035                                                         offset + 6, 2,
2036                                                         "Identifier: %d", pntohs(&rtsolpr->fmip6_rtsolpr_id));
2037                                         dissect_icmpv6fmip6opt(tvb, offset + sizeof(*dp), icmp6_tree);
2038                                         break;
2039                                 }
2040                         case FMIP6_SUBTYPE_PRRTADV:
2041                                 {
2042                                         struct fmip6_prrtadv *prrtadv;
2043                                         prrtadv = (struct fmip6_prrtadv*) dp;
2044                                         proto_tree_add_text(icmp6_tree, tvb,
2045                                                         offset + 4, 1,
2046                                                         "Subtype: Proxy Router Advertisement");
2047                                         proto_tree_add_text(icmp6_tree, tvb,
2048                                                         offset + 6, 2,
2049                                                         "Identifier: %d", pntohs(&prrtadv->fmip6_prrtadv_id));
2050                                         dissect_icmpv6fmip6opt(tvb, offset + sizeof(*dp), icmp6_tree);
2051                                         break;
2052                                 }
2053                         case FMIP6_SUBTYPE_HI:
2054                                 {
2055                                         struct fmip6_hi *hi;
2056                                         int flagoff;
2057                                         guint8 hi_flags;
2058                                         hi = (struct fmip6_hi*) dp;
2059                                         proto_tree_add_text(icmp6_tree, tvb,
2060                                                         offset + 4, 1,
2061                                                         "Subtype: Handover Initiate");
2062
2063                                         flagoff = offset + offsetof(struct fmip6_hi, fmip6_hi_flags_reserved);
2064                                         hi_flags = tvb_get_guint8(tvb, flagoff);
2065                                         tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 1, "Flags: 0x%02x", hi_flags);
2066                                         field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
2067                                         proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
2068                                                         decode_boolean_bitfield(hi_flags,
2069                                                                 FMIP_HI_FLAG_ASSIGNED, 8, "Assigned", "Not assigned"));
2070                                         proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
2071                                                         decode_boolean_bitfield(hi_flags,
2072                                                                 FMIP_HI_FLAG_BUFFER, 8, "Buffered", "Not buffered"));
2073                                         proto_tree_add_text(icmp6_tree, tvb,
2074                                                         offset + 6, 2,
2075                                                         "Identifier: %d", pntohs(&hi->fmip6_hi_id));
2076                                         dissect_icmpv6fmip6opt(tvb, offset + sizeof(*dp), icmp6_tree);
2077                                         break;
2078                                 }
2079                         case FMIP6_SUBTYPE_HACK:
2080                                 {
2081                                         struct fmip6_hack *hack;
2082                                         hack = (struct fmip6_hack*) dp;
2083                                         proto_tree_add_text(icmp6_tree, tvb,
2084                                                         offset + 4, 1,
2085                                                         "Subtype: Handover Acknowledge");
2086                                         proto_tree_add_text(icmp6_tree, tvb,
2087                                                         offset + 6, 2,
2088                                                         "Identifier: %d", pntohs(&hack->fmip6_hack_id));
2089                                         dissect_icmpv6fmip6opt(tvb, offset + sizeof(*dp), icmp6_tree);
2090                                         break;
2091                                 }
2092                 }
2093             break;
2094         case ICMP6_CERT_PATH_AD:
2095                 /*RFC 3971 6.4.2.  Certification Path Advertisement Message Format */
2096                 offset = offset +4;
2097                 proto_tree_add_text(icmp6_tree, tvb, offset, -1,"Certification Path Advertisement Message");
2098
2099                 /* Identifier A 16-bit unsigned integer field */
2100                 proto_tree_add_item(icmp6_tree, hf_icmpv6_identifier, tvb, offset, 2, FALSE);
2101                 offset = offset + 2;
2102                 /* All Components  A 16-bit unsigned integer field*/
2103                 proto_tree_add_item(icmp6_tree, hf_icmpv6_all_comp, tvb, offset, 2, FALSE);
2104                 offset = offset + 2;
2105
2106                 /* Component A 16-bit unsigned integer field, used to inform the receiver
2107                  * which certificate is being sent.
2108                  */
2109                 proto_tree_add_item(icmp6_tree, hf_icmpv6_comp, tvb, offset, 2, FALSE);
2110                 offset = offset + 2;
2111
2112                 /* Reserved */
2113                 proto_tree_add_text(icmp6_tree, tvb, offset, 2,"Reserved");
2114                 offset = offset + 2;
2115
2116                 dissect_icmpv6ndopt(tvb, offset, pinfo, icmp6_tree);
2117                 break;
2118         default:
2119             next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
2120             call_dissector(data_handle,next_tvb, pinfo, tree);
2121             break;
2122         }
2123     }
2124 }
2125
2126 void
2127 proto_register_icmpv6(void)
2128 {
2129   static hf_register_info hf[] = {
2130     { &hf_icmpv6_type,
2131       { "Type",           "icmpv6.type",        FT_UINT8,  BASE_DEC, NULL, 0x0,
2132         "", HFILL }},
2133     { &hf_icmpv6_code,
2134       { "Code",           "icmpv6.code",        FT_UINT8,  BASE_DEC, NULL, 0x0,
2135         "", HFILL }},
2136     { &hf_icmpv6_checksum,
2137       { "Checksum",       "icmpv6.checksum",    FT_UINT16, BASE_HEX, NULL, 0x0,
2138         "", HFILL }},
2139     { &hf_icmpv6_checksum_bad,
2140       { "Bad Checksum",   "icmpv6.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2141         "", HFILL }},
2142     { &hf_icmpv6_haad_ha_addrs,
2143       { "Home Agent Addresses", "icmpv6.haad.ha_addrs",
2144        FT_IPv6, BASE_HEX, NULL, 0x0,
2145        "", HFILL }},
2146     { &hf_icmpv6_ra_cur_hop_limit,
2147       { "Cur hop limit",           "icmpv6.ra.cur_hop_limit", FT_UINT8,  BASE_DEC, NULL, 0x0,
2148         "Current hop limit", HFILL }},
2149     { &hf_icmpv6_ra_router_lifetime,
2150       { "Router lifetime",           "icmpv6.ra.router_lifetime", FT_UINT16,  BASE_DEC, NULL, 0x0,
2151         "Router lifetime (s)", HFILL }},
2152     { &hf_icmpv6_ra_reachable_time,
2153       { "Reachable time",           "icmpv6.ra.reachable_time", FT_UINT32,  BASE_DEC, NULL, 0x0,
2154         "Reachable time (ms)", HFILL }},
2155     { &hf_icmpv6_ra_retrans_timer,
2156       { "Retrans timer",           "icmpv6.ra.retrans_timer", FT_UINT32,  BASE_DEC, NULL, 0x0,
2157         "Retrans timer (ms)", HFILL }},
2158     { &hf_icmpv6_option,
2159       { "ICMPv6 Option",           "icmpv6.option", FT_NONE,  BASE_NONE, NULL, 0x0,
2160         "Option", HFILL }},
2161     { &hf_icmpv6_option_type,
2162       { "Type",           "icmpv6.option.type", FT_UINT8,  BASE_DEC, VALS(option_vals), 0x0,
2163         "Options type", HFILL }},
2164     { &hf_icmpv6_option_length,
2165       { "Length",           "icmpv6.option.length", FT_UINT8,  BASE_DEC, NULL, 0x0,
2166         "Options length (in bytes)", HFILL }},
2167         { &hf_icmpv6_opt_cga_pad_len,
2168       { "Pad Length",           "icmpv6.option.cga.pad_length", FT_UINT8,  BASE_DEC, NULL, 0x0,
2169         "Pad Length (in bytes)", HFILL }},
2170         { &hf_icmpv6_opt_cga,
2171       { "CGA",           "icmpv6.option.cga", FT_BYTES,  BASE_NONE, NULL, 0x0,
2172         "CGA", HFILL }},
2173         { &hf_icmpv6_opt_rsa_key_hash,
2174       { "Key Hash",           "icmpv6.option.rsa.key_hash", FT_BYTES,  BASE_HEX, NULL, 0x0,
2175         "Key Hash", HFILL }},
2176         { &hf_icmpv6_opt_name_type,
2177       { "Name Type",           "icmpv6.option.name_type", FT_UINT8,  BASE_DEC, VALS(icmpv6_option_name_type_vals), 0x0,
2178         "Name Type", HFILL }},
2179         { &hf_icmpv6_opt_name_x501,
2180       { "DER Encoded X.501 Name",           "icmpv6.option.name_x501", FT_BYTES,  BASE_HEX, NULL, 0x0,
2181         "DER Encoded X.501 Name", HFILL }},
2182         { &hf_icmpv6_opt_name_fqdn,
2183       { "FQDN",           "icmpv6.option.name_type.fqdn", FT_STRING,  BASE_NONE, NULL, 0x0,
2184         "FQDN", HFILL }},
2185         { &hf_icmpv6_opt_cert_type,
2186       { "Cert Type",           "icmpv6.option.name_type", FT_UINT8,  BASE_DEC, VALS(icmpv6_option_cert_type_vals), 0x0,
2187         "Cert Type", HFILL }},
2188         { &hf_icmpv6_identifier,
2189       { "Identifier",           "icmpv6.identifier", FT_UINT16,  BASE_DEC, NULL, 0x0,
2190         "Identifier", HFILL }},
2191         { &hf_icmpv6_all_comp,
2192       { "All Components",           "icmpv6.all_comp", FT_UINT16,  BASE_DEC, NULL, 0x0,
2193         "All Components", HFILL }},
2194         { &hf_icmpv6_comp,
2195       { "Component",           "icmpv6.comp", FT_UINT16,  BASE_DEC, NULL, 0x0,
2196         "Component", HFILL }},
2197     { &hf_icmpv6_x509if_Name,
2198       { "Name", "icmpv6.x509_Name", FT_UINT32, BASE_DEC, VALS(x509if_Name_vals), 0,
2199         "Name", HFILL }},
2200     { &hf_icmpv6_x509af_Certificate,
2201       { "Certificate", "icmpv6_x509_Certificate", FT_NONE, BASE_NONE, NULL, 0,
2202         "Certificate", HFILL }},
2203
2204
2205   };
2206
2207   static gint *ett[] = {
2208     &ett_icmpv6,
2209     &ett_icmpv6opt,
2210     &ett_icmpv6flag,
2211     &ett_nodeinfo_flag,
2212     &ett_nodeinfo_subject4,
2213     &ett_nodeinfo_subject6,
2214     &ett_nodeinfo_node4,
2215     &ett_nodeinfo_node6,
2216     &ett_nodeinfo_nodebitmap,
2217     &ett_nodeinfo_nodedns,
2218     &ett_multicastRR,
2219         &ett_icmpv6opt_name,
2220   };
2221
2222   proto_icmpv6 = proto_register_protocol("Internet Control Message Protocol v6",
2223                                          "ICMPv6", "icmpv6");
2224   proto_register_field_array(proto_icmpv6, hf, array_length(hf));
2225   proto_register_subtree_array(ett, array_length(ett));
2226
2227   register_dissector("icmpv6", dissect_icmpv6, proto_icmpv6);
2228 }
2229
2230 void
2231 proto_reg_handoff_icmpv6(void)
2232 {
2233   dissector_handle_t icmpv6_handle;
2234
2235   icmpv6_handle = create_dissector_handle(dissect_icmpv6, proto_icmpv6);
2236   dissector_add("ip.proto", IP_PROTO_ICMPV6, icmpv6_handle);
2237
2238   /*
2239    * Get a handle for the IPv6 dissector.
2240    */
2241   ipv6_handle = find_dissector("ipv6");
2242   data_handle = find_dissector("data");
2243 }