2 * Routines for ICMPv6 packet disassembly
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"
51 #include <epan/in_cksum.h>
52 #include <epan/addr_resolv.h>
53 #include <epan/ipproto.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;
78 static int hf_icmpv6_haad_ha_addrs = -1;
80 static gint ett_icmpv6 = -1;
81 static gint ett_icmpv6opt = -1;
82 static gint ett_icmpv6flag = -1;
83 static gint ett_nodeinfo_flag = -1;
84 static gint ett_nodeinfo_subject4 = -1;
85 static gint ett_nodeinfo_subject6 = -1;
86 static gint ett_nodeinfo_node4 = -1;
87 static gint ett_nodeinfo_node6 = -1;
88 static gint ett_nodeinfo_nodebitmap = -1;
89 static gint ett_nodeinfo_nodedns = -1;
90 static gint ett_multicastRR = -1;
92 static dissector_handle_t ipv6_handle;
93 static dissector_handle_t data_handle;
95 static const value_string names_nodeinfo_qtype[] = {
96 { NI_QTYPE_NOOP, "NOOP" },
97 { NI_QTYPE_SUPTYPES, "Supported query types" },
98 { NI_QTYPE_DNSNAME, "DNS name" },
99 { NI_QTYPE_NODEADDR, "Node addresses" },
100 { NI_QTYPE_IPV4ADDR, "IPv4 node addresses" },
104 static const value_string names_rrenum_matchcode[] = {
105 { RPM_PCO_ADD, "Add" },
106 { RPM_PCO_CHANGE, "Change" },
107 { RPM_PCO_SETGLOBAL, "Set Global" },
111 static const value_string names_router_pref[] = {
112 { ND_RA_FLAG_RTPREF_HIGH, "High" },
113 { ND_RA_FLAG_RTPREF_MEDIUM, "Medium" },
114 { ND_RA_FLAG_RTPREF_LOW, "Low" },
115 { ND_RA_FLAG_RTPREF_RSV, "Reserved" },
119 dissect_contained_icmpv6(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
121 gboolean save_in_error_pkt;
124 /* Save the current value of the "we're inside an error packet"
125 flag, and set that flag; subdissectors may treat packets
126 that are the payload of error packets differently from
128 save_in_error_pkt = pinfo->in_error_pkt;
129 pinfo->in_error_pkt = TRUE;
131 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
133 /* tiny sanity check */
134 if ((tvb_get_guint8(tvb, offset) & 0xf0) == 0x60) {
135 /* The contained packet is an IPv6 datagram; dissect it. */
136 call_dissector(ipv6_handle, next_tvb, pinfo, tree);
138 call_dissector(data_handle,next_tvb, pinfo, tree);
140 /* Restore the "we're inside an error packet" flag. */
141 pinfo->in_error_pkt = save_in_error_pkt;
145 dissect_icmpv6opt(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
147 proto_tree *icmp6opt_tree, *field_tree;
149 struct nd_opt_hdr nd_opt_hdr, *opt;
152 static const guint8 nd_redirect_reserved[6] = {0, 0, 0, 0, 0, 0};
153 guint8 nd_redirect_res[6];
159 if ((int)tvb_reported_length(tvb) <= offset)
160 return; /* No more options left */
163 tvb_memcpy(tvb, (guint8 *)opt, offset, sizeof *opt);
164 len = opt->nd_opt_len << 3;
166 /* !!! specify length */
167 ti = proto_tree_add_text(tree, tvb, offset, len, "ICMPv6 options");
168 icmp6opt_tree = proto_item_add_subtree(ti, ett_icmpv6opt);
171 proto_tree_add_text(icmp6opt_tree, tvb,
172 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
173 "Invalid option length: %u",
175 return; /* we must not try to decode this */
178 switch (opt->nd_opt_type) {
179 case ND_OPT_SOURCE_LINKADDR:
180 typename = "Source link-layer address";
182 case ND_OPT_TARGET_LINKADDR:
183 typename = "Target link-layer address";
185 case ND_OPT_PREFIX_INFORMATION:
186 typename = "Prefix information";
188 case ND_OPT_REDIRECTED_HEADER:
189 typename = "Redirected header";
194 case ND_OPT_ADVINTERVAL:
195 typename = "Advertisement Interval";
197 case ND_OPT_HOMEAGENT_INFO:
198 typename = "Home Agent Information";
201 typename = "HMIPv6 MAP option";
204 typename = "Unknown";
208 proto_tree_add_text(icmp6opt_tree, tvb,
209 offset + offsetof(struct nd_opt_hdr, nd_opt_type), 1,
210 "Type: %u (%s)", opt->nd_opt_type, typename);
211 proto_tree_add_text(icmp6opt_tree, tvb,
212 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
213 "Length: %u bytes (%u)", opt->nd_opt_len << 3, opt->nd_opt_len);
216 switch (opt->nd_opt_type) {
217 case ND_OPT_SOURCE_LINKADDR:
218 case ND_OPT_TARGET_LINKADDR:
224 p = offset + sizeof(*opt);
225 len = (opt->nd_opt_len << 3) - sizeof(*opt);
226 a = tvb_get_ptr(tvb, p, len);
227 t = g_malloc(len * 3);
228 memset(t, 0, len * 3);
229 for (i = 0; i < len; i++) {
232 sprintf(&t[i * 3], "%02x", a[i]);
234 proto_tree_add_text(icmp6opt_tree, tvb,
235 offset + sizeof(*opt), len, "Link-layer address: %s", t);
239 case ND_OPT_PREFIX_INFORMATION:
241 struct nd_opt_prefix_info nd_opt_prefix_info, *pi;
244 pi = &nd_opt_prefix_info;
245 tvb_memcpy(tvb, (guint8 *)pi, offset, sizeof *pi);
246 proto_tree_add_text(icmp6opt_tree, tvb,
247 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix_len),
248 1, "Prefix length: %u", pi->nd_opt_pi_prefix_len);
250 flagoff = offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved);
251 tf = proto_tree_add_text(icmp6opt_tree, tvb, flagoff, 1, "Flags: 0x%02x",
252 tvb_get_guint8(tvb, offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_flags_reserved)));
253 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
254 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
255 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
256 ND_OPT_PI_FLAG_ONLINK, 8, "Onlink", "Not onlink"));
257 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
258 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
259 ND_OPT_PI_FLAG_AUTO, 8, "Auto", "Not auto"));
260 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
261 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
262 ND_OPT_PI_FLAG_ROUTER, 8,
263 "Router Address", "Not router address"));
264 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
265 decode_boolean_bitfield(pi->nd_opt_pi_flags_reserved,
266 ND_OPT_PI_FLAG_SITEPREF, 8,
267 "Site prefix", "Not site prefix"));
268 proto_tree_add_text(icmp6opt_tree, tvb,
269 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_valid_time),
270 4, "Valid lifetime: 0x%08x",
271 pntohl(&pi->nd_opt_pi_valid_time));
272 proto_tree_add_text(icmp6opt_tree, tvb,
273 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_preferred_time),
274 4, "Preferred lifetime: 0x%08x",
275 pntohl(&pi->nd_opt_pi_preferred_time));
276 proto_tree_add_text(icmp6opt_tree, tvb,
277 offset + offsetof(struct nd_opt_prefix_info, nd_opt_pi_prefix),
278 16, "Prefix: %s", ip6_to_str(&pi->nd_opt_pi_prefix));
281 case ND_OPT_REDIRECTED_HEADER:
282 tvb_memcpy(tvb, (guint8 *)&nd_redirect_res, offset + 2, 6);
283 if (memcmp(nd_redirect_res, nd_redirect_reserved, 6) == 0)
284 proto_tree_add_text(icmp6opt_tree, tvb,
285 offset + 2, 6, "Reserved: 0 (correct)");
287 proto_tree_add_text(icmp6opt_tree, tvb,
288 offset +2, 6, "Reserved: MUST be 0 (incorrect!)");
289 proto_tree_add_text(icmp6opt_tree, tvb,
290 offset + 8, (opt->nd_opt_len << 3) - 8, "Redirected packet");
291 dissect_contained_icmpv6(tvb, offset + 8, pinfo, icmp6opt_tree);
294 proto_tree_add_text(icmp6opt_tree, tvb,
295 offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu), 4,
296 "MTU: %u", tvb_get_ntohl(tvb, offset + offsetof(struct nd_opt_mtu, nd_opt_mtu_mtu)));
298 case ND_OPT_ADVINTERVAL:
299 proto_tree_add_text(icmp6opt_tree, tvb,
300 offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint), 4,
301 "Advertisement Interval: %u",
302 tvb_get_ntohl(tvb, offset + offsetof(struct nd_opt_adv_int, nd_opt_adv_int_advint)));
304 case ND_OPT_HOMEAGENT_INFO:
306 struct nd_opt_ha_info pibuf, *pi;
309 tvb_memcpy(tvb, (guint8 *)pi, offset, sizeof *pi);
310 proto_tree_add_text(icmp6opt_tree, tvb,
311 offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_pref),
312 2, "Home Agent Preference: %d",
313 (gint16)pntohs(&pi->nd_opt_ha_info_ha_pref));
314 proto_tree_add_text(icmp6opt_tree, tvb,
315 offset + offsetof(struct nd_opt_ha_info, nd_opt_ha_info_ha_life),
316 2, "Home Agent Lifetime: %u",
317 pntohs(&pi->nd_opt_ha_info_ha_life));
322 struct nd_opt_map_info mapbuf, *map;
326 tvb_memcpy(tvb, (guint8 *)map, offset, sizeof *map);
327 proto_tree_add_text(icmp6opt_tree, tvb,
328 offset + offsetof(struct nd_opt_map_info, nd_opt_map_dist_and_pref),
329 1, "Distance: %u", (map->nd_opt_map_dist_and_pref >> 4));
330 proto_tree_add_text(icmp6opt_tree, tvb,
331 offset + offsetof(struct nd_opt_map_info, nd_opt_map_dist_and_pref),
332 1, "Preference: %u", (map->nd_opt_map_dist_and_pref & 0x0F));
333 flagoff = offset + offsetof(struct nd_opt_map_info,
335 tf = proto_tree_add_text(icmp6opt_tree, tvb, flagoff, 1,
337 tvb_get_guint8(tvb, offset + offsetof(struct nd_opt_map_info,
339 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
340 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
341 decode_boolean_bitfield(map->nd_opt_map_flags,
342 ND_OPT_MAP_FLAG_R, 8, "R", "No R"));
343 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
344 decode_boolean_bitfield(map->nd_opt_map_flags,
345 ND_OPT_MAP_FLAG_M, 8, "M", "No M"));
346 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
347 decode_boolean_bitfield(map->nd_opt_map_flags,
348 ND_OPT_MAP_FLAG_I, 8, "I", "No I"));
349 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
350 decode_boolean_bitfield(map->nd_opt_map_flags,
351 ND_OPT_MAP_FLAG_T, 8, "T", "No T"));
352 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
353 decode_boolean_bitfield(map->nd_opt_map_flags,
354 ND_OPT_MAP_FLAG_P, 8, "P", "No P"));
355 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
356 decode_boolean_bitfield(map->nd_opt_map_flags,
357 ND_OPT_MAP_FLAG_V, 8, "V", "No V"));
358 proto_tree_add_text(icmp6opt_tree, tvb,
359 offset + offsetof(struct nd_opt_map_info, nd_opt_map_lifetime),
360 4, "Lifetime: %u", pntohl(&map->nd_opt_map_lifetime));
362 proto_tree_add_text(icmp6opt_tree, tvb,
363 offset + offsetof(struct nd_opt_map_info, nd_opt_map_address), 16,
365 "Address of MAP: %s (%s)",
366 get_hostname6(&map->nd_opt_map_address),
368 "Address of MAP: %s",
370 ip6_to_str(&map->nd_opt_map_address));
373 case ND_OPT_ROUTE_INFO:
375 struct nd_opt_route_info ribuf, *ri;
376 struct e_in6_addr in6;
381 tvb_memcpy(tvb, (guint8 *)ri, offset, sizeof *ri);
382 memset(&in6, 0, sizeof(in6));
383 switch (ri->nd_opt_rti_len) {
388 tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*ri), l = 8);
391 tvb_memcpy(tvb, (guint8 *)&in6, offset + sizeof(*ri), l = 16);
398 proto_tree_add_text(icmp6opt_tree, tvb,
399 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_prefixlen),
400 1, "Prefix length: %u", ri->nd_opt_rti_prefixlen);
401 tf = proto_tree_add_text(icmp6opt_tree, tvb,
402 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_flags),
403 1, "Flags: 0x%02x", ri->nd_opt_rti_flags);
404 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
405 proto_tree_add_text(field_tree, tvb,
406 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_flags),
408 decode_enumerated_bitfield(ri->nd_opt_rti_flags,
409 ND_RA_FLAG_RTPREF_MASK, 8, names_router_pref,
410 "Router preference: %s"));
411 lifetime = pntohl(&ri->nd_opt_rti_lifetime);
412 if (lifetime == 0xffffffff)
413 proto_tree_add_text(icmp6opt_tree, tvb,
414 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_lifetime),
415 sizeof(ri->nd_opt_rti_lifetime), "Lifetime: infinity");
417 proto_tree_add_text(icmp6opt_tree, tvb,
418 offset + offsetof(struct nd_opt_route_info, nd_opt_rti_lifetime),
419 sizeof(ri->nd_opt_rti_lifetime), "Lifetime: %u", lifetime);
420 proto_tree_add_text(icmp6opt_tree, tvb,
421 offset + sizeof(*ri), l, "Prefix: %s", ip6_to_str(&in6));
423 proto_tree_add_text(icmp6opt_tree, tvb,
424 offset + offsetof(struct nd_opt_hdr, nd_opt_len), 1,
425 "Invalid option length: %u", opt->nd_opt_len);
431 offset += (opt->nd_opt_len << 3);
436 * draft-ietf-ipngwg-icmp-name-lookups-07.txt
437 * Note that the packet format was changed several times in the past.
441 bitrange0(guint32 v, int s, char *buf, int buflen)
457 ep = buf + buflen - 1;
458 memset(buf, 0, buflen);
461 /* shift till we have 0x01 */
462 if ((v & 0x01) == 0) {
465 v >>= 4; off += 4; continue;
467 v >>= 3; off += 3; continue;
468 case 0x04: case 0x0c:
469 v >>= 2; off += 2; continue;
471 v >>= 1; off += 1; continue;
475 /* we have 0x01 with us */
476 for (i = 0; i < 32 - off; i++) {
477 if ((v & (0x01 << i)) == 0)
481 l = snprintf(p, ep - p, ",%d", s + off);
483 l = snprintf(p, ep - p, ",%d-%d", s + off,
486 if (l == -1 || l > ep - p) {
497 bitrange(tvbuff_t *tvb, int offset, int l, int s)
499 static char buf[1024];
503 memset(buf, 0, sizeof(buf));
505 eq = buf + sizeof(buf) - 1;
506 for (i = 0; i < l; i++) {
507 if (bitrange0(tvb_get_ntohl(tvb, offset + i * 4), s + i * 4, q, eq - q) == NULL) {
508 if (q != buf && q + 5 < buf + sizeof(buf))
509 strncpy(q, ",...", 5);
518 dissect_nodeinfo(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
520 proto_tree *field_tree;
522 struct icmp6_nodeinfo icmp6_nodeinfo, *ni;
527 char dname[MAXDNAME];
530 ni = &icmp6_nodeinfo;
531 tvb_memcpy(tvb, (guint8 *)ni, offset, sizeof *ni);
533 flags = pntohs(&ni->ni_flags);
534 tf = proto_tree_add_text(tree, tvb,
535 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
536 sizeof(ni->ni_flags), "Flags: 0x%04x", flags);
537 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_flag);
538 switch (pntohs(&ni->ni_qtype)) {
539 case NI_QTYPE_SUPTYPES:
540 if (ni->ni_type == ICMP6_NI_QUERY) {
541 proto_tree_add_text(field_tree, tvb,
542 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
543 sizeof(ni->ni_flags), "%s",
544 decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
545 "Compressed reply supported",
546 "No compressed reply support"));
548 proto_tree_add_text(field_tree, tvb,
549 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
550 sizeof(ni->ni_flags), "%s",
551 decode_boolean_bitfield(flags, NI_SUPTYPE_FLAG_COMPRESS, sizeof(flags) * 8,
552 "Compressed", "Not compressed"));
555 case NI_QTYPE_DNSNAME:
556 if (ni->ni_type == ICMP6_NI_REPLY) {
557 proto_tree_add_text(field_tree, tvb,
558 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
559 sizeof(ni->ni_flags), "%s",
560 decode_boolean_bitfield(flags, NI_FQDN_FLAG_VALIDTTL, sizeof(flags) * 8,
561 "Valid TTL field", "Meaningless TTL field"));
564 case NI_QTYPE_NODEADDR:
565 proto_tree_add_text(field_tree, tvb,
566 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
567 sizeof(ni->ni_flags), "%s",
568 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_GLOBAL, sizeof(flags) * 8,
570 "Not global address"));
571 proto_tree_add_text(field_tree, tvb,
572 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
573 sizeof(ni->ni_flags), "%s",
574 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_SITELOCAL, sizeof(flags) * 8,
575 "Site-local address",
576 "Not site-local address"));
577 proto_tree_add_text(field_tree, tvb,
578 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
579 sizeof(ni->ni_flags), "%s",
580 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_LINKLOCAL, sizeof(flags) * 8,
581 "Link-local address",
582 "Not link-local address"));
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_NODEADDR_FLAG_COMPAT, sizeof(flags) * 8,
587 "IPv4 compatible/mapped address",
588 "Not IPv4 compatible/mapped address"));
590 case NI_QTYPE_IPV4ADDR:
591 proto_tree_add_text(field_tree, tvb,
592 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
593 sizeof(ni->ni_flags), "%s",
594 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_ALL, sizeof(flags) * 8,
595 "All unicast address",
596 "Unicast addresses on the queried interface"));
597 proto_tree_add_text(field_tree, tvb,
598 offset + offsetof(struct icmp6_nodeinfo, ni_flags),
599 sizeof(ni->ni_flags), "%s",
600 decode_boolean_bitfield(flags, NI_NODEADDR_FLAG_TRUNCATE, sizeof(flags) * 8,
601 "Truncated", "Not truncated"));
606 proto_tree_add_text(tree, tvb,
607 offset + offsetof(struct icmp6_nodeinfo, icmp6_ni_nonce[0]),
608 sizeof(ni->icmp6_ni_nonce), "Nonce: 0x%08x%08x",
609 pntohl(&ni->icmp6_ni_nonce[0]), pntohl(&ni->icmp6_ni_nonce[4]));
611 /* offset for "the rest of data" */
615 if (!tvb_bytes_exist(tvb, offset, sizeof(*ni)))
617 if (ni->ni_type == ICMP6_NI_QUERY) {
618 switch (ni->ni_code) {
619 case ICMP6_NI_SUBJ_IPV6:
620 n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
621 n /= sizeof(struct e_in6_addr);
622 tf = proto_tree_add_text(tree, tvb,
623 offset + sizeof(*ni), -1, "IPv6 subject addresses");
624 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject6);
625 p = offset + sizeof *ni;
626 for (i = 0; i < n; i++) {
627 struct e_in6_addr e_in6_addr;
628 tvb_memcpy(tvb, (guint8 *)&e_in6_addr, p, sizeof e_in6_addr);
629 proto_tree_add_text(field_tree, tvb,
630 p, sizeof(struct e_in6_addr),
631 "%s", ip6_to_str(&e_in6_addr));
632 p += sizeof(struct e_in6_addr);
634 off = tvb_length_remaining(tvb, offset);
636 case ICMP6_NI_SUBJ_FQDN:
637 l = get_dns_name(tvb, offset + sizeof(*ni),
638 offset + sizeof(*ni), dname, sizeof(dname));
639 if (tvb_bytes_exist(tvb, offset + sizeof(*ni) + l, 1) &&
640 tvb_get_guint8(tvb, offset + sizeof(*ni) + l) == 0) {
642 proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
643 "DNS label: %s (truncated)", dname);
645 proto_tree_add_text(tree, tvb, offset + sizeof(*ni), l,
646 "DNS label: %s", dname);
648 off = tvb_length_remaining(tvb, offset + sizeof(*ni) + l);
650 case ICMP6_NI_SUBJ_IPV4:
651 n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
652 n /= sizeof(guint32);
653 tf = proto_tree_add_text(tree, tvb,
654 offset + sizeof(*ni), -1, "IPv4 subject addresses");
655 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_subject4);
656 p = offset + sizeof *ni;
657 for (i = 0; i < n; i++) {
658 tvb_memcpy(tvb, ipaddr, p, 4);
659 proto_tree_add_text(field_tree, tvb,
660 p, sizeof(guint32), "%s", ip_to_str(ipaddr));
661 p += sizeof(guint32);
663 off = tvb_length_remaining(tvb, offset);
667 switch (pntohs(&ni->ni_qtype)) {
670 case NI_QTYPE_SUPTYPES:
671 p = offset + sizeof *ni;
672 tf = proto_tree_add_text(tree, tvb,
673 offset + sizeof(*ni), -1,
674 "Supported type bitmap%s",
675 (flags & 0x0001) ? ", compressed" : "");
676 field_tree = proto_item_add_subtree(tf,
677 ett_nodeinfo_nodebitmap);
679 while (tvb_bytes_exist(tvb, p, sizeof(guint32))) { /* XXXX Check what? */
680 if ((flags & 0x0001) == 0) {
681 l = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
682 l /= sizeof(guint32);
685 l = tvb_get_ntohs(tvb, p);
686 i = tvb_get_ntohs(tvb, p + sizeof(guint16)); /*skip*/
688 if (n + l * 32 > (1 << 16))
690 if (n + (l + i) * 32 > (1 << 16))
692 if ((flags & 0x0001) == 0) {
693 proto_tree_add_text(field_tree, tvb, p,
694 l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
695 bitrange(tvb, p, l, n));
698 proto_tree_add_text(field_tree, tvb, p,
699 4 + l * 4, "Bitmap (%d to %d): %s", n, n + l * 32 - 1,
700 bitrange(tvb, p + 4, l, n));
703 n += l * 32 + i * 32;
705 off = tvb_length_remaining(tvb, offset);
707 case NI_QTYPE_DNSNAME:
708 proto_tree_add_text(tree, tvb, offset + sizeof(*ni),
709 sizeof(gint32), "TTL: %d", (gint32)tvb_get_ntohl(tvb, offset + sizeof *ni));
710 tf = proto_tree_add_text(tree, tvb,
711 offset + sizeof(*ni) + sizeof(guint32), -1,
713 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_nodedns);
714 j = offset + sizeof (*ni) + sizeof(guint32);
715 while (j < tvb_reported_length(tvb)) {
716 l = get_dns_name(tvb, j,
717 offset + sizeof (*ni) + sizeof(guint32),
718 dname,sizeof(dname));
719 if (tvb_bytes_exist(tvb, j + l, 1) &&
720 tvb_get_guint8(tvb, j + l) == 0) {
722 proto_tree_add_text(field_tree, tvb, j, l,
723 "DNS label: %s (truncated)", dname);
725 proto_tree_add_text(field_tree, tvb, j, l,
726 "DNS label: %s", dname);
730 off = tvb_length_remaining(tvb, offset);
732 case NI_QTYPE_NODEADDR:
733 n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
734 n /= sizeof(gint32) + sizeof(struct e_in6_addr);
735 tf = proto_tree_add_text(tree, tvb,
736 offset + sizeof(*ni), -1, "IPv6 node addresses");
737 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node6);
738 p = offset + sizeof (*ni);
739 for (i = 0; i < n; i++) {
740 struct e_in6_addr e_in6_addr;
742 ttl = (gint32)tvb_get_ntohl(tvb, p);
743 tvb_memcpy(tvb, (guint8 *)&e_in6_addr, p + sizeof ttl, sizeof e_in6_addr);
744 proto_tree_add_text(field_tree, tvb,
745 p, sizeof(struct e_in6_addr) + sizeof(gint32),
746 "%s (TTL %d)", ip6_to_str(&e_in6_addr), ttl);
747 p += sizeof(struct e_in6_addr) + sizeof(gint32);
749 off = tvb_length_remaining(tvb, offset);
751 case NI_QTYPE_IPV4ADDR:
752 n = tvb_reported_length_remaining(tvb, offset + sizeof(*ni));
753 n /= sizeof(gint32) + sizeof(guint32);
754 tf = proto_tree_add_text(tree, tvb,
755 offset + sizeof(*ni), -1, "IPv4 node addresses");
756 field_tree = proto_item_add_subtree(tf, ett_nodeinfo_node4);
757 p = offset + sizeof *ni;
758 for (i = 0; i < n; i++) {
759 tvb_memcpy(tvb, ipaddr, sizeof(gint32) + p, 4);
760 proto_tree_add_text(field_tree, tvb,
761 p, sizeof(guint32), "%s (TTL %d)", ip_to_str(ipaddr), tvb_get_ntohl(tvb, p));
762 p += sizeof(gint32) + sizeof(guint32);
764 off = tvb_length_remaining(tvb, offset);
770 /* the rest of data */
771 call_dissector(data_handle,tvb_new_subset(tvb, offset + off, -1, -1), pinfo, tree);
775 dissect_rrenum(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
777 proto_tree *field_tree, *opt_tree;
779 struct icmp6_router_renum icmp6_router_renum, *rr;
780 struct rr_pco_match rr_pco_match, *match;
781 struct rr_pco_use rr_pco_use, *use;
786 rr = &icmp6_router_renum;
787 tvb_memcpy(tvb, (guint8 *)rr, offset, sizeof *rr);
788 proto_tree_add_text(tree, tvb,
789 offset + offsetof(struct icmp6_router_renum, rr_seqnum), 4,
790 "Sequence number: 0x%08x", pntohl(&rr->rr_seqnum));
791 proto_tree_add_text(tree, tvb,
792 offset + offsetof(struct icmp6_router_renum, rr_segnum), 1,
793 "Segment number: 0x%02x", rr->rr_segnum);
795 flagoff = offset + offsetof(struct icmp6_router_renum, rr_flags);
796 flags = tvb_get_guint8(tvb, flagoff);
797 tf = proto_tree_add_text(tree, tvb, flagoff, 1,
798 "Flags: 0x%02x", flags);
799 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
800 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
801 decode_boolean_bitfield(flags, 0x80, 8,
802 "Test command", "Not test command"));
803 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
804 decode_boolean_bitfield(flags, 0x40, 8,
805 "Result requested", "Result not requested"));
806 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
807 decode_boolean_bitfield(flags, 0x20, 8,
808 "All interfaces", "Not all interfaces"));
809 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
810 decode_boolean_bitfield(flags, 0x10, 8,
811 "Site specific", "Not site specific"));
812 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
813 decode_boolean_bitfield(flags, 0x08, 8,
814 "Processed previously", "Complete result"));
816 proto_tree_add_text(tree, tvb,
817 offset + offsetof(struct icmp6_router_renum, rr_maxdelay), 2,
818 "Max delay: 0x%04x", pntohs(&rr->rr_maxdelay));
819 call_dissector(data_handle,tvb_new_subset(tvb, offset + sizeof(*rr), -1, -1), pinfo, tree); /*XXX*/
821 if (rr->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
822 off = offset + sizeof(*rr);
823 match = &rr_pco_match;
824 tvb_memcpy(tvb, (guint8 *)match, off, sizeof *match);
825 tf = proto_tree_add_text(tree, tvb, off, sizeof(*match),
826 "Match-Prefix: %s/%u (%u-%u)", ip6_to_str(&match->rpm_prefix),
827 match->rpm_matchlen, match->rpm_minlen, match->rpm_maxlen);
828 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
829 proto_tree_add_text(opt_tree, tvb,
830 off + offsetof(struct rr_pco_match, rpm_code),
831 sizeof(match->rpm_code), "OpCode: %s (%u)",
832 val_to_str(match->rpm_code, names_rrenum_matchcode, "Unknown"),
834 proto_tree_add_text(opt_tree, tvb,
835 off + offsetof(struct rr_pco_match, rpm_len),
836 sizeof(match->rpm_len), "OpLength: %u (%u octets)",
837 match->rpm_len, match->rpm_len * 8);
838 proto_tree_add_text(opt_tree, tvb,
839 off + offsetof(struct rr_pco_match, rpm_ordinal),
840 sizeof(match->rpm_ordinal), "Ordinal: %u", match->rpm_ordinal);
841 proto_tree_add_text(opt_tree, tvb,
842 off + offsetof(struct rr_pco_match, rpm_matchlen),
843 sizeof(match->rpm_matchlen), "MatchLen: %u", match->rpm_matchlen);
844 proto_tree_add_text(opt_tree, tvb,
845 off + offsetof(struct rr_pco_match, rpm_minlen),
846 sizeof(match->rpm_minlen), "MinLen: %u", match->rpm_minlen);
847 proto_tree_add_text(opt_tree, tvb,
848 off + offsetof(struct rr_pco_match, rpm_maxlen),
849 sizeof(match->rpm_maxlen), "MaxLen: %u", match->rpm_maxlen);
850 proto_tree_add_text(opt_tree, tvb,
851 off + offsetof(struct rr_pco_match, rpm_prefix),
852 sizeof(match->rpm_prefix), "MatchPrefix: %s",
853 ip6_to_str(&match->rpm_prefix));
855 off += sizeof(*match);
857 for (l = match->rpm_len * 8 - sizeof(*match);
858 l >= sizeof(*use); l -= sizeof(*use), off += sizeof(*use)) {
859 tvb_memcpy(tvb, (guint8 *)use, off, sizeof *use);
860 tf = proto_tree_add_text(tree, tvb, off, sizeof(*use),
861 "Use-Prefix: %s/%u (keep %u)", ip6_to_str(&use->rpu_prefix),
862 use->rpu_uselen, use->rpu_keeplen);
863 opt_tree = proto_item_add_subtree(tf, ett_icmpv6opt);
864 proto_tree_add_text(opt_tree, tvb,
865 off + offsetof(struct rr_pco_use, rpu_uselen),
866 sizeof(use->rpu_uselen), "UseLen: %u", use->rpu_uselen);
867 proto_tree_add_text(opt_tree, tvb,
868 off + offsetof(struct rr_pco_use, rpu_keeplen),
869 sizeof(use->rpu_keeplen), "KeepLen: %u", use->rpu_keeplen);
870 tf = proto_tree_add_text(opt_tree, tvb,
871 flagoff = off + offsetof(struct rr_pco_use, rpu_ramask),
872 sizeof(use->rpu_ramask), "FlagMask: 0x%x", use->rpu_ramask);
873 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
874 flags = tvb_get_guint8(tvb, flagoff);
875 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
876 decode_boolean_bitfield(flags,
877 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
878 "Onlink", "Not onlink"));
879 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
880 decode_boolean_bitfield(flags,
881 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8,
882 "Auto", "Not auto"));
883 tf = proto_tree_add_text(opt_tree, tvb,
884 flagoff = off + offsetof(struct rr_pco_use, rpu_raflags),
885 sizeof(use->rpu_raflags), "RAFlags: 0x%x", use->rpu_raflags);
886 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
887 flags = tvb_get_guint8(tvb, flagoff);
888 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
889 decode_boolean_bitfield(flags,
890 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK, 8,
891 "Onlink", "Not onlink"));
892 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
893 decode_boolean_bitfield(flags,
894 ICMP6_RR_PCOUSE_RAFLAGS_AUTO, 8, "Auto", "Not auto"));
895 if (pntohl(&use->rpu_vltime) == 0xffffffff)
896 proto_tree_add_text(opt_tree, tvb,
897 off + offsetof(struct rr_pco_use, rpu_vltime),
898 sizeof(use->rpu_vltime), "Valid Lifetime: infinity");
900 proto_tree_add_text(opt_tree, tvb,
901 off + offsetof(struct rr_pco_use, rpu_vltime),
902 sizeof(use->rpu_vltime), "Valid Lifetime: %u",
903 pntohl(&use->rpu_vltime));
904 if (pntohl(&use->rpu_pltime) == 0xffffffff)
905 proto_tree_add_text(opt_tree, tvb,
906 off + offsetof(struct rr_pco_use, rpu_pltime),
907 sizeof(use->rpu_pltime), "Preferred Lifetime: infinity");
909 proto_tree_add_text(opt_tree, tvb,
910 off + offsetof(struct rr_pco_use, rpu_pltime),
911 sizeof(use->rpu_pltime), "Preferred Lifetime: %u",
912 pntohl(&use->rpu_pltime));
913 tf = proto_tree_add_text(opt_tree, tvb,
914 flagoff = off + offsetof(struct rr_pco_use, rpu_flags),
915 sizeof(use->rpu_flags), "Flags: 0x%08x",
916 pntohl(&use->rpu_flags));
917 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
918 flags = tvb_get_guint8(tvb, flagoff);
919 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
920 decode_boolean_bitfield(flags,
921 ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, 32,
922 "Decrement valid lifetime", "No decrement valid lifetime"));
923 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
924 decode_boolean_bitfield(flags,
925 ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, 32,
926 "Decrement preferred lifetime",
927 "No decrement preferred lifetime"));
928 proto_tree_add_text(opt_tree, tvb,
929 off + offsetof(struct rr_pco_use, rpu_prefix),
930 sizeof(use->rpu_prefix), "UsePrefix: %s",
931 ip6_to_str(&use->rpu_prefix));
938 * See I-D draft-vida-mld-v2-08
940 static const value_string mldrv2ModesNames[] = {
943 { 3, "Changed to include" },
944 { 4, "Changed to exclude" },
945 { 5, "Allow new sources" },
946 { 6, "Block old sources" },
951 dissect_mldrv2( tvbuff_t *tvb, guint32 offset, guint16 count, proto_tree *tree )
953 proto_tree *sub_tree;
956 guint8 recordType, auxDataLen;
957 guint32 sourceNb, recordSize, localOffset;
958 struct e_in6_addr addr;
960 for( ; count; count--, offset += recordSize ) {
961 localOffset = offset;
962 recordType = tvb_get_guint8( tvb, localOffset );
964 auxDataLen = tvb_get_guint8( tvb, localOffset );
966 sourceNb = tvb_get_ntohs( tvb, localOffset );
968 recordSize = 4 + 16 + (16 * sourceNb) + (auxDataLen * 4);
970 tvb_memcpy(tvb, (guint8 *)&addr, localOffset, sizeof(addr) );
971 tf = proto_tree_add_text( tree, tvb, offset, recordSize,
973 "%s: %s (%s)", val_to_str(recordType, mldrv2ModesNames,"Unknown mode"),
974 get_hostname6(&addr), ip6_to_str(&addr)
976 "%s: %s", val_to_str(recordType, mldrv2ModesNames,"Unknown mode"),
980 sub_tree = proto_item_add_subtree(tf, ett_multicastRR);
982 proto_tree_add_text( sub_tree, tvb, offset, 1, "Mode: %s",
983 val_to_str(recordType, mldrv2ModesNames,"Unknown mode") );
984 proto_tree_add_text( sub_tree, tvb, offset+1, 1, "Aux data len: %u", auxDataLen * 4);
985 proto_tree_add_text( sub_tree, tvb, localOffset, 16, "Multicast Address: %s", ip6_to_str(&addr) );
988 for( ; sourceNb; sourceNb--, localOffset += 16 ) {
989 tvb_memcpy(tvb, (guint8 *)&addr, localOffset, sizeof(addr) );
990 proto_tree_add_text( sub_tree, tvb, localOffset, 16,
992 "Source Address: %s (%s)", get_hostname6(&addr), ip6_to_str(&addr) );
994 "Source Address: %s", ip6_to_str(&addr) );
1001 dissect_mldqv2(tvbuff_t *tvb, guint32 offset, guint16 count, proto_tree *tree)
1003 struct e_in6_addr addr;
1005 for ( ; count; count--, offset += 16) {
1006 tvb_memcpy(tvb, (guint8 *)&addr, offset, sizeof(addr));
1007 proto_tree_add_text(tree, tvb, offset, 16,
1008 "Source Address: %s (%s)", get_hostname6(&addr), ip6_to_str(&addr));
1013 dissect_icmpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1015 proto_tree *icmp6_tree, *field_tree;
1016 proto_item *ti, *tf = NULL;
1017 struct icmp6_hdr icmp6_hdr, *dp;
1018 struct icmp6_nodeinfo *ni = NULL;
1019 char *codename, *typename;
1020 char *colcodename, *coltypename;
1022 guint length, reported_length;
1025 guint16 cksum, computed_cksum;
1029 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1030 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICMPv6");
1031 if (check_col(pinfo->cinfo, COL_INFO))
1032 col_clear(pinfo->cinfo, COL_INFO);
1035 tvb_memcpy(tvb, (guint8 *)&icmp6_hdr, offset, sizeof icmp6_hdr);
1037 codename = typename = colcodename = coltypename = "Unknown";
1039 switch (dp->icmp6_type) {
1040 case ICMP6_DST_UNREACH:
1041 typename = coltypename = "Unreachable";
1042 switch (dp->icmp6_code) {
1043 case ICMP6_DST_UNREACH_NOROUTE:
1044 codename = colcodename = "Route unreachable";
1046 case ICMP6_DST_UNREACH_ADMIN:
1047 codename = colcodename = "Administratively prohibited";
1049 case ICMP6_DST_UNREACH_NOTNEIGHBOR:
1050 codename = colcodename = "Not a neighbor";
1052 case ICMP6_DST_UNREACH_ADDR:
1053 codename = colcodename = "Address unreachable";
1055 case ICMP6_DST_UNREACH_NOPORT:
1056 codename = colcodename = "Port unreachable";
1060 case ICMP6_PACKET_TOO_BIG:
1061 typename = coltypename = "Too big";
1062 codename = colcodename = NULL;
1064 case ICMP6_TIME_EXCEEDED:
1065 typename = coltypename = "Time exceeded";
1066 switch (dp->icmp6_code) {
1067 case ICMP6_TIME_EXCEED_TRANSIT:
1068 codename = colcodename = "In-transit";
1070 case ICMP6_TIME_EXCEED_REASSEMBLY:
1071 codename = colcodename = "Reassembly";
1075 case ICMP6_PARAM_PROB:
1076 typename = coltypename = "Parameter problem";
1077 switch (dp->icmp6_code) {
1078 case ICMP6_PARAMPROB_HEADER:
1079 codename = colcodename = "Header";
1081 case ICMP6_PARAMPROB_NEXTHEADER:
1082 codename = colcodename = "Next header";
1084 case ICMP6_PARAMPROB_OPTION:
1085 codename = colcodename = "Option";
1089 case ICMP6_ECHO_REQUEST:
1090 typename = coltypename = "Echo request";
1091 codename = colcodename = NULL;
1093 case ICMP6_ECHO_REPLY:
1094 typename = coltypename = "Echo reply";
1095 codename = colcodename = NULL;
1097 case ICMP6_MEMBERSHIP_QUERY:
1098 typename = coltypename = "Multicast listener query";
1099 codename = colcodename = NULL;
1101 case ICMP6_MEMBERSHIP_REPORT:
1102 typename = coltypename = "Multicast listener report";
1103 codename = colcodename = NULL;
1105 case ICMP6_MEMBERSHIP_REDUCTION:
1106 typename = coltypename = "Multicast listener done";
1107 codename = colcodename = NULL;
1109 case ND_ROUTER_SOLICIT:
1110 typename = coltypename = "Router solicitation";
1111 codename = colcodename = NULL;
1112 len = sizeof(struct nd_router_solicit);
1114 case ND_ROUTER_ADVERT:
1115 typename = coltypename = "Router advertisement";
1116 codename = colcodename = NULL;
1117 len = sizeof(struct nd_router_advert);
1119 case ND_NEIGHBOR_SOLICIT:
1120 typename = coltypename = "Neighbor solicitation";
1121 codename = colcodename = NULL;
1122 len = sizeof(struct nd_neighbor_solicit);
1124 case ND_NEIGHBOR_ADVERT:
1125 typename = coltypename = "Neighbor advertisement";
1126 codename = colcodename = NULL;
1127 len = sizeof(struct nd_neighbor_advert);
1130 typename = coltypename = "Redirect";
1131 codename = colcodename = NULL;
1132 len = sizeof(struct nd_redirect);
1134 case ICMP6_ROUTER_RENUMBERING:
1135 typename = coltypename = "Router renumbering";
1136 switch (dp->icmp6_code) {
1137 case ICMP6_ROUTER_RENUMBERING_COMMAND:
1138 codename = colcodename = "Command";
1140 case ICMP6_ROUTER_RENUMBERING_RESULT:
1141 codename = colcodename = "Result";
1143 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
1144 codename = colcodename = "Sequence number reset";
1147 len = sizeof(struct icmp6_router_renum);
1149 case ICMP6_NI_QUERY:
1150 case ICMP6_NI_REPLY:
1151 ni = (struct icmp6_nodeinfo *)dp;
1152 if (ni->ni_type == ICMP6_NI_QUERY) {
1153 typename = coltypename = "Node information query";
1154 switch (ni->ni_code) {
1155 case ICMP6_NI_SUBJ_IPV6:
1156 codename = "Query subject = IPv6 addresses";
1158 case ICMP6_NI_SUBJ_FQDN:
1159 if (tvb_bytes_exist(tvb, offset, sizeof(*ni)))
1160 codename = "Query subject = DNS name";
1162 codename = "Query subject = empty";
1164 case ICMP6_NI_SUBJ_IPV4:
1165 codename = "Query subject = IPv4 addresses";
1169 typename = coltypename = "Node information reply";
1170 switch (ni->ni_code) {
1171 case ICMP6_NI_SUCCESS:
1172 codename = "Successful";
1174 case ICMP6_NI_REFUSED:
1175 codename = "Refused";
1177 case ICMP6_NI_UNKNOWN:
1178 codename = "Unknown query type";
1182 colcodename = val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1184 len = sizeof(struct icmp6_nodeinfo);
1186 case ICMP6_MIP6_DHAAD_REQUEST:
1187 typename = coltypename = "Dynamic Home Agent Address Discovery Request";
1188 codename = "Should always be zero";
1191 case ICMP6_MIP6_DHAAD_REPLY:
1192 typename = coltypename = "Dynamic Home Agent Address Discovery Reply";
1193 codename = "Should always be zero";
1196 case ICMP6_MIP6_MPS:
1197 typename = coltypename = "Mobile Prefix Solicitation";
1198 codename = "Should always be zero";
1201 case ICMP6_MIP6_MPA:
1202 typename = coltypename = "Mobile Prefix Advertisement";
1203 codename = "Should always be zero";
1206 case ICMP6_MLDV2_REPORT:
1207 typename = coltypename = "Multicast Listener Report Message v2";
1208 codename = "Should always be zero";
1213 if (check_col(pinfo->cinfo, COL_INFO)) {
1214 char typebuf[256], codebuf[256];
1216 if (coltypename && strcmp(coltypename, "Unknown") == 0) {
1217 snprintf(typebuf, sizeof(typebuf), "Unknown (0x%02x)",
1219 coltypename = typebuf;
1221 if (colcodename && strcmp(colcodename, "Unknown") == 0) {
1222 snprintf(codebuf, sizeof(codebuf), "Unknown (0x%02x)",
1224 colcodename = codebuf;
1227 col_add_fstr(pinfo->cinfo, COL_INFO, "%s (%s)", coltypename, colcodename);
1229 col_add_fstr(pinfo->cinfo, COL_INFO, "%s", coltypename);
1234 /* !!! specify length */
1235 ti = proto_tree_add_item(tree, proto_icmpv6, tvb, offset, -1, FALSE);
1236 icmp6_tree = proto_item_add_subtree(ti, ett_icmpv6);
1238 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_type, tvb,
1239 offset + offsetof(struct icmp6_hdr, icmp6_type), 1,
1241 "Type: %u (%s)", dp->icmp6_type, typename);
1243 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
1244 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
1246 "Code: %u (%s)", dp->icmp6_code, codename);
1248 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_code, tvb,
1249 offset + offsetof(struct icmp6_hdr, icmp6_code), 1,
1251 "Code: %u", dp->icmp6_code);
1253 cksum = (guint16)g_htons(dp->icmp6_cksum);
1254 length = tvb_length(tvb);
1255 reported_length = tvb_reported_length(tvb);
1256 if (!pinfo->fragmented && length >= reported_length) {
1257 /* The packet isn't part of a fragmented datagram and isn't
1258 truncated, so we can checksum it. */
1260 /* Set up the fields of the pseudo-header. */
1261 cksum_vec[0].ptr = pinfo->src.data;
1262 cksum_vec[0].len = pinfo->src.len;
1263 cksum_vec[1].ptr = pinfo->dst.data;
1264 cksum_vec[1].len = pinfo->dst.len;
1265 cksum_vec[2].ptr = (const guint8 *)&phdr;
1266 phdr[0] = g_htonl(tvb_reported_length(tvb));
1267 phdr[1] = g_htonl(IP_PROTO_ICMPV6);
1268 cksum_vec[2].len = 8;
1269 cksum_vec[3].len = tvb_reported_length(tvb);
1270 cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, cksum_vec[3].len);
1271 computed_cksum = in_cksum(cksum_vec, 4);
1272 if (computed_cksum == 0) {
1273 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1275 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1277 "Checksum: 0x%04x (correct)", cksum);
1279 proto_tree_add_boolean_hidden(icmp6_tree, hf_icmpv6_checksum_bad,
1281 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1283 proto_tree_add_uint_format(icmp6_tree, hf_icmpv6_checksum,
1285 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1287 "Checksum: 0x%04x (incorrect, should be 0x%04x)",
1288 cksum, in_cksum_shouldbe(cksum, computed_cksum));
1291 proto_tree_add_uint(icmp6_tree, hf_icmpv6_checksum, tvb,
1292 offset + offsetof(struct icmp6_hdr, icmp6_cksum), 2,
1297 switch (dp->icmp6_type) {
1298 case ICMP6_DST_UNREACH:
1299 case ICMP6_TIME_EXCEEDED:
1300 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1303 case ICMP6_PACKET_TOO_BIG:
1304 proto_tree_add_text(icmp6_tree, tvb,
1305 offset + offsetof(struct icmp6_hdr, icmp6_mtu), 4,
1306 "MTU: %u", pntohl(&dp->icmp6_mtu));
1307 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1310 case ICMP6_PARAM_PROB:
1311 proto_tree_add_text(icmp6_tree, tvb,
1312 offset + offsetof(struct icmp6_hdr, icmp6_pptr), 4,
1313 "Problem pointer: 0x%04x", pntohl(&dp->icmp6_pptr));
1314 dissect_contained_icmpv6(tvb, offset + sizeof(*dp), pinfo,
1317 case ICMP6_ECHO_REQUEST:
1318 case ICMP6_ECHO_REPLY:
1319 proto_tree_add_text(icmp6_tree, tvb,
1320 offset + offsetof(struct icmp6_hdr, icmp6_id), 2,
1321 "ID: 0x%04x", (guint16)g_ntohs(dp->icmp6_id));
1322 proto_tree_add_text(icmp6_tree, tvb,
1323 offset + offsetof(struct icmp6_hdr, icmp6_seq), 2,
1324 "Sequence: 0x%04x", (guint16)g_ntohs(dp->icmp6_seq));
1325 next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1326 call_dissector(data_handle,next_tvb, pinfo, icmp6_tree);
1328 case ICMP6_MEMBERSHIP_QUERY:
1329 case ICMP6_MEMBERSHIP_REPORT:
1330 case ICMP6_MEMBERSHIP_REDUCTION:
1331 #define MLDV2_MINLEN 28
1332 #define MLDV1_MINLEN 24
1333 if (dp->icmp6_type == ICMP6_MEMBERSHIP_QUERY) {
1334 if (length >= MLDV2_MINLEN) {
1340 mrc = g_ntohs(dp->icmp6_maxdelay);
1341 flag = tvb_get_guint8(tvb, offset + sizeof(*dp) + 16);
1342 qqi = tvb_get_guint8(tvb, offset + sizeof(*dp) + 16 + 1);
1343 nsrcs = tvb_get_ntohs(tvb, offset + sizeof(*dp) + 16 + 2);
1346 mrc = ((mrc & 0x0fff) | 0x1000) <<
1347 (((mrc & 0x7000) >> 12) + 3);
1348 proto_tree_add_text(icmp6_tree, tvb,
1349 offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
1350 "Maximum response delay[ms]: %u", mrc);
1352 proto_tree_add_text(icmp6_tree, tvb, offset + sizeof(*dp),
1353 16, "Multicast Address: %s",
1354 ip6_to_str((const struct e_in6_addr *)(tvb_get_ptr(tvb,
1355 offset + sizeof *dp, sizeof (struct e_in6_addr)))));
1357 proto_tree_add_text(icmp6_tree, tvb,
1358 offset + sizeof(*dp) + 16, 1, "S Flag: %s",
1359 flag & 0x08 ? "ON" : "OFF");
1360 proto_tree_add_text(icmp6_tree, tvb,
1361 offset + sizeof(*dp) + 16, 1, "Robustness: %d",
1364 qqi = ((qqi & 0x0f) | 0x10) << (((qqi & 0x70) >> 4) + 3);
1365 proto_tree_add_text(icmp6_tree, tvb,
1366 offset + sizeof(*dp) + 17, 1, "QQI: %d", qqi);
1368 dissect_mldqv2(tvb, offset + sizeof(*dp) + 20, nsrcs,
1371 } else if (length > MLDV1_MINLEN) {
1372 next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1373 call_dissector(data_handle,next_tvb, pinfo, tree);
1376 /* MLDv1 Query -> FALLTHOUGH */
1380 proto_tree_add_text(icmp6_tree, tvb,
1381 offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
1382 "Maximum response delay: %u",
1383 (guint16)g_ntohs(dp->icmp6_maxdelay));
1384 proto_tree_add_text(icmp6_tree, tvb, offset + sizeof(*dp), 16,
1385 "Multicast Address: %s",
1386 ip6_to_str((const struct e_in6_addr *)(tvb_get_ptr(tvb, offset + sizeof *dp, sizeof (struct e_in6_addr)))));
1388 case ND_ROUTER_SOLICIT:
1389 dissect_icmpv6opt(tvb, offset + sizeof(*dp), pinfo, icmp6_tree);
1391 case ICMP6_MLDV2_REPORT: {
1394 nbRecords = tvb_get_ntohs( tvb, offset+4+2 );
1395 dissect_mldrv2( tvb, offset+4+2+2, nbRecords, icmp6_tree );
1398 case ND_ROUTER_ADVERT:
1400 struct nd_router_advert nd_router_advert, *ra;
1404 ra = &nd_router_advert;
1405 tvb_memcpy(tvb, (guint8 *)ra, offset, sizeof *ra);
1406 proto_tree_add_text(icmp6_tree, tvb,
1407 offset + offsetof(struct nd_router_advert, nd_ra_curhoplimit),
1408 1, "Cur hop limit: %u", ra->nd_ra_curhoplimit);
1410 flagoff = offset + offsetof(struct nd_router_advert, nd_ra_flags_reserved);
1411 ra_flags = tvb_get_guint8(tvb, flagoff);
1412 tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 1, "Flags: 0x%02x", ra_flags);
1413 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1414 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1415 decode_boolean_bitfield(ra_flags,
1416 ND_RA_FLAG_MANAGED, 8, "Managed", "Not managed"));
1417 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1418 decode_boolean_bitfield(ra_flags,
1419 ND_RA_FLAG_OTHER, 8, "Other", "Not other"));
1420 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1421 decode_boolean_bitfield(ra_flags,
1422 ND_RA_FLAG_HOME_AGENT, 8,
1423 "Home Agent", "Not Home Agent"));
1424 proto_tree_add_text(field_tree, tvb, flagoff, 1, "%s",
1425 decode_enumerated_bitfield(ra_flags, ND_RA_FLAG_RTPREF_MASK, 8,
1426 names_router_pref, "Router preference: %s"));
1427 proto_tree_add_text(icmp6_tree, tvb,
1428 offset + offsetof(struct nd_router_advert, nd_ra_router_lifetime),
1429 2, "Router lifetime: %u",
1430 (guint16)g_ntohs(ra->nd_ra_router_lifetime));
1431 proto_tree_add_text(icmp6_tree, tvb,
1432 offset + offsetof(struct nd_router_advert, nd_ra_reachable), 4,
1433 "Reachable time: %u", pntohl(&ra->nd_ra_reachable));
1434 proto_tree_add_text(icmp6_tree, tvb,
1435 offset + offsetof(struct nd_router_advert, nd_ra_retransmit), 4,
1436 "Retrans time: %u", pntohl(&ra->nd_ra_retransmit));
1437 dissect_icmpv6opt(tvb, offset + sizeof(struct nd_router_advert), pinfo, icmp6_tree);
1440 case ND_NEIGHBOR_SOLICIT:
1442 struct nd_neighbor_solicit nd_neighbor_solicit, *ns;
1444 ns = &nd_neighbor_solicit;
1445 tvb_memcpy(tvb, (guint8 *)ns, offset, sizeof *ns);
1446 proto_tree_add_text(icmp6_tree, tvb,
1447 offset + offsetof(struct nd_neighbor_solicit, nd_ns_target), 16,
1450 get_hostname6(&ns->nd_ns_target),
1454 ip6_to_str(&ns->nd_ns_target));
1456 dissect_icmpv6opt(tvb, offset + sizeof(*ns), pinfo, icmp6_tree);
1459 case ND_NEIGHBOR_ADVERT:
1461 int flagoff, targetoff;
1463 struct e_in6_addr na_target;
1465 flagoff = offset + offsetof(struct nd_neighbor_advert, nd_na_flags_reserved);
1466 na_flags = tvb_get_ntohl(tvb, flagoff);
1468 tf = proto_tree_add_text(icmp6_tree, tvb, flagoff, 4, "Flags: 0x%08x", na_flags);
1469 field_tree = proto_item_add_subtree(tf, ett_icmpv6flag);
1470 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1471 decode_boolean_bitfield(na_flags,
1472 ND_NA_FLAG_ROUTER, 32, "Router", "Not router"));
1473 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1474 decode_boolean_bitfield(na_flags,
1475 ND_NA_FLAG_SOLICITED, 32, "Solicited", "Not adverted"));
1476 proto_tree_add_text(field_tree, tvb, flagoff, 4, "%s",
1477 decode_boolean_bitfield(na_flags,
1478 ND_NA_FLAG_OVERRIDE, 32, "Override", "Not override"));
1480 targetoff = offset + offsetof(struct nd_neighbor_advert, nd_na_target);
1481 tvb_memcpy(tvb, (guint8 *)&na_target, targetoff, sizeof na_target);
1482 proto_tree_add_text(icmp6_tree, tvb, targetoff, 16,
1485 get_hostname6(&na_target),
1489 ip6_to_str(&na_target));
1491 dissect_icmpv6opt(tvb, offset + sizeof(struct nd_neighbor_advert), pinfo, icmp6_tree);
1496 struct nd_redirect nd_redirect, *rd;
1499 tvb_memcpy(tvb, (guint8 *)rd, offset, sizeof *rd);
1500 proto_tree_add_text(icmp6_tree, tvb,
1501 offset + offsetof(struct nd_redirect, nd_rd_target), 16,
1504 get_hostname6(&rd->nd_rd_target),
1508 ip6_to_str(&rd->nd_rd_target));
1510 proto_tree_add_text(icmp6_tree, tvb,
1511 offset + offsetof(struct nd_redirect, nd_rd_dst), 16,
1513 "Destination: %s (%s)",
1514 get_hostname6(&rd->nd_rd_dst),
1518 ip6_to_str(&rd->nd_rd_dst));
1520 dissect_icmpv6opt(tvb, offset + sizeof(*rd), pinfo, icmp6_tree);
1523 case ICMP6_ROUTER_RENUMBERING:
1524 dissect_rrenum(tvb, offset, pinfo, icmp6_tree);
1526 case ICMP6_NI_QUERY:
1527 case ICMP6_NI_REPLY:
1528 ni = (struct icmp6_nodeinfo *)dp;
1529 proto_tree_add_text(icmp6_tree, tvb,
1530 offset + offsetof(struct icmp6_nodeinfo, ni_qtype),
1531 sizeof(ni->ni_qtype),
1532 "Query type: 0x%04x (%s)", pntohs(&ni->ni_qtype),
1533 val_to_str(pntohs(&ni->ni_qtype), names_nodeinfo_qtype,
1535 dissect_nodeinfo(tvb, offset, pinfo, icmp6_tree);
1537 case ICMP6_MIP6_DHAAD_REQUEST:
1538 proto_tree_add_text(icmp6_tree, tvb,
1539 offset + 4, 2, "Identifier: %d (0x%02x)",
1540 tvb_get_ntohs(tvb, offset + 4),
1541 tvb_get_ntohs(tvb, offset + 4));
1542 proto_tree_add_text(icmp6_tree, tvb,
1543 offset + 6, 2, "Reserved: %d",
1544 tvb_get_ntohs(tvb, offset + 6));
1546 case ICMP6_MIP6_DHAAD_REPLY:
1547 proto_tree_add_text(icmp6_tree, tvb,
1548 offset + 4, 2, "Identifier: %d (0x%02x)",
1549 tvb_get_ntohs(tvb, offset + 4),
1550 tvb_get_ntohs(tvb, offset + 4));
1551 proto_tree_add_text(icmp6_tree, tvb,
1552 offset + 6, 2, "Reserved: %d",
1553 tvb_get_ntohs(tvb, offset + 6));
1554 /* Show all Home Agent Addresses */
1557 int ha_num = (length - 8)/16;
1559 for (i = 0; i < ha_num; i++) {
1561 proto_tree_add_ipv6(icmp6_tree, hf_icmpv6_haad_ha_addrs,
1562 tvb, offset + 8 + suboffset, 16,
1563 tvb_get_ptr(tvb, offset + 8 + suboffset, 16));
1567 case ICMP6_MIP6_MPS:
1568 proto_tree_add_text(icmp6_tree, tvb,
1569 offset + 4, 2, "Identifier: %d (0x%02x)",
1570 tvb_get_ntohs(tvb, offset + 4),
1571 tvb_get_ntohs(tvb, offset + 4));
1572 proto_tree_add_text(icmp6_tree, tvb,
1573 offset + 6, 2, "Reserved: %d",
1574 tvb_get_ntohs(tvb, offset + 6));
1576 case ICMP6_MIP6_MPA:
1577 proto_tree_add_text(icmp6_tree, tvb,
1578 offset + 4, 2, "Identifier: %d (0x%02x)",
1579 tvb_get_ntohs(tvb, offset + 4),
1580 tvb_get_ntohs(tvb, offset + 4));
1581 proto_tree_add_text(icmp6_tree, tvb,
1583 decode_boolean_bitfield(tvb_get_guint8(tvb, offset + 6),
1585 "Managed Address Configuration",
1586 "No Managed Address Configuration"));
1587 proto_tree_add_text(icmp6_tree, tvb,
1589 decode_boolean_bitfield(tvb_get_guint8(tvb, offset + 6),
1591 "Other Stateful Configuration",
1592 "No Other Stateful Configuration"));
1593 proto_tree_add_text(icmp6_tree, tvb,
1594 offset + 7, 1, "Reserved: %d",
1595 tvb_get_guint8(tvb, offset + 7));
1596 /* Show all options */
1597 dissect_icmpv6opt(tvb, offset + 8, pinfo, icmp6_tree);
1600 next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
1601 call_dissector(data_handle,next_tvb, pinfo, tree);
1608 proto_register_icmpv6(void)
1610 static hf_register_info hf[] = {
1612 { "Type", "icmpv6.type", FT_UINT8, BASE_DEC, NULL, 0x0,
1615 { "Code", "icmpv6.code", FT_UINT8, BASE_DEC, NULL, 0x0,
1617 { &hf_icmpv6_checksum,
1618 { "Checksum", "icmpv6.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
1620 { &hf_icmpv6_checksum_bad,
1621 { "Bad Checksum", "icmpv6.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1623 { &hf_icmpv6_haad_ha_addrs,
1624 { "Home Agent Addresses", "icmpv6.haad.ha_addrs",
1625 FT_IPv6, BASE_HEX, NULL, 0x0,
1628 static gint *ett[] = {
1633 &ett_nodeinfo_subject4,
1634 &ett_nodeinfo_subject6,
1635 &ett_nodeinfo_node4,
1636 &ett_nodeinfo_node6,
1637 &ett_nodeinfo_nodebitmap,
1638 &ett_nodeinfo_nodedns,
1642 proto_icmpv6 = proto_register_protocol("Internet Control Message Protocol v6",
1643 "ICMPv6", "icmpv6");
1644 proto_register_field_array(proto_icmpv6, hf, array_length(hf));
1645 proto_register_subtree_array(ett, array_length(ett));
1649 proto_reg_handoff_icmpv6(void)
1651 dissector_handle_t icmpv6_handle;
1653 icmpv6_handle = create_dissector_handle(dissect_icmpv6, proto_icmpv6);
1654 dissector_add("ip.proto", IP_PROTO_ICMPV6, icmpv6_handle);
1655 dissector_add("wtap_encap", WTAP_ENCAP_RAW_ICMPV6, icmpv6_handle);
1658 * Get a handle for the IPv6 dissector.
1660 ipv6_handle = find_dissector("ipv6");
1661 data_handle = find_dissector("data");