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