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