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