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