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