2 * Routines for AODV6 dissection
3 * Copyright 2002, Antti J. Tuominen <ajtuomin@tml.hut.fi>
4 * Loosely based on packet-aodv.c.
6 * $Id: packet-aodv6.c,v 1.5 2002/08/28 21:00:07 jmayer Exp $
8 * Ethereal - Network traffic analyzer
9 * By Gerald Combs <gerald@ethereal.com>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33 #include <epan/int-64bit.h>
34 #include <epan/packet.h>
35 #include <epan/ipv6-utils.h>
38 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
41 #define INET6_ADDRLEN 16
42 #define UDP_PORT_AODV6 654
48 #define AODV6_RREP_ACK 19
52 #define AODV6_EXT_INT 2
53 #define AODV6_EXT_NTP 3
56 #define RREQ_GRAT 0x20
58 #define RREQ_JOIN 0x80
63 #define RERR_NODEL 0x80
65 static const value_string type_vals[] = {
66 {AODV6_RREQ, "Route Request"},
67 {AODV6_RREP, "Route Reply"},
68 {AODV6_RERR, "Route Error"},
69 {AODV6_RREP_ACK, "Route Reply Acknowledgment"},
73 static const value_string exttype_vals[] = {
75 {AODV6_EXT_INT, "Hello Interval"},
76 {AODV6_EXT_NTP, "Timestamp"},
80 typedef struct aodv6_rreq {
88 struct e_in6_addr dest_addr;
89 struct e_in6_addr orig_addr;
92 typedef struct aodv6_rrep {
98 struct e_in6_addr dest_addr;
99 struct e_in6_addr orig_addr;
103 typedef struct aodv6_rerr {
109 struct e_in6_addr dest_addr;
112 typedef struct aodv6_rrep_ack {
117 typedef struct aodv6_ext {
122 /* Initialize the protocol and registered fields */
123 static int proto_aodv6 = -1;
124 static int hf_aodv6_type = -1;
125 static int hf_aodv6_flags = -1;
126 static int hf_aodv6_prefix_sz = -1;
127 static int hf_aodv6_hopcount = -1;
128 static int hf_aodv6_rreq_id = -1;
129 static int hf_aodv6_dest_ip = -1;
130 static int hf_aodv6_dest_seqno = -1;
131 static int hf_aodv6_orig_ip = -1;
132 static int hf_aodv6_orig_seqno = -1;
133 static int hf_aodv6_lifetime = -1;
134 static int hf_aodv6_destcount = -1;
135 static int hf_aodv6_unreach_dest_ip = -1;
136 static int hf_aodv6_unreach_dest_seqno = -1;
137 static int hf_aodv6_flags_rreq_join = -1;
138 static int hf_aodv6_flags_rreq_repair = -1;
139 static int hf_aodv6_flags_rreq_gratuitous = -1;
140 static int hf_aodv6_flags_rrep_repair = -1;
141 static int hf_aodv6_flags_rrep_ack = -1;
142 static int hf_aodv6_flags_rerr_nodelete = -1;
143 static int hf_aodv6_ext_type = -1;
144 static int hf_aodv6_ext_length = -1;
145 static int hf_aodv6_ext_interval = -1;
146 static int hf_aodv6_ext_timestamp = -1;
148 /* Initialize the subtree pointers */
149 static gint ett_aodv6 = -1;
150 static gint ett_aodv6_flags = -1;
151 static gint ett_aodv6_unreach_dest = -1;
152 static gint ett_aodv6_extensions = -1;
156 dissect_aodv6ext(tvbuff_t * tvb, int offset, proto_tree * tree)
158 proto_tree *aodv6ext_tree;
160 aodv6_ext_t aodv6ext, *ext;
168 if ((int) tvb_reported_length(tvb) <= offset)
169 return; /* No more options left */
172 tvb_memcpy(tvb, (guint8 *) ext, offset, sizeof(*ext));
175 ti = proto_tree_add_text(tree, tvb, offset, sizeof(aodv6_ext_t) +
176 len, "AODV6 Extensions");
177 aodv6ext_tree = proto_item_add_subtree(ti, ett_aodv6_extensions);
180 proto_tree_add_text(aodv6ext_tree, tvb,
181 offset + offsetof(aodv6_ext_t, length), 1,
182 "Invalid option length: %u", ext->length);
183 return; /* we must not try to decode this */
188 typename = "Hello Interval";
191 typename = "Timestamp";
194 typename = "Unknown";
197 proto_tree_add_text(aodv6ext_tree, tvb,
198 offset + offsetof(aodv6_ext_t, type), 1,
199 "Type: %u (%s)", ext->type, typename);
200 proto_tree_add_text(aodv6ext_tree, tvb,
201 offset + offsetof(aodv6_ext_t, length), 1,
202 "Length: %u bytes", ext->length);
204 offset += sizeof(aodv6_ext_t);
208 proto_tree_add_uint(aodv6ext_tree, hf_aodv6_ext_interval,
209 tvb, offset, 4, tvb_get_ntohl(tvb, offset));
212 proto_tree_add_item(aodv6ext_tree, hf_aodv6_ext_timestamp,
213 tvb, offset, 8, FALSE);
218 /* If multifield extensions appear, we need more
219 * sophisticated handler. For now, this is okay. */
221 offset += ext->length;
226 dissect_aodv6(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
228 proto_item *ti = NULL, *tj = NULL, *tk = NULL;
229 proto_tree *aodv6_tree = NULL, *aodv6_flags_tree = NULL,
230 *aodv6_unreach_dest_tree = NULL;
237 /* Make entries in Protocol column and Info column on summary
240 if (check_col(pinfo->cinfo, COL_PROTOCOL))
241 col_set_str(pinfo->cinfo, COL_PROTOCOL, "AODV6");
243 if (check_col(pinfo->cinfo, COL_INFO))
244 col_clear(pinfo->cinfo, COL_INFO);
246 /* Check the type of AODV6 packet. */
247 type = tvb_get_guint8(tvb, 0);
248 if (type < AODV6_RREQ || type > AODV6_RREP_ACK) {
249 return 0; /* don't process */
253 ti = proto_tree_add_protocol_format(tree, proto_aodv6, tvb, 0, -1,
254 "Ad hoc On-demand Distance Vector v6, %s",
255 val_to_str(type, type_vals,
256 "Unknown AODV6 Packet Type (%u)"));
257 aodv6_tree = proto_item_add_subtree(ti, ett_aodv6);
259 proto_tree_add_uint(aodv6_tree, hf_aodv6_type, tvb, 0, 1, type);
260 tj = proto_tree_add_text(aodv6_tree, tvb, 1, 1, "Flags:");
261 aodv6_flags_tree = proto_item_add_subtree(tj, ett_aodv6_flags);
268 rreq.flags = tvb_get_guint8(tvb, offsetof(rreq_t, flags));
269 rreq.hop_count = tvb_get_guint8(tvb, offsetof(rreq_t, hop_count));
270 rreq.rreq_id = tvb_get_ntohl(tvb, offsetof(rreq_t, rreq_id));
271 rreq.dest_seqno = tvb_get_ntohl(tvb, offsetof(rreq_t, dest_seqno));
272 rreq.orig_seqno = tvb_get_ntohl(tvb, offsetof(rreq_t, orig_seqno));
273 tvb_memcpy(tvb, (guint8 *) & rreq.dest_addr,
274 offsetof(rreq_t, dest_addr), INET6_ADDRLEN);
275 tvb_memcpy(tvb, (guint8 *) & rreq.orig_addr,
276 offsetof(rreq_t, orig_addr), INET6_ADDRLEN);
279 proto_tree_add_boolean(aodv6_flags_tree,
280 hf_aodv6_flags_rreq_join, tvb,
281 offsetof(rreq_t, flags), 1, rreq.flags);
282 proto_tree_add_boolean(aodv6_flags_tree,
283 hf_aodv6_flags_rreq_repair, tvb,
284 offsetof(rreq_t, flags), 1, rreq.flags);
285 proto_tree_add_boolean(aodv6_flags_tree,
286 hf_aodv6_flags_rreq_gratuitous, tvb,
287 offsetof(rreq_t, flags), 1, rreq.flags);
288 if (rreq.flags & RREQ_JOIN)
289 proto_item_append_text(tj, " J");
290 if (rreq.flags & RREQ_REP)
291 proto_item_append_text(tj, " R");
292 if (rreq.flags & RREQ_GRAT)
293 proto_item_append_text(tj, " G");
294 proto_tree_add_uint(aodv6_tree, hf_aodv6_hopcount, tvb,
295 offsetof(rreq_t, hop_count), 1,
297 proto_tree_add_uint(aodv6_tree, hf_aodv6_rreq_id, tvb,
298 offsetof(rreq_t, rreq_id), 4,
300 proto_tree_add_uint(aodv6_tree, hf_aodv6_dest_seqno, tvb,
301 offsetof(rreq_t, dest_seqno), 4,
303 proto_tree_add_uint(aodv6_tree, hf_aodv6_orig_seqno, tvb,
304 offsetof(rreq_t, orig_seqno), 4,
306 proto_tree_add_ipv6(aodv6_tree, hf_aodv6_dest_ip, tvb,
307 offsetof(rreq_t, dest_addr),
309 (guint8 *) & rreq.dest_addr);
310 proto_tree_add_ipv6(aodv6_tree, hf_aodv6_orig_ip, tvb,
311 offsetof(rreq_t, orig_addr),
313 (guint8 *) & rreq.orig_addr);
314 proto_item_append_text(ti,
315 ", Dest IP: %s, Orig IP: %s, Id=%u",
316 ip6_to_str(&rreq.dest_addr),
317 ip6_to_str(&rreq.orig_addr),
319 extlen = ((int) tvb_reported_length(tvb) - sizeof(rreq_t));
321 dissect_aodv6ext(tvb, sizeof(rreq_t), aodv6_tree);
325 if (check_col(pinfo->cinfo, COL_INFO))
326 col_add_fstr(pinfo->cinfo, COL_INFO,
327 "%s, D: %s O: %s Id=%u Hcnt=%u DSN=%u OSN=%u",
328 val_to_str(type, type_vals,
329 "Unknown AODV6 Packet Type (%u)"),
330 ip6_to_str(&rreq.dest_addr),
331 ip6_to_str(&rreq.orig_addr),
333 rreq.hop_count, rreq.dest_seqno, rreq.orig_seqno);
337 rrep.flags = tvb_get_guint8(tvb, offsetof(rrep_t, flags));
338 rrep.prefix_sz = tvb_get_guint8(tvb, offsetof(rrep_t, prefix_sz)) & 0x1F;
339 rrep.hop_count = tvb_get_guint8(tvb, offsetof(rrep_t, hop_count));
340 rrep.dest_seqno = tvb_get_ntohl(tvb, offsetof(rrep_t, dest_seqno));
341 tvb_memcpy(tvb, (guint8 *) & rrep.dest_addr,
342 offsetof(rrep_t, dest_addr), INET6_ADDRLEN);
343 tvb_memcpy(tvb, (guint8 *) & rrep.orig_addr,
344 offsetof(rrep_t, orig_addr), INET6_ADDRLEN);
345 rrep.lifetime = tvb_get_ntohl(tvb, offsetof(rrep_t, lifetime));
348 proto_tree_add_boolean(aodv6_flags_tree,
349 hf_aodv6_flags_rrep_repair, tvb,
350 offsetof(rrep_t, flags), 1, rrep.flags);
351 proto_tree_add_boolean(aodv6_flags_tree,
352 hf_aodv6_flags_rrep_ack, tvb,
353 offsetof(rrep_t, flags), 1, rrep.flags);
354 if (rrep.flags & RREP_REP)
355 proto_item_append_text(tj, " R");
356 if (rrep.flags & RREP_ACK)
357 proto_item_append_text(tj, " A");
358 proto_tree_add_uint(aodv6_tree, hf_aodv6_prefix_sz,
359 tvb, offsetof(rrep_t, prefix_sz), 1,
361 proto_tree_add_uint(aodv6_tree, hf_aodv6_hopcount,
362 tvb, offsetof(rrep_t, hop_count), 1,
364 proto_tree_add_uint(aodv6_tree, hf_aodv6_dest_seqno,
365 tvb, offsetof(rrep_t, dest_seqno), 4,
367 proto_tree_add_ipv6(aodv6_tree, hf_aodv6_dest_ip,
368 tvb, offsetof(rrep_t, dest_addr),
370 (guint8 *) & rrep.dest_addr);
371 proto_tree_add_ipv6(aodv6_tree, hf_aodv6_orig_ip, tvb,
372 offsetof(rrep_t, orig_addr),
374 (guint8 *) & rrep.orig_addr);
375 proto_tree_add_uint(aodv6_tree, hf_aodv6_lifetime, tvb,
376 offsetof(rrep_t, lifetime), 4,
378 proto_item_append_text(ti,
379 ", Dest IP: %s, Orig IP: %s, Lifetime=%u",
380 ip6_to_str(&rrep.dest_addr),
381 ip6_to_str(&rrep.orig_addr),
383 extlen = ((int) tvb_reported_length(tvb) - sizeof(rrep_t));
385 dissect_aodv6ext(tvb, sizeof(rrep_t), aodv6_tree);
389 if (check_col(pinfo->cinfo, COL_INFO))
390 col_add_fstr(pinfo->cinfo, COL_INFO,
391 "%s D: %s O: %s Hcnt=%u DSN=%u Lifetime=%u",
392 val_to_str(type, type_vals,
393 "Unknown AODV6 Packet Type (%u)"),
394 ip6_to_str(&rrep.dest_addr),
395 ip6_to_str(&rrep.orig_addr),
396 rrep.hop_count, rrep.dest_seqno, rrep.lifetime);
400 rerr.flags = tvb_get_guint8(tvb, offsetof(rerr_t, flags));
402 tvb_get_guint8(tvb, offsetof(rerr_t, dest_count));
405 proto_tree_add_boolean(aodv6_flags_tree,
406 hf_aodv6_flags_rerr_nodelete, tvb,
407 offsetof(rerr_t, flags), 1, rerr.flags);
408 if (rerr.flags & RERR_NODEL)
409 proto_item_append_text(tj, " N");
410 proto_tree_add_uint(aodv6_tree, hf_aodv6_destcount, tvb,
411 offsetof(rerr_t, dest_count), 1,
413 tk = proto_tree_add_text(aodv6_tree, tvb,
414 offsetof(rerr_t, dest_addr),
416 INET6_ADDRLEN) * rerr.dest_count,
417 "Unreachable Destinations");
419 aodv6_unreach_dest_tree =
420 proto_item_add_subtree(tk, ett_aodv6_unreach_dest);
421 for (i = 0; i < rerr.dest_count; i++) {
423 tvb_get_ntohl(tvb, offsetof(rerr_t, dest_seqno)
424 + (4 + INET6_ADDRLEN) * i);
425 tvb_memcpy(tvb, (guint8 *) & rerr.dest_addr,
426 offsetof(rerr_t, dest_addr)
427 + (4 + INET6_ADDRLEN) * i, INET6_ADDRLEN);
428 proto_tree_add_uint(aodv6_unreach_dest_tree,
429 hf_aodv6_dest_seqno, tvb,
430 offsetof(rerr_t, dest_seqno)
431 + (4 + INET6_ADDRLEN) * i, 4,
433 proto_tree_add_ipv6(aodv6_unreach_dest_tree,
434 hf_aodv6_dest_ip, tvb,
435 offsetof(rerr_t, dest_addr)
436 + (4 + INET6_ADDRLEN) * i,
438 (guint8 *) & rerr.dest_addr);
442 if (check_col(pinfo->cinfo, COL_INFO))
443 col_add_fstr(pinfo->cinfo, COL_INFO,
445 val_to_str(type, type_vals,
446 "Unknown AODV6 Packet Type (%u)"),
450 if (check_col(pinfo->cinfo, COL_INFO))
451 col_add_fstr(pinfo->cinfo, COL_INFO, "%s",
452 val_to_str(type, type_vals,
453 "Unknown AODV6 Packet Type (%u)"));
456 proto_tree_add_text(aodv6_tree, tvb, 0, 1,
457 "Unknown AODV6 Packet Type (%u)", type);
460 return tvb_length(tvb);
463 /* Register the protocol with Ethereal */
465 proto_register_aodv6(void)
467 static hf_register_info hf[] = {
469 {"Type", "aodv6.type",
470 FT_UINT8, BASE_DEC, VALS(type_vals), 0x0,
471 "AODV6 packet type", HFILL}
474 {"Flags", "aodv6.flags",
475 FT_UINT16, BASE_DEC, NULL, 0x0,
478 {&hf_aodv6_flags_rreq_join,
479 {"RREQ Join", "aodv6.flags.rreq_join",
480 FT_BOOLEAN, 8, TFS(&flags_set_truth), RREQ_JOIN,
483 {&hf_aodv6_flags_rreq_repair,
484 {"RREQ Repair", "aodv6.flags.rreq_repair",
485 FT_BOOLEAN, 8, TFS(&flags_set_truth), RREQ_REP,
488 {&hf_aodv6_flags_rreq_gratuitous,
489 {"RREQ Gratuitous", "aodv6.flags.rreq_gratuitous",
490 FT_BOOLEAN, 8, TFS(&flags_set_truth), RREQ_GRAT,
493 {&hf_aodv6_flags_rrep_repair,
494 {"RREP Repair", "aodv6.flags.rrep_repair",
495 FT_BOOLEAN, 8, TFS(&flags_set_truth), RREP_REP,
498 {&hf_aodv6_flags_rrep_ack,
499 {"RREP Acknowledgment", "aodv6.flags.rrep_ack",
500 FT_BOOLEAN, 8, TFS(&flags_set_truth), RREP_ACK,
503 {&hf_aodv6_flags_rerr_nodelete,
504 {"RERR No Delete", "aodv6.flags.rerr_nodelete",
505 FT_BOOLEAN, 8, TFS(&flags_set_truth), RERR_NODEL,
508 {&hf_aodv6_prefix_sz,
509 {"Prefix Size", "aodv6.prefix_sz",
510 FT_UINT8, BASE_DEC, NULL, 0x0,
511 "Prefix Size", HFILL}
514 {"Hop Count", "aodv6.hopcount",
515 FT_UINT8, BASE_DEC, NULL, 0x0,
519 {"RREQ ID", "aodv6.rreq_id",
520 FT_UINT32, BASE_DEC, NULL, 0x0,
523 {&hf_aodv6_dest_seqno,
524 {"Destination Sequence Number", "aodv6.dest_seqno",
525 FT_UINT32, BASE_DEC, NULL, 0x0,
526 "Destination Sequence Number", HFILL}
528 {&hf_aodv6_orig_seqno,
529 {"Originator Sequence Number", "aodv6.orig_seqno",
530 FT_UINT32, BASE_DEC, NULL, 0x0,
531 "Originator Sequence Number", HFILL}
534 {"Destination IP", "aodv6.dest_ip",
535 FT_IPv6, BASE_DEC, NULL, 0x0,
536 "Destination IP Address", HFILL}
539 {"Originator IP", "aodv6.orig_ip",
540 FT_IPv6, BASE_DEC, NULL, 0x0,
541 "Originator IP Address", HFILL}
544 {"Lifetime", "aodv6.lifetime",
545 FT_UINT32, BASE_DEC, NULL, 0x0,
548 {&hf_aodv6_destcount,
549 {"Destination Count", "aodv6.destcount",
550 FT_UINT8, BASE_DEC, NULL, 0x0,
551 "Unreachable Destinations Count", HFILL}
553 {&hf_aodv6_unreach_dest_seqno,
554 {"Unreachable Destination Sequence Number",
555 "aodv6.unreach_dest_seqno",
556 FT_UINT32, BASE_DEC, NULL, 0x0,
557 "Unreachable Destination Sequence Number", HFILL}
559 {&hf_aodv6_unreach_dest_ip,
560 {"Unreachable Destination IP", "aodv6.unreach_dest_ip",
561 FT_IPv6, BASE_DEC, NULL, 0x0,
562 "Unreachable Destination IP Address", HFILL}
565 {"Extension Type", "aodv6.ext_type",
566 FT_UINT8, BASE_DEC, NULL, 0x0,
567 "Extension Format Type", HFILL}
569 {&hf_aodv6_ext_length,
570 {"Extension Length", "aodv6.ext_length",
571 FT_UINT8, BASE_DEC, NULL, 0x0,
572 "Extension Data Length", HFILL}
574 {&hf_aodv6_ext_interval,
575 {"Hello Interval", "aodv6.hello_interval",
576 FT_UINT32, BASE_DEC, NULL, 0x0,
577 "Hello Interval Extension", HFILL}
579 {&hf_aodv6_ext_timestamp,
580 {"Timestamp", "aodv6.timestamp",
581 FT_UINT64, BASE_DEC, NULL, 0x0,
582 "Timestamp Extension", HFILL}
586 /* Setup protocol subtree array */
587 static gint *ett[] = {
590 &ett_aodv6_unreach_dest,
591 &ett_aodv6_extensions,
594 /* Register the protocol name and description */
596 proto_register_protocol
597 ("Ad hoc On-demand Distance Vector Routing Protocol v6", "AODV6",
600 /* Required function calls to register the header fields and
603 proto_register_field_array(proto_aodv6, hf, array_length(hf));
604 proto_register_subtree_array(ett, array_length(ett));
608 proto_reg_handoff_aodv6(void)
610 dissector_handle_t aodv6_handle;
612 aodv6_handle = new_create_dissector_handle(dissect_aodv6, proto_aodv6);
613 dissector_add("udp.port", UDP_PORT_AODV6, aodv6_handle);