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