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