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