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