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