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