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