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