2 * Routines for ICMPv6 packet disassembly
4 * $Id: packet-icmpv6.c,v 1.72 2003/04/28 19:24:48 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * MobileIPv6 support added by Tomislav Borosa <tomislav.borosa@siemens.hr>
12 * HMIPv6 support added by Martti Kuparinen <martti.kuparinen@iki.fi>
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.
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.
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.
44 #ifdef NEED_SNPRINTF_H
45 # include "snprintf.h"
48 #include <epan/packet.h>
49 #include "packet-ipv6.h"
50 #include "packet-dns.h"
52 #include <epan/resolv.h>
56 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
60 * See, under http://www.ietf.org/internet-drafts/
62 * draft-ietf-mobileip-ipv6-15.txt
66 * draft-ietf-ipngwg-icmp-name-lookups-08.txt
70 * draft-ietf-mobileip-hmipv6-05.txt
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;
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;
90 static dissector_handle_t ipv6_handle;
91 static dissector_handle_t data_handle;
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" },
102 static const value_string names_rrenum_matchcode[] = {
103 { RPM_PCO_ADD, "Add" },
104 { RPM_PCO_CHANGE, "Change" },
105 { RPM_PCO_SETGLOBAL, "Set Global" },
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" },
117 dissect_contained_icmpv6(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
119 gboolean save_in_error_pkt;
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
126 save_in_error_pkt = pinfo->in_error_pkt;
127 pinfo->in_error_pkt = TRUE;
129 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
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);
136 call_dissector(data_handle,next_tvb, pinfo, tree);
138 /* Restore the "we're inside an error packet" flag. */
139 pinfo->in_error_pkt = save_in_error_pkt;
143 dissect_icmpv6opt(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
145 proto_tree *icmp6opt_tree, *field_tree;
147 struct nd_opt_hdr nd_opt_hdr, *opt;
150 static const guint8 nd_redirect_reserved[6] = {0, 0, 0, 0, 0, 0};
151 guint8 nd_redirect_res[6];
157 if ((int)tvb_reported_length(tvb) <= offset)
158 return; /* No more options left */
161 tvb_memcpy(tvb, (guint8 *)opt, offset, sizeof *opt);
162 len = opt->nd_opt_len << 3;
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);
169 proto_tree_add_text(icmp6opt_tree, tvb,
170 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
171 "Invalid option length: %u",
173 return; /* we must not try to decode this */
176 switch (opt->nd_opt_type) {
177 case ND_OPT_SOURCE_LINKADDR:
178 typename = "Source link-layer address";
180 case ND_OPT_TARGET_LINKADDR:
181 typename = "Target link-layer address";
183 case ND_OPT_PREFIX_INFORMATION:
184 typename = "Prefix information";
186 case ND_OPT_REDIRECTED_HEADER:
187 typename = "Redirected header";
192 case ND_OPT_ADVINTERVAL:
193 typename = "Advertisement Interval";
195 case ND_OPT_HOMEAGENT_INFO:
196 typename = "Home Agent Information";
199 typename = "HMIPv6 MAP option";
202 typename = "Unknown";
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);
214 switch (opt->nd_opt_type) {
215 case ND_OPT_SOURCE_LINKADDR:
216 case ND_OPT_TARGET_LINKADDR:
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++) {
227 sprintf(&t[i * 3], "%02x", tvb_get_guint8(tvb, p + i) & 0xff);
229 proto_tree_add_text(icmp6opt_tree, tvb,
230 offset + sizeof(*opt), len, "Link-layer address: %s", t);
234 case ND_OPT_PREFIX_INFORMATION:
236 struct nd_opt_prefix_info nd_opt_prefix_info, *pi;
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);
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));
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)");
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);
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)));
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)));
299 case ND_OPT_HOMEAGENT_INFO:
301 struct nd_opt_ha_info pibuf, *pi;
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));
317 struct nd_opt_map_info mapbuf, *map;
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,
330 tf = proto_tree_add_text(icmp6opt_tree, tvb, flagoff, 1,
332 tvb_get_guint8(tvb, offset + offsetof(struct nd_opt_map_info,
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));
357 proto_tree_add_text(icmp6opt_tree, tvb,
358 offset + offsetof(struct nd_opt_map_info, nd_opt_map_address), 16,
360 "Address of MAP: %s (%s)",
361 get_hostname6(&map->nd_opt_map_address),
363 "Address of MAP: %s",
365 ip6_to_str(&map->nd_opt_map_address));
368 case ND_OPT_ROUTE_INFO:
370 struct nd_opt_route_info ribuf, *ri;
371 struct e_in6_addr in6;
376 tvb_memcpy(tvb, (guint8 *)ri, offset, sizeof *ri);
377 memset(&in6, 0, sizeof(in6));
378 switch (ri->nd_opt_rti_len) {
383 tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*ri), l = 8);
386 tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*ri), l = 16);
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),
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");
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));
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);
426 offset += (opt->nd_opt_len << 3);
431 * draft-ietf-ipngwg-icmp-name-lookups-07.txt
432 * Note that the packet format was changed several times in the past.
436 bitrange0(v, s, buf, buflen)
456 ep = buf + buflen - 1;
457 memset(buf, 0, buflen);
460 /* shift till we have 0x01 */
461 if ((v & 0x01) == 0) {
464 v >>= 4; off += 4; continue;
466 v >>= 3; off += 3; continue;
467 case 0x04: case 0x0c:
468 v >>= 2; off += 2; continue;
470 v >>= 1; off += 1; continue;
474 /* we have 0x01 with us */
475 for (i = 0; i < 32 - off; i++) {
476 if ((v & (0x01 << i)) == 0)
480 l = snprintf(p, ep - p, ",%d", s + off);
482 l = snprintf(p, ep - p, ",%d-%d", s + off,
485 if (l == -1 || l > ep - p) {
496 bitrange(tvbuff_t *tvb, int offset, int l, int s)
498 static char buf[1024];
502 memset(buf, 0, sizeof(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);
517 dissect_nodeinfo(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
519 proto_tree *field_tree;
521 struct icmp6_nodeinfo icmp6_nodeinfo, *ni;
526 char dname[MAXDNAME];
529 ni = &icmp6_nodeinfo;
530 tvb_memcpy(tvb, (guint8 *)ni, offset, sizeof *ni);
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"));
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"));
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"));
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,
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"));
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"));
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]));
610 /* offset for "the rest of data" */
614 if (!tvb_bytes_exist(tvb, offset, sizeof(*ni)))
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);
633 off = tvb_length_remaining(tvb, offset);
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) {
641 proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
642 "DNS label: %s (truncated)", dname);
644 proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
645 "DNS label: %s", dname);
647 off = tvb_length_remaining(tvb, offset + sizeof(*ni) + l);
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);
662 off = tvb_length_remaining(tvb, offset);
666 switch (pntohs(&ni->ni_qtype)) {
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);
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);
684 l = tvb_get_ntohs(tvb, p);
685 i = tvb_get_ntohs(tvb, p + sizeof(guint16)); /*skip*/
687 if (n + l * 32 > (1 << 16))
689 if (n + (l + i) * 32 > (1 << 16))
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));
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));
702 n += l * 32 + i * 32;
704 off = tvb_length_remaining(tvb, offset);
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,
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) {
721 proto_tree_add_text(field_tree, tvb, j, l,
722 "DNS label: %s (truncated)", dname);
724 proto_tree_add_text(field_tree, tvb, j, l,
725 "DNS label: %s", dname);
729 off = tvb_length_remaining(tvb, offset);
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;
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);
748 off = tvb_length_remaining(tvb, offset);
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);
763 off = tvb_length_remaining(tvb, offset);
769 /* the rest of data */
770 call_dissector(data_handle,tvb_new_subset(tvb, offset + off, -1, -1), pinfo, tree);
774 dissect_rrenum(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
776 proto_tree *field_tree, *opt_tree;
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;
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);
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"));
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*/
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"),
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));
854 off += sizeof(*match);
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");
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");
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));
937 dissect_icmpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
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;
946 guint length, reported_length;
949 guint16 cksum, computed_cksum;
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);
959 tvb_memcpy(tvb, (guint8 *)&icmp6_hdr, offset, sizeof icmp6_hdr);
961 codename = typename = colcodename = coltypename = "Unknown";
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";
970 case ICMP6_DST_UNREACH_ADMIN:
971 codename = colcodename = "Administratively prohibited";
973 case ICMP6_DST_UNREACH_NOTNEIGHBOR:
974 codename = colcodename = "Not a neighbor";
976 case ICMP6_DST_UNREACH_ADDR:
977 codename = colcodename = "Address unreachable";
979 case ICMP6_DST_UNREACH_NOPORT:
980 codename = colcodename = "Port unreachable";
984 case ICMP6_PACKET_TOO_BIG:
985 typename = coltypename = "Too big";
986 codename = colcodename = NULL;
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";
994 case ICMP6_TIME_EXCEED_REASSEMBLY:
995 codename = colcodename = "Reassembly";
999 case ICMP6_PARAM_PROB:
1000 typename = coltypename = "Parameter problem";
1001 switch (dp->icmp6_code) {
1002 case ICMP6_PARAMPROB_HEADER:
1003 codename = colcodename = "Header";
1005 case ICMP6_PARAMPROB_NEXTHEADER:
1006 codename = colcodename = "Next header";
1008 case ICMP6_PARAMPROB_OPTION:
1009 codename = colcodename = "Option";
1013 case ICMP6_ECHO_REQUEST:
1014 typename = coltypename = "Echo request";
1015 codename = colcodename = NULL;
1017 case ICMP6_ECHO_REPLY:
1018 typename = coltypename = "Echo reply";
1019 codename = colcodename = NULL;
1021 case ICMP6_MEMBERSHIP_QUERY:
1022 typename = coltypename = "Multicast listener query";
1023 codename = colcodename = NULL;
1025 case ICMP6_MEMBERSHIP_REPORT:
1026 typename = coltypename = "Multicast listener report";
1027 codename = colcodename = NULL;
1029 case ICMP6_MEMBERSHIP_REDUCTION:
1030 typename = coltypename = "Multicast listener done";
1031 codename = colcodename = NULL;
1033 case ND_ROUTER_SOLICIT:
1034 typename = coltypename = "Router solicitation";
1035 codename = colcodename = NULL;
1036 len = sizeof(struct nd_router_solicit);
1038 case ND_ROUTER_ADVERT:
1039 typename = coltypename = "Router advertisement";
1040 codename = colcodename = NULL;
1041 len = sizeof(struct nd_router_advert);
1043 case ND_NEIGHBOR_SOLICIT:
1044 typename = coltypename = "Neighbor solicitation";
1045 codename = colcodename = NULL;
1046 len = sizeof(struct nd_neighbor_solicit);
1048 case ND_NEIGHBOR_ADVERT:
1049 typename = coltypename = "Neighbor advertisement";
1050 codename = colcodename = NULL;
1051 len = sizeof(struct nd_neighbor_advert);
1054 typename = coltypename = "Redirect";
1055 codename = colcodename = NULL;
1056 len = sizeof(struct nd_redirect);
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";
1064 case ICMP6_ROUTER_RENUMBERING_RESULT:
1065 codename = colcodename = "Result";
1067 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
1068 codename = colcodename = "Sequence number reset";
1071 len = sizeof(struct icmp6_router_renum);
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";
1082 case ICMP6_NI_SUBJ_FQDN:
1083 if (tvb_bytes_exist(tvb, offset, sizeof(*ni)))
1084 codename = "Query subject = DNS name";
1086 codename = "Query subject = empty";
1088 case ICMP6_NI_SUBJ_IPV4:
1089 codename = "Query subject = IPv4 addresses";
1093 typename = coltypename = "Node information reply";
1094 switch (ni->ni_code) {
1095 case ICMP6_NI_SUCCESS:
1096 codename = "Successful";
1098 case ICMP6_NI_REFUSED:
1099 codename = "Refused";
1101 case ICMP6_NI_UNKNOWN:
1102 codename = "Unknown query type";
1106 colcodename = val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1108 len = sizeof(struct icmp6_nodeinfo);
1110 case ICMP6_MIP6_DHAAD_REQUEST:
1111 typename = coltypename = "Dynamic Home Agent Address Discovery Request";
1112 codename = "Should always be zero";
1115 case ICMP6_MIP6_DHAAD_REPLY:
1116 typename = coltypename = "Dynamic Home Agent Address Discovery Reply";
1117 codename = "Should always be zero";
1120 case ICMP6_MIP6_MPS:
1121 typename = coltypename = "Mobile Prefix Solicitation";
1122 codename = "Should always be zero";
1125 case ICMP6_MIP6_MPA:
1126 typename = coltypename = "Mobile Prefix Advertisement";
1127 codename = "Should always be zero";
1132 if (check_col(pinfo->cinfo, COL_INFO)) {
1133 char typebuf[256], codebuf[256];
1135 if (coltypename && strcmp(coltypename, "Unknown") == 0) {
1136 snprintf(typebuf, sizeof(typebuf), "Unknown (0x%02x)",
1138 coltypename = typebuf;
1140 if (colcodename && strcmp(colcodename, "Unknown") == 0) {
1141 snprintf(codebuf, sizeof(codebuf), "Unknown (0x%02x)",
1143 colcodename = codebuf;
1146 col_add_fstr(pinfo->cinfo, COL_INFO, "%s (%s)", coltypename, colcodename);
1148 col_add_fstr(pinfo->cinfo, COL_INFO, "%s", coltypename);
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);
1157 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_type, tvb,
1158 offset + offsetof(struct icmp6_hdr, icmp6_type), 1,
1160 "Type: %u (%s)", dp->icmp6_type, typename);
1162 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
1163 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
1165 "Code: %u (%s)", dp->icmp6_code, codename);
1167 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
1168 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
1170 "Code: %u", dp->icmp6_code);
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. */
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,
1194 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1196 "Checksum: 0x%04x (correct)", cksum);
1198 proto_tree_add_boolean_hidden(icmp6_tree, hf_icmpv6_checksum_bad,
1200 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1202 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1204 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1206 "Checksum: 0x%04x (incorrect, should be 0x%04x)",
1207 cksum, in_cksum_shouldbe(cksum, computed_cksum));
1210 proto_tree_add_uint(icmp6_tree, hf_icmpv6_checksum, tvb,
1211 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1216 switch (dp->icmp6_type) {
1217 case ICMP6_DST_UNREACH:
1218 case ICMP6_TIME_EXCEEDED:
1219 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
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,
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,
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);
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)))));
1258 case ND_ROUTER_SOLICIT:
1259 dissect_icmpv6opt(tvb, offset + sizeof(*dp), pinfo, icmp6_tree);
1261 case ND_ROUTER_ADVERT:
1263 struct nd_router_advert nd_router_advert, *ra;
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);
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);
1303 case ND_NEIGHBOR_SOLICIT:
1305 struct nd_neighbor_solicit nd_neighbor_solicit, *ns;
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,
1313 get_hostname6(&ns->nd_ns_target),
1317 ip6_to_str(&ns->nd_ns_target));
1319 dissect_icmpv6opt(tvb, offset + sizeof(*ns), pinfo, icmp6_tree);
1322 case ND_NEIGHBOR_ADVERT:
1324 int flagoff, targetoff;
1326 struct e_in6_addr na_target;
1328 flagoff = offset + offsetof(struct nd_neighbor_advert, nd_na_flags_reserved);
1329 na_flags = tvb_get_ntohl(tvb, flagoff);
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"));
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,
1348 get_hostname6(&na_target),
1352 ip6_to_str(&na_target));
1354 dissect_icmpv6opt(tvb, offset + sizeof(struct nd_neighbor_advert), pinfo, icmp6_tree);
1359 struct nd_redirect nd_redirect, *rd;
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,
1367 get_hostname6(&rd->nd_rd_target),
1371 ip6_to_str(&rd->nd_rd_target));
1373 proto_tree_add_text(icmp6_tree, tvb,
1374 offset + offsetof(struct nd_redirect, nd_rd_dst), 16,
1376 "Destination: %s (%s)",
1377 get_hostname6(&rd->nd_rd_dst),
1381 ip6_to_str(&rd->nd_rd_dst));
1383 dissect_icmpv6opt(tvb, offset + sizeof(*rd), pinfo, icmp6_tree);
1386 case ICMP6_ROUTER_RENUMBERING:
1387 dissect_rrenum(tvb, offset, pinfo, icmp6_tree);
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,
1398 dissect_nodeinfo(tvb, offset, pinfo, icmp6_tree);
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));
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 */
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));
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,
1435 decode_boolean_bitfield(tvb_get_guint8(tvb, offset + 6),
1437 "Managed Address Configuration",
1438 "No Managed Address Configuration"));
1439 proto_tree_add_text(icmp6_tree, tvb,
1441 decode_boolean_bitfield(tvb_get_guint8(tvb, offset + 6),
1443 "Other Stateful Configuration",
1444 "No Other Stateful Configuration"));
1445 /* TODO Show all options */
1448 next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1449 call_dissector(data_handle,next_tvb, pinfo, tree);
1456 proto_register_icmpv6(void)
1458 static hf_register_info hf[] = {
1460 { "Type", "icmpv6.type", FT_UINT8, BASE_DEC, NULL, 0x0,
1463 { "Code", "icmpv6.code", FT_UINT8, BASE_DEC, NULL, 0x0,
1465 { &hf_icmpv6_checksum,
1466 { "Checksum", "icmpv6.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1468 { &hf_icmpv6_checksum_bad,
1469 { "Bad Checksum", "icmpv6.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1472 static gint *ett[] = {
1477 &ett_nodeinfo_subject4,
1478 &ett_nodeinfo_subject6,
1479 &ett_nodeinfo_node4,
1480 &ett_nodeinfo_node6,
1481 &ett_nodeinfo_nodebitmap,
1482 &ett_nodeinfo_nodedns,
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));
1492 proto_reg_handoff_icmpv6(void)
1494 dissector_handle_t icmpv6_handle;
1496 icmpv6_handle = create_dissector_handle(dissect_icmpv6, proto_icmpv6);
1497 dissector_add("ip.proto", IP_PROTO_ICMPV6, icmpv6_handle);
1500 * Get a handle for the IPv6 dissector.
1502 ipv6_handle = find_dissector("ipv6");
1503 data_handle = find_dissector("data");