removed some gcc warnings (hopefully)
[obnox/wireshark/wip.git] / epan / dissectors / packet-icmpv6.c
1 /* packet-icmpv6.c
2  * Routines for ICMPv6 packet disassembly
3  *
4  * $Id$
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 <epan/in_cksum.h>
52 #include <epan/addr_resolv.h>
53 #include <epan/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-08
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_mldqv2(tvbuff_t *tvb, guint32 offset, guint16 count, proto_tree *tree)
1002 {
1003   struct e_in6_addr addr;
1004
1005   for ( ; count; count--, offset += 16) {
1006       tvb_memcpy(tvb, (guint8 *)&addr, offset, sizeof(addr));
1007       proto_tree_add_text(tree, tvb, offset, 16, 
1008                           "Source Address: %s (%s)", get_hostname6(&addr), ip6_to_str(&addr));
1009   }
1010 }
1011
1012 static void
1013 dissect_icmpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1014 {
1015     proto_tree *icmp6_tree, *field_tree;
1016     proto_item *ti, *tf = NULL;
1017     struct icmp6_hdr icmp6_hdr, *dp;
1018     struct icmp6_nodeinfo *ni = NULL;
1019     char *codename, *typename;
1020     char *colcodename, *coltypename;
1021     int len;
1022     guint length, reported_length;
1023     vec_t cksum_vec[4];
1024     guint32 phdr[2];
1025     guint16 cksum, computed_cksum;
1026     int offset;
1027     tvbuff_t *next_tvb;
1028
1029     if (check_col(pinfo->cinfo, COL_PROTOCOL))
1030         col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICMPv6");
1031     if (check_col(pinfo->cinfo, COL_INFO))
1032         col_clear(pinfo->cinfo, COL_INFO);
1033
1034     offset = 0;
1035     tvb_memcpy(tvb, (guint8 *)&icmp6_hdr, offset, sizeof icmp6_hdr);
1036     dp = &icmp6_hdr;
1037     codename = typename = colcodename = coltypename = "Unknown";
1038     len = sizeof(*dp);
1039     switch (dp->icmp6_type) {
1040     case ICMP6_DST_UNREACH:
1041         typename = coltypename = "Unreachable";
1042         switch (dp->icmp6_code) {
1043         case ICMP6_DST_UNREACH_NOROUTE:
1044             codename = colcodename = "Route unreachable";
1045             break;
1046         case ICMP6_DST_UNREACH_ADMIN:
1047             codename = colcodename = "Administratively prohibited";
1048             break;
1049         case ICMP6_DST_UNREACH_NOTNEIGHBOR:
1050             codename = colcodename = "Not a neighbor";
1051             break;
1052         case ICMP6_DST_UNREACH_ADDR:
1053             codename = colcodename = "Address unreachable";
1054             break;
1055         case ICMP6_DST_UNREACH_NOPORT:
1056             codename = colcodename = "Port unreachable";
1057             break;
1058         }
1059         break;
1060     case ICMP6_PACKET_TOO_BIG:
1061         typename = coltypename = "Too big";
1062         codename = colcodename = NULL;
1063         break;
1064     case ICMP6_TIME_EXCEEDED:
1065         typename = coltypename = "Time exceeded";
1066         switch (dp->icmp6_code) {
1067         case ICMP6_TIME_EXCEED_TRANSIT:
1068             codename = colcodename = "In-transit";
1069             break;
1070         case ICMP6_TIME_EXCEED_REASSEMBLY:
1071             codename = colcodename = "Reassembly";
1072             break;
1073         }
1074         break;
1075     case ICMP6_PARAM_PROB:
1076         typename = coltypename = "Parameter problem";
1077         switch (dp->icmp6_code) {
1078         case ICMP6_PARAMPROB_HEADER:
1079             codename = colcodename = "Header";
1080             break;
1081         case ICMP6_PARAMPROB_NEXTHEADER:
1082             codename = colcodename = "Next header";
1083             break;
1084         case ICMP6_PARAMPROB_OPTION:
1085             codename = colcodename = "Option";
1086             break;
1087         }
1088         break;
1089     case ICMP6_ECHO_REQUEST:
1090         typename = coltypename = "Echo request";
1091         codename = colcodename = NULL;
1092         break;
1093     case ICMP6_ECHO_REPLY:
1094         typename = coltypename = "Echo reply";
1095         codename = colcodename = NULL;
1096         break;
1097     case ICMP6_MEMBERSHIP_QUERY:
1098         typename = coltypename = "Multicast listener query";
1099         codename = colcodename = NULL;
1100         break;
1101     case ICMP6_MEMBERSHIP_REPORT:
1102         typename = coltypename = "Multicast listener report";
1103         codename = colcodename = NULL;
1104         break;
1105     case ICMP6_MEMBERSHIP_REDUCTION:
1106         typename = coltypename = "Multicast listener done";
1107         codename = colcodename = NULL;
1108         break;
1109     case ND_ROUTER_SOLICIT:
1110         typename = coltypename = "Router solicitation";
1111         codename = colcodename = NULL;
1112         len = sizeof(struct nd_router_solicit);
1113         break;
1114     case ND_ROUTER_ADVERT:
1115         typename = coltypename = "Router advertisement";
1116         codename = colcodename = NULL;
1117         len = sizeof(struct nd_router_advert);
1118         break;
1119     case ND_NEIGHBOR_SOLICIT:
1120         typename = coltypename = "Neighbor solicitation";
1121         codename = colcodename = NULL;
1122         len = sizeof(struct nd_neighbor_solicit);
1123         break;
1124     case ND_NEIGHBOR_ADVERT:
1125         typename = coltypename = "Neighbor advertisement";
1126         codename = colcodename = NULL;
1127         len = sizeof(struct nd_neighbor_advert);
1128         break;
1129     case ND_REDIRECT:
1130         typename = coltypename = "Redirect";
1131         codename = colcodename = NULL;
1132         len = sizeof(struct nd_redirect);
1133         break;
1134     case ICMP6_ROUTER_RENUMBERING:
1135         typename = coltypename = "Router renumbering";
1136         switch (dp->icmp6_code) {
1137         case ICMP6_ROUTER_RENUMBERING_COMMAND:
1138             codename = colcodename = "Command";
1139             break;
1140         case ICMP6_ROUTER_RENUMBERING_RESULT:
1141             codename = colcodename = "Result";
1142             break;
1143         case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
1144             codename = colcodename = "Sequence number reset";
1145             break;
1146         }
1147         len = sizeof(struct icmp6_router_renum);
1148         break;
1149     case ICMP6_NI_QUERY:
1150     case ICMP6_NI_REPLY:
1151         ni = (struct icmp6_nodeinfo *)dp;
1152         if (ni->ni_type == ICMP6_NI_QUERY) {
1153             typename = coltypename = "Node information query";
1154             switch (ni->ni_code) {
1155             case ICMP6_NI_SUBJ_IPV6:
1156                 codename = "Query subject = IPv6 addresses";
1157                 break;
1158             case ICMP6_NI_SUBJ_FQDN:
1159                 if (tvb_bytes_exist(tvb, offset, sizeof(*ni)))
1160                     codename = "Query subject = DNS name";
1161                 else
1162                     codename = "Query subject = empty";
1163                 break;
1164             case ICMP6_NI_SUBJ_IPV4:
1165                 codename = "Query subject = IPv4 addresses";
1166                 break;
1167             }
1168         } else {
1169             typename = coltypename = "Node information reply";
1170             switch (ni->ni_code) {
1171             case ICMP6_NI_SUCCESS:
1172                 codename = "Successful";
1173                 break;
1174             case ICMP6_NI_REFUSED:
1175                 codename = "Refused";
1176                 break;
1177             case ICMP6_NI_UNKNOWN:
1178                 codename = "Unknown query type";
1179                 break;
1180             }
1181         }
1182         colcodename = val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1183             "Unknown");
1184         len = sizeof(struct icmp6_nodeinfo);
1185         break;
1186     case ICMP6_MIP6_DHAAD_REQUEST:
1187         typename = coltypename = "Dynamic Home Agent Address Discovery Request";
1188         codename = "Should always be zero";
1189         colcodename = NULL;
1190         break;
1191     case ICMP6_MIP6_DHAAD_REPLY:
1192         typename = coltypename = "Dynamic Home Agent Address Discovery Reply";
1193         codename = "Should always be zero";
1194         colcodename = NULL;
1195         break;
1196     case ICMP6_MIP6_MPS:
1197         typename = coltypename = "Mobile Prefix Solicitation";
1198         codename = "Should always be zero";
1199         colcodename = NULL;
1200         break;
1201     case ICMP6_MIP6_MPA:
1202         typename = coltypename = "Mobile Prefix Advertisement";
1203         codename = "Should always be zero";
1204         colcodename = NULL;
1205         break;
1206     case ICMP6_MLDV2_REPORT:
1207         typename = coltypename = "Multicast Listener Report Message v2";
1208         codename = "Should always be zero";
1209         colcodename = NULL;
1210         break;
1211     }
1212
1213     if (check_col(pinfo->cinfo, COL_INFO)) {
1214         char typebuf[256], codebuf[256];
1215
1216         if (coltypename && strcmp(coltypename, "Unknown") == 0) {
1217             snprintf(typebuf, sizeof(typebuf), "Unknown (0x%02x)",
1218                 dp->icmp6_type);
1219             coltypename = typebuf;
1220         }
1221         if (colcodename && strcmp(colcodename, "Unknown") == 0) {
1222             snprintf(codebuf, sizeof(codebuf), "Unknown (0x%02x)",
1223                 dp->icmp6_code);
1224             colcodename = codebuf;
1225         }
1226         if (colcodename) {
1227             col_add_fstr(pinfo->cinfo, COL_INFO, "%s (%s)", coltypename, colcodename);
1228         } else {
1229             col_add_fstr(pinfo->cinfo, COL_INFO, "%s", coltypename);
1230         }
1231     }
1232
1233     if (tree) {
1234         /* !!! specify length */
1235         ti = proto_tree_add_item(tree, proto_icmpv6, tvb, offset, -1, FALSE);
1236         icmp6_tree = proto_item_add_subtree(ti, ett_icmpv6);
1237
1238         proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_type, tvb,
1239             offset + offsetof(struct icmp6_hdr, icmp6_type), 1,
1240             dp->icmp6_type,
1241             "Type: %u (%s)", dp->icmp6_type, typename);
1242         if (codename) {
1243             proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
1244                 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
1245                 dp->icmp6_code,
1246                 "Code: %u (%s)", dp->icmp6_code, codename);
1247         } else {
1248             proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
1249                 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
1250                 dp->icmp6_code,
1251                 "Code: %u", dp->icmp6_code);
1252         }
1253         cksum = (guint16)g_htons(dp->icmp6_cksum);
1254         length = tvb_length(tvb);
1255         reported_length = tvb_reported_length(tvb);
1256         if (!pinfo->fragmented && length >= reported_length) {
1257             /* The packet isn't part of a fragmented datagram and isn't
1258                truncated, so we can checksum it. */
1259
1260             /* Set up the fields of the pseudo-header. */
1261             cksum_vec[0].ptr = pinfo->src.data;
1262             cksum_vec[0].len = pinfo->src.len;
1263             cksum_vec[1].ptr = pinfo->dst.data;
1264             cksum_vec[1].len = pinfo->dst.len;
1265             cksum_vec[2].ptr = (const guint8 *)&phdr;
1266             phdr[0] = g_htonl(tvb_reported_length(tvb));
1267             phdr[1] = g_htonl(IP_PROTO_ICMPV6);
1268             cksum_vec[2].len = 8;
1269             cksum_vec[3].len = tvb_reported_length(tvb);
1270             cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, cksum_vec[3].len);
1271             computed_cksum = in_cksum(cksum_vec, 4);
1272             if (computed_cksum == 0) {
1273                 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1274                         tvb,
1275                         offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1276                         cksum,
1277                         "Checksum: 0x%04x (correct)", cksum);
1278             } else {
1279                 proto_tree_add_boolean_hidden(icmp6_tree, hf_icmpv6_checksum_bad,
1280                         tvb,
1281                         offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1282                         TRUE);
1283                 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1284                         tvb,
1285                         offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1286                         cksum,
1287                         "Checksum: 0x%04x (incorrect, should be 0x%04x)",
1288                         cksum, in_cksum_shouldbe(cksum, computed_cksum));
1289             }
1290         } else {
1291             proto_tree_add_uint(icmp6_tree, hf_icmpv6_checksum, tvb,
1292                 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1293                 cksum);
1294         }
1295
1296         /* decode... */
1297         switch (dp->icmp6_type) {
1298         case ICMP6_DST_UNREACH:
1299         case ICMP6_TIME_EXCEEDED:
1300             dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1301                 icmp6_tree);
1302             break;
1303         case ICMP6_PACKET_TOO_BIG:
1304             proto_tree_add_text(icmp6_tree, tvb,
1305                 offset + offsetof(struct icmp6_hdr, icmp6_mtu), 4,
1306                 "MTU: %u", pntohl(&dp->icmp6_mtu));
1307             dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1308                 icmp6_tree);
1309             break;
1310         case ICMP6_PARAM_PROB:
1311             proto_tree_add_text(icmp6_tree, tvb,
1312                 offset + offsetof(struct icmp6_hdr, icmp6_pptr), 4,
1313                 "Problem pointer: 0x%04x", pntohl(&dp->icmp6_pptr));
1314             dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1315                 icmp6_tree);
1316             break;
1317         case ICMP6_ECHO_REQUEST:
1318         case ICMP6_ECHO_REPLY:
1319             proto_tree_add_text(icmp6_tree, tvb,
1320                 offset + offsetof(struct icmp6_hdr, icmp6_id), 2,
1321                 "ID: 0x%04x", (guint16)g_ntohs(dp->icmp6_id));
1322             proto_tree_add_text(icmp6_tree, tvb,
1323                 offset + offsetof(struct icmp6_hdr, icmp6_seq), 2,
1324                 "Sequence: 0x%04x", (guint16)g_ntohs(dp->icmp6_seq));
1325             next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1326             call_dissector(data_handle,next_tvb, pinfo, icmp6_tree);
1327             break;
1328         case ICMP6_MEMBERSHIP_QUERY:
1329         case ICMP6_MEMBERSHIP_REPORT:
1330         case ICMP6_MEMBERSHIP_REDUCTION:
1331 #define MLDV2_MINLEN 28
1332 #define MLDV1_MINLEN 24
1333             if (dp->icmp6_type == ICMP6_MEMBERSHIP_QUERY) {
1334                 if (length >= MLDV2_MINLEN) {
1335                     guint32 mrc;
1336                     guint16 qqi;
1337                     guint8 flag;
1338                     guint16 nsrcs;
1339                     
1340                     mrc = g_ntohs(dp->icmp6_maxdelay);
1341                     flag = tvb_get_guint8(tvb, offset + sizeof(*dp) + 16);
1342                     qqi = tvb_get_guint8(tvb, offset + sizeof(*dp) + 16 + 1);
1343                     nsrcs = tvb_get_ntohs(tvb, offset + sizeof(*dp) + 16 + 2);
1344
1345                     if (mrc >= 32768)
1346                         mrc = ((mrc & 0x0fff) | 0x1000) << 
1347                                 (((mrc & 0x7000) >> 12) + 3);
1348                     proto_tree_add_text(icmp6_tree, tvb,
1349                         offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
1350                         "Maximum response delay[ms]: %u", mrc);
1351
1352                     proto_tree_add_text(icmp6_tree, tvb, offset + sizeof(*dp),
1353                         16, "Multicast Address: %s",
1354                         ip6_to_str((const struct e_in6_addr *)(tvb_get_ptr(tvb,
1355                             offset + sizeof *dp, sizeof (struct e_in6_addr)))));
1356
1357                     proto_tree_add_text(icmp6_tree, tvb,
1358                         offset + sizeof(*dp) + 16, 1, "S Flag: %s",
1359                         flag & 0x08 ? "ON" : "OFF");
1360                     proto_tree_add_text(icmp6_tree, tvb,
1361                         offset + sizeof(*dp) + 16, 1, "Robustness: %d",
1362                         flag & 0x07);
1363                     if (qqi >= 128)
1364                         qqi = ((qqi & 0x0f) | 0x10) << (((qqi & 0x70) >> 4) + 3);
1365                     proto_tree_add_text(icmp6_tree, tvb,
1366                         offset + sizeof(*dp) + 17, 1, "QQI: %d", qqi);
1367
1368                     dissect_mldqv2(tvb, offset + sizeof(*dp) + 20, nsrcs,
1369                         icmp6_tree);
1370                     break;
1371                 } else if (length > MLDV1_MINLEN) {
1372                     next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1373                     call_dissector(data_handle,next_tvb, pinfo, tree);
1374                     break;
1375                 }
1376                 /* MLDv1 Query -> FALLTHOUGH */
1377             }
1378 #undef MLDV2_MINLEN
1379 #undef MLDV1_MINLEN
1380             proto_tree_add_text(icmp6_tree, tvb,
1381                 offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
1382                 "Maximum response delay: %u",
1383                 (guint16)g_ntohs(dp->icmp6_maxdelay));
1384             proto_tree_add_text(icmp6_tree, tvb, offset + sizeof(*dp), 16,
1385                 "Multicast Address: %s",
1386                 ip6_to_str((const struct e_in6_addr *)(tvb_get_ptr(tvb, offset + sizeof *dp, sizeof (struct e_in6_addr)))));
1387             break;
1388         case ND_ROUTER_SOLICIT:
1389             dissect_icmpv6opt(tvb, offset + sizeof(*dp), pinfo, icmp6_tree);
1390             break;
1391         case ICMP6_MLDV2_REPORT: {
1392           guint16 nbRecords;
1393           
1394           nbRecords = tvb_get_ntohs( tvb, offset+4+2 );
1395           dissect_mldrv2( tvb, offset+4+2+2, nbRecords, icmp6_tree );
1396           break;
1397         }
1398         case ND_ROUTER_ADVERT:
1399           {
1400             struct nd_router_advert nd_router_advert, *ra;
1401             int flagoff;
1402             guint32 ra_flags;
1403
1404             ra = &nd_router_advert;
1405             tvb_memcpy(tvb, (guint8 *)ra, offset, sizeof *ra);
1406             proto_tree_add_text(icmp6_tree, tvb,
1407                 offset + offsetof(struct nd_router_advert, nd_ra_curhoplimit),
1408                 1, "Cur hop limit: %u", ra->nd_ra_curhoplimit);
1409
1410             flagoff = offset + offsetof(struct nd_router_advert, nd_ra_flags_reserved);
1411             ra_flags = tvb_get_guint8(tvb, flagoff);
1412             tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 1, "Flags: 0x%02x", ra_flags);
1413             field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1414             proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1415                 decode_boolean_bitfield(ra_flags,
1416                         ND_RA_FLAG_MANAGED, 8, "Managed", "Not managed"));
1417             proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1418                 decode_boolean_bitfield(ra_flags,
1419                         ND_RA_FLAG_OTHER, 8, "Other", "Not other"));
1420             proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1421                 decode_boolean_bitfield(ra_flags,
1422                         ND_RA_FLAG_HOME_AGENT, 8,
1423                         "Home Agent", "Not Home Agent"));
1424             proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1425                 decode_enumerated_bitfield(ra_flags, ND_RA_FLAG_RTPREF_MASK, 8,
1426                 names_router_pref, "Router preference: %s"));
1427             proto_tree_add_text(icmp6_tree, tvb,
1428                 offset + offsetof(struct nd_router_advert, nd_ra_router_lifetime),
1429                 2, "Router lifetime: %u",
1430                 (guint16)g_ntohs(ra->nd_ra_router_lifetime));
1431             proto_tree_add_text(icmp6_tree, tvb,
1432                 offset + offsetof(struct nd_router_advert, nd_ra_reachable), 4,
1433                 "Reachable time: %u", pntohl(&ra->nd_ra_reachable));
1434             proto_tree_add_text(icmp6_tree, tvb,
1435                 offset + offsetof(struct nd_router_advert, nd_ra_retransmit), 4,
1436                 "Retrans time: %u", pntohl(&ra->nd_ra_retransmit));
1437             dissect_icmpv6opt(tvb, offset + sizeof(struct nd_router_advert), pinfo, icmp6_tree);
1438             break;
1439           }
1440         case ND_NEIGHBOR_SOLICIT:
1441           {
1442             struct nd_neighbor_solicit nd_neighbor_solicit, *ns;
1443
1444             ns = &nd_neighbor_solicit;
1445             tvb_memcpy(tvb, (guint8 *)ns, offset, sizeof *ns);
1446             proto_tree_add_text(icmp6_tree, tvb,
1447                         offset + offsetof(struct nd_neighbor_solicit, nd_ns_target), 16,
1448 #ifdef INET6
1449                         "Target: %s (%s)",
1450                         get_hostname6(&ns->nd_ns_target),
1451 #else
1452                         "Target: %s",
1453 #endif
1454                         ip6_to_str(&ns->nd_ns_target));
1455
1456             dissect_icmpv6opt(tvb, offset + sizeof(*ns), pinfo, icmp6_tree);
1457             break;
1458           }
1459         case ND_NEIGHBOR_ADVERT:
1460           {
1461             int flagoff, targetoff;
1462             guint32 na_flags;
1463             struct e_in6_addr na_target;
1464
1465             flagoff = offset + offsetof(struct nd_neighbor_advert, nd_na_flags_reserved);
1466             na_flags = tvb_get_ntohl(tvb, flagoff);
1467
1468             tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 4, "Flags: 0x%08x", na_flags);
1469             field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1470             proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1471                 decode_boolean_bitfield(na_flags,
1472                         ND_NA_FLAG_ROUTER, 32, "Router", "Not router"));
1473             proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1474                 decode_boolean_bitfield(na_flags,
1475                         ND_NA_FLAG_SOLICITED, 32, "Solicited", "Not adverted"));
1476             proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1477                 decode_boolean_bitfield(na_flags,
1478                         ND_NA_FLAG_OVERRIDE, 32, "Override", "Not override"));
1479
1480             targetoff = offset + offsetof(struct nd_neighbor_advert, nd_na_target);
1481             tvb_memcpy(tvb, (guint8 *)&na_target, targetoff, sizeof na_target);
1482             proto_tree_add_text(icmp6_tree, tvb, targetoff, 16,
1483 #ifdef INET6
1484                         "Target: %s (%s)",
1485                         get_hostname6(&na_target),
1486 #else
1487                         "Target: %s",
1488 #endif
1489                         ip6_to_str(&na_target));
1490
1491             dissect_icmpv6opt(tvb, offset + sizeof(struct nd_neighbor_advert), pinfo, icmp6_tree);
1492             break;
1493           }
1494         case ND_REDIRECT:
1495           {
1496             struct nd_redirect nd_redirect, *rd;
1497
1498             rd = &nd_redirect;
1499             tvb_memcpy(tvb, (guint8 *)rd, offset, sizeof *rd);
1500             proto_tree_add_text(icmp6_tree, tvb,
1501                         offset + offsetof(struct nd_redirect, nd_rd_target), 16,
1502 #ifdef INET6
1503                         "Target: %s (%s)",
1504                         get_hostname6(&rd->nd_rd_target),
1505 #else
1506                         "Target: %s",
1507 #endif
1508                         ip6_to_str(&rd->nd_rd_target));
1509
1510             proto_tree_add_text(icmp6_tree, tvb,
1511                         offset + offsetof(struct nd_redirect, nd_rd_dst), 16,
1512 #ifdef INET6
1513                         "Destination: %s (%s)",
1514                         get_hostname6(&rd->nd_rd_dst),
1515 #else
1516                         "Destination: %s",
1517 #endif
1518                         ip6_to_str(&rd->nd_rd_dst));
1519
1520             dissect_icmpv6opt(tvb, offset + sizeof(*rd), pinfo, icmp6_tree);
1521             break;
1522           }
1523         case ICMP6_ROUTER_RENUMBERING:
1524             dissect_rrenum(tvb, offset, pinfo, icmp6_tree);
1525             break;
1526         case ICMP6_NI_QUERY:
1527         case ICMP6_NI_REPLY:
1528             ni = (struct icmp6_nodeinfo *)dp;
1529             proto_tree_add_text(icmp6_tree, tvb,
1530                 offset + offsetof(struct icmp6_nodeinfo, ni_qtype),
1531                 sizeof(ni->ni_qtype),
1532                 "Query type: 0x%04x (%s)", pntohs(&ni->ni_qtype),
1533                 val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1534                 "Unknown"));
1535             dissect_nodeinfo(tvb, offset, pinfo, icmp6_tree);
1536             break;
1537         case ICMP6_MIP6_DHAAD_REQUEST:
1538             proto_tree_add_text(icmp6_tree, tvb,
1539                 offset + 4, 2, "Identifier: %d (0x%02x)",
1540                 tvb_get_ntohs(tvb, offset + 4),
1541                 tvb_get_ntohs(tvb, offset + 4));
1542             proto_tree_add_text(icmp6_tree, tvb,
1543                 offset + 6, 2, "Reserved: %d",
1544                 tvb_get_ntohs(tvb, offset + 6));
1545             break;
1546         case ICMP6_MIP6_DHAAD_REPLY:
1547             proto_tree_add_text(icmp6_tree, tvb,
1548                 offset + 4, 2, "Identifier: %d (0x%02x)",
1549                 tvb_get_ntohs(tvb, offset + 4),
1550                 tvb_get_ntohs(tvb, offset + 4));
1551             proto_tree_add_text(icmp6_tree, tvb,
1552                 offset + 6, 2, "Reserved: %d",
1553                 tvb_get_ntohs(tvb, offset + 6));
1554             /* Show all Home Agent Addresses */
1555             {
1556                 int i, suboffset;
1557                 int ha_num = (length - 8)/16;
1558
1559                 for (i = 0; i < ha_num; i++) {
1560                     suboffset = 16 * i;
1561                     proto_tree_add_ipv6(icmp6_tree, hf_icmpv6_haad_ha_addrs,
1562                         tvb, offset + 8 + suboffset, 16,
1563                         tvb_get_ptr(tvb, offset + 8 + suboffset, 16));
1564                 }
1565             }
1566             break;
1567         case ICMP6_MIP6_MPS:
1568             proto_tree_add_text(icmp6_tree, tvb,
1569                 offset + 4, 2, "Identifier: %d (0x%02x)",
1570                 tvb_get_ntohs(tvb, offset + 4),
1571                 tvb_get_ntohs(tvb, offset + 4));
1572             proto_tree_add_text(icmp6_tree, tvb,
1573                 offset + 6, 2, "Reserved: %d",
1574                 tvb_get_ntohs(tvb, offset + 6));
1575             break;
1576         case ICMP6_MIP6_MPA:
1577             proto_tree_add_text(icmp6_tree, tvb,
1578                 offset + 4, 2, "Identifier: %d (0x%02x)",
1579                 tvb_get_ntohs(tvb, offset + 4),
1580                 tvb_get_ntohs(tvb, offset + 4));
1581             proto_tree_add_text(icmp6_tree, tvb,
1582                 offset + 6, 1,
1583                 decode_boolean_bitfield(tvb_get_guint8(tvb, offset + 6),
1584                     0x80, 8,
1585                     "Managed Address Configuration",
1586                     "No Managed Address Configuration"));
1587             proto_tree_add_text(icmp6_tree, tvb,
1588                 offset + 6, 1,
1589                 decode_boolean_bitfield(tvb_get_guint8(tvb, offset + 6),
1590                     0x40, 8,
1591                     "Other Stateful Configuration",
1592                     "No Other Stateful Configuration"));
1593             proto_tree_add_text(icmp6_tree, tvb,
1594                 offset + 7, 1, "Reserved: %d",
1595                 tvb_get_guint8(tvb, offset + 7));
1596             /* Show all options */
1597             dissect_icmpv6opt(tvb, offset + 8, pinfo, icmp6_tree);
1598             break;
1599         default:
1600             next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1601             call_dissector(data_handle,next_tvb, pinfo, tree);
1602             break;
1603         }
1604     }
1605 }
1606
1607 void
1608 proto_register_icmpv6(void)
1609 {
1610   static hf_register_info hf[] = {
1611     { &hf_icmpv6_type,
1612       { "Type",           "icmpv6.type",        FT_UINT8,  BASE_DEC, NULL, 0x0,
1613         "", HFILL }},
1614     { &hf_icmpv6_code,
1615       { "Code",           "icmpv6.code",        FT_UINT8,  BASE_DEC, NULL, 0x0,
1616         "", HFILL }},
1617     { &hf_icmpv6_checksum,
1618       { "Checksum",       "icmpv6.checksum",    FT_UINT16, BASE_HEX, NULL, 0x0,
1619         "", HFILL }},
1620     { &hf_icmpv6_checksum_bad,
1621       { "Bad Checksum",   "icmpv6.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1622         "", HFILL }},
1623     { &hf_icmpv6_haad_ha_addrs,
1624       { "Home Agent Addresses", "icmpv6.haad.ha_addrs",
1625        FT_IPv6, BASE_HEX, NULL, 0x0,
1626        "", HFILL }},
1627   };
1628   static gint *ett[] = {
1629     &ett_icmpv6,
1630     &ett_icmpv6opt,
1631     &ett_icmpv6flag,
1632     &ett_nodeinfo_flag,
1633     &ett_nodeinfo_subject4,
1634     &ett_nodeinfo_subject6,
1635     &ett_nodeinfo_node4,
1636     &ett_nodeinfo_node6,
1637     &ett_nodeinfo_nodebitmap,
1638     &ett_nodeinfo_nodedns,
1639     &ett_multicastRR,
1640   };
1641
1642   proto_icmpv6 = proto_register_protocol("Internet Control Message Protocol v6",
1643                                          "ICMPv6", "icmpv6");
1644   proto_register_field_array(proto_icmpv6, hf, array_length(hf));
1645   proto_register_subtree_array(ett, array_length(ett));
1646 }
1647
1648 void
1649 proto_reg_handoff_icmpv6(void)
1650 {
1651   dissector_handle_t icmpv6_handle;
1652
1653   icmpv6_handle = create_dissector_handle(dissect_icmpv6, proto_icmpv6);
1654   dissector_add("ip.proto", IP_PROTO_ICMPV6, icmpv6_handle);
1655   dissector_add("wtap_encap", WTAP_ENCAP_RAW_ICMPV6, icmpv6_handle);
1656
1657   /*
1658    * Get a handle for the IPv6 dissector.
1659    */
1660   ipv6_handle = find_dissector("ipv6");
1661   data_handle = find_dissector("data");
1662 }