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