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