Fix some aclocal warnings during autogen.sh
[obnox/wireshark/wip.git] / packet-aodv.c
1 /* packet-aodv.c
2  * Routines for AODV dissection
3  * Copyright 2000, Erik Nordström <erik.nordstrom@it.uu.se>
4  *
5  * $Id: packet-aodv.c,v 1.10 2003/09/13 00:57:10 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #ifdef HAVE_STDDEF_H
31 #include <stddef.h>
32 #endif
33 #include <string.h>
34
35 #include <glib.h>
36
37 #include <epan/int-64bit.h>
38 #include <epan/packet.h>
39 #include <epan/ipv6-utils.h>
40
41 #ifndef offsetof
42 #define offsetof(type, member)  ((size_t)(&((type *)0)->member))
43 #endif
44
45 /*
46  * See
47  *
48  *      http://www.ietf.org/internet-drafts/draft-ietf-manet-aodv-13.txt
49  *
50  *      http://www.cs.ucsb.edu/~ebelding/txt/aodv6.txt
51  *
52  *      http://www.tcs.hut.fi/~anttit/manet/drafts/draft-perkins-aodv6-01.txt
53  */
54
55 #define INET6_ADDRLEN   16
56 #define UDP_PORT_AODV   654
57
58 /* Message Types */
59 #define RREQ                    1
60 #define RREP                    2
61 #define RERR                    3
62 #define RREP_ACK                4
63 #define DRAFT_01_V6_RREQ        16
64 #define DRAFT_01_V6_RREP        17
65 #define DRAFT_01_V6_RERR        18
66 #define DRAFT_01_V6_RREP_ACK    19
67
68 /* Extension Types */
69 #define AODV_EXT        1
70 #define AODV_EXT_INT    2
71 #define AODV_EXT_NTP    3
72
73 /* Flag bits: */
74 #define RREQ_GRAT       0x20
75 #define RREQ_REP        0x40
76 #define RREQ_JOIN       0x80
77
78 #define RREP_ACK_REQ    0x40
79 #define RREP_REP        0x80
80
81 #define RERR_NODEL      0x80
82
83 static const value_string type_vals[] = {
84     { RREQ,                 "Route Request" },
85     { RREP,                 "Route Reply" },
86     { RERR,                 "Route Error" },
87     { RREP_ACK,             "Route Reply Acknowledgment"},
88     { DRAFT_01_V6_RREQ,     "draft-perkins-aodv6-01 Route Request"},
89     { DRAFT_01_V6_RREP,     "draft-perkins-aodv6-01 Route Reply"},
90     { DRAFT_01_V6_RERR,     "draft-perkins-aodv6-01 Route Error"},
91     { DRAFT_01_V6_RREP_ACK, "draft-perkins-aodv6-01 Route Reply Acknowledgment"},
92     { 0,                    NULL }
93 };
94
95 static const value_string exttype_vals[] = {
96     { AODV_EXT,     "None"},
97     { AODV_EXT_INT, "Hello Interval"},
98     { AODV_EXT_NTP, "Timestamp"},
99     { 0,            NULL}
100 };
101
102 typedef struct v6_ext {
103     guint8 type;
104     guint8 length;
105 } aodv_ext_t;
106
107 /* Initialize the protocol and registered fields */
108 static int proto_aodv = -1;
109 static int hf_aodv_type = -1;
110 static int hf_aodv_flags = -1;
111 static int hf_aodv_prefix_sz = -1;
112 static int hf_aodv_hopcount = -1;
113 static int hf_aodv_rreq_id = -1;
114 static int hf_aodv_dest_ip = -1;
115 static int hf_aodv_dest_ipv6 = -1;
116 static int hf_aodv_dest_seqno = -1;
117 static int hf_aodv_orig_ip = -1;
118 static int hf_aodv_orig_ipv6 = -1;
119 static int hf_aodv_orig_seqno = -1;
120 static int hf_aodv_lifetime = -1;
121 static int hf_aodv_destcount = -1;
122 static int hf_aodv_unreach_dest_ip = -1;
123 static int hf_aodv_unreach_dest_ipv6 = -1;
124 static int hf_aodv_unreach_dest_seqno = -1;
125 static int hf_aodv_flags_rreq_join = -1;
126 static int hf_aodv_flags_rreq_repair = -1;
127 static int hf_aodv_flags_rreq_gratuitous = -1;
128 static int hf_aodv_flags_rrep_repair = -1;
129 static int hf_aodv_flags_rrep_ack = -1;
130 static int hf_aodv_flags_rerr_nodelete = -1;
131 static int hf_aodv_ext_type = -1;
132 static int hf_aodv_ext_length = -1;
133 static int hf_aodv_ext_interval = -1;
134 static int hf_aodv_ext_timestamp = -1;
135
136 /* Initialize the subtree pointers */
137 static gint ett_aodv = -1;
138 static gint ett_aodv_flags = -1;
139 static gint ett_aodv_unreach_dest = -1;
140 static gint ett_aodv_extensions = -1;
141
142 /* Code to actually dissect the packets */
143
144 static void
145 dissect_aodv_ext(tvbuff_t * tvb, int offset, proto_tree * tree)
146 {
147     proto_tree *ext_tree;
148     proto_item *ti;
149     aodv_ext_t aodvext, *ext;
150     int len;
151
152     if (!tree)
153         return;
154
155   again:
156     if ((int) tvb_reported_length(tvb) <= offset)
157         return;                 /* No more options left */
158
159     ext = &aodvext;
160     tvb_memcpy(tvb, (guint8 *) ext, offset, sizeof(*ext));
161     len = ext->length;
162
163     ti = proto_tree_add_text(tree, tvb, offset, sizeof(aodv_ext_t) +
164                              len, "Extensions");
165     ext_tree = proto_item_add_subtree(ti, ett_aodv_extensions);
166
167     if (len == 0) {
168         proto_tree_add_text(ext_tree, tvb,
169                             offset + offsetof(aodv_ext_t, length), 1,
170                             "Invalid option length: %u", ext->length);
171         return;                 /* we must not try to decode this */
172     }
173
174     proto_tree_add_text(ext_tree, tvb,
175                         offset + offsetof(aodv_ext_t, type), 1,
176                         "Type: %u (%s)", ext->type,
177                         val_to_str(ext->type, exttype_vals, "Unknown"));
178     proto_tree_add_text(ext_tree, tvb,
179                         offset + offsetof(aodv_ext_t, length), 1,
180                         "Length: %u bytes", ext->length);
181
182     offset += sizeof(aodv_ext_t);
183
184     switch (ext->type) {
185     case AODV_EXT_INT:
186         proto_tree_add_uint(ext_tree, hf_aodv_ext_interval,
187                             tvb, offset, 4, tvb_get_ntohl(tvb, offset));
188         break;
189     case AODV_EXT_NTP:
190         proto_tree_add_item(ext_tree, hf_aodv_ext_timestamp,
191                             tvb, offset, 8, FALSE);
192         break;
193     default:
194         break;
195     }
196     /* If multifield extensions appear, we need more
197      * sophisticated handler.  For now, this is okay. */
198
199     offset += ext->length;
200     goto again;
201 }
202
203 static void
204 dissect_aodv_rreq(tvbuff_t *tvb, packet_info *pinfo, proto_tree *aodv_tree,
205                   proto_item *ti, gboolean is_ipv6)
206 {
207     int offset = 1;
208     proto_item *tj;
209     proto_tree *aodv_flags_tree;
210     guint8 flags;
211     guint8 hop_count;
212     guint32 rreq_id;
213     guint32 dest_addr_v4;
214     struct e_in6_addr dest_addr_v6;
215     guint32 dest_seqno;
216     guint32 orig_addr_v4;
217     struct e_in6_addr orig_addr_v6;
218     guint32 orig_seqno;
219     int extlen;
220
221     flags = tvb_get_guint8(tvb, offset);
222     if (aodv_tree) {
223         tj = proto_tree_add_text(aodv_tree, tvb, offset, 1, "Flags:");
224         aodv_flags_tree = proto_item_add_subtree(tj, ett_aodv_flags);
225         proto_tree_add_boolean(aodv_flags_tree, hf_aodv_flags_rreq_join,
226                                tvb, offset, 1, flags);
227         proto_tree_add_boolean(aodv_flags_tree, hf_aodv_flags_rreq_repair,
228                                tvb, offset, 1, flags);
229         proto_tree_add_boolean(aodv_flags_tree, hf_aodv_flags_rreq_gratuitous,
230                                tvb, offset, 1, flags);
231         if (flags & RREQ_JOIN)
232             proto_item_append_text(tj, " J");
233         if (flags & RREQ_REP)
234             proto_item_append_text(tj, " R");
235         if (flags & RREQ_GRAT)
236             proto_item_append_text(tj, " G");
237     }
238     offset += 2;        /* skip reserved byte */
239
240     hop_count = tvb_get_guint8(tvb, offset);
241     if (aodv_tree)
242         proto_tree_add_uint(aodv_tree, hf_aodv_hopcount, tvb, offset, 1,
243                             hop_count);
244     offset += 1;
245
246     rreq_id = tvb_get_ntohl(tvb, offset);
247     if (aodv_tree)
248         proto_tree_add_uint(aodv_tree, hf_aodv_rreq_id, tvb, offset, 4,
249                             rreq_id);
250     offset += 4;
251
252     if (is_ipv6) {
253         tvb_memcpy(tvb, (guint8 *)&dest_addr_v6, offset, INET6_ADDRLEN);
254         if (aodv_tree) {
255             proto_tree_add_ipv6(aodv_tree, hf_aodv_dest_ipv6, tvb, offset,
256                                 INET6_ADDRLEN, (guint8 *)&dest_addr_v6);
257             proto_item_append_text(ti, ", Dest IP: %s",
258                                    ip6_to_str(&dest_addr_v6));
259         }
260         if (check_col(pinfo->cinfo, COL_INFO))
261             col_append_fstr(pinfo->cinfo, COL_INFO, ", D: %s",
262                             ip6_to_str(&dest_addr_v6));
263         offset += INET6_ADDRLEN;
264     } else {
265         tvb_memcpy(tvb, (guint8 *)&dest_addr_v4, offset, 4);
266         if (aodv_tree) {
267             proto_tree_add_ipv4(aodv_tree, hf_aodv_dest_ip, tvb, offset, 4,
268                                 dest_addr_v4);
269             proto_item_append_text(ti, ", Dest IP: %s",
270                                    ip_to_str((guint8 *)&dest_addr_v4));
271         }
272         if (check_col(pinfo->cinfo, COL_INFO))
273             col_append_fstr(pinfo->cinfo, COL_INFO, ", D: %s",
274                             ip_to_str((guint8 *)&dest_addr_v4));
275         offset += 4;
276     }
277
278     dest_seqno = tvb_get_ntohl(tvb, offset);
279     if (aodv_tree)
280         proto_tree_add_uint(aodv_tree, hf_aodv_dest_seqno, tvb, offset, 4,
281                             dest_seqno);
282     offset += 4;
283
284     if (is_ipv6) {
285         tvb_memcpy(tvb, (guint8 *)&orig_addr_v6, offset, INET6_ADDRLEN);
286         if (aodv_tree) {
287             proto_tree_add_ipv6(aodv_tree, hf_aodv_orig_ipv6, tvb, offset,
288                                 INET6_ADDRLEN, (guint8 *)&orig_addr_v6);
289             proto_item_append_text(ti, ", Orig IP: %s",
290                                    ip6_to_str(&orig_addr_v6));
291         }
292         if (check_col(pinfo->cinfo, COL_INFO))
293             col_append_fstr(pinfo->cinfo, COL_INFO, ", O: %s",
294                             ip6_to_str(&orig_addr_v6));
295         offset += INET6_ADDRLEN;
296     } else {
297         tvb_memcpy(tvb, (guint8 *)&orig_addr_v4, offset, 4);
298         if (aodv_tree) {
299             proto_tree_add_ipv4(aodv_tree, hf_aodv_orig_ip, tvb, offset, 4,
300                                 orig_addr_v4);
301             proto_item_append_text(ti, ", Orig IP: %s",
302                                    ip_to_str((guint8 *)&orig_addr_v4));
303         }
304         if (check_col(pinfo->cinfo, COL_INFO))
305             col_append_fstr(pinfo->cinfo, COL_INFO, ", O: %s",
306                             ip_to_str((guint8 *)&orig_addr_v4));
307         offset += 4;
308     }
309
310     orig_seqno = tvb_get_ntohl(tvb, offset);
311     if (aodv_tree)
312         proto_tree_add_uint(aodv_tree, hf_aodv_orig_seqno, tvb, offset, 4,
313                             orig_seqno);
314     if (check_col(pinfo->cinfo, COL_INFO))
315         col_append_fstr(pinfo->cinfo, COL_INFO, " Id=%u Hcnt=%u DSN=%u OSN=%u",
316                         rreq_id,
317                         hop_count,
318                         dest_seqno,
319                         orig_seqno);
320     offset += 4;
321
322     if (aodv_tree) {
323         extlen = tvb_reported_length_remaining(tvb, offset);
324         if (extlen > 0)
325             dissect_aodv_ext(tvb, offset, aodv_tree);
326     }
327 }
328
329 static void
330 dissect_aodv_rrep(tvbuff_t *tvb, packet_info *pinfo, proto_tree *aodv_tree,
331                   proto_item *ti, gboolean is_ipv6)
332 {
333     int offset = 1;
334     proto_item *tj;
335     proto_tree *aodv_flags_tree;
336     guint8 flags;
337     guint8 prefix_sz;
338     guint8 hop_count;
339     guint32 dest_addr_v4;
340     struct e_in6_addr dest_addr_v6;
341     guint32 dest_seqno;
342     guint32 orig_addr_v4;
343     struct e_in6_addr orig_addr_v6;
344     guint32 lifetime;
345     int extlen;
346
347     flags = tvb_get_guint8(tvb, offset);
348     if (aodv_tree) {
349         tj = proto_tree_add_text(aodv_tree, tvb, offset, 1, "Flags:");
350         aodv_flags_tree = proto_item_add_subtree(tj, ett_aodv_flags);
351         proto_tree_add_boolean(aodv_flags_tree, hf_aodv_flags_rrep_repair,
352                                tvb, offset, 1, flags);
353         proto_tree_add_boolean(aodv_flags_tree, hf_aodv_flags_rrep_ack, tvb,
354                                offset, 1, flags);
355         if (flags & RREP_REP)
356             proto_item_append_text(tj, " R");
357         if (flags & RREP_ACK_REQ)
358             proto_item_append_text(tj, " A");
359     }
360     offset += 1;
361
362     prefix_sz = tvb_get_guint8(tvb, offset) & 0x1F;
363     if (aodv_tree)
364         proto_tree_add_uint(aodv_tree, hf_aodv_prefix_sz, tvb, offset, 1,
365                             prefix_sz);
366     offset += 1;
367
368     hop_count = tvb_get_guint8(tvb, offset);
369     if (aodv_tree)
370         proto_tree_add_uint(aodv_tree, hf_aodv_hopcount, tvb, offset, 1,
371                             hop_count);
372     offset += 1;
373
374     if (is_ipv6) {
375         tvb_memcpy(tvb, (guint8 *)&dest_addr_v6, offset, INET6_ADDRLEN);
376         if (aodv_tree) {
377             proto_tree_add_ipv6(aodv_tree, hf_aodv_dest_ipv6, tvb, offset,
378                                 INET6_ADDRLEN, (guint8 *)&dest_addr_v6);
379             proto_item_append_text(ti, ", Dest IP: %s",
380                                    ip6_to_str(&dest_addr_v6));
381         }
382         if (check_col(pinfo->cinfo, COL_INFO))
383             col_append_fstr(pinfo->cinfo, COL_INFO, ", D: %s",
384                             ip6_to_str(&dest_addr_v6));
385         offset += INET6_ADDRLEN;
386     } else {
387         tvb_memcpy(tvb, (guint8 *)&dest_addr_v4, offset, 4);
388         if (aodv_tree) {
389             proto_tree_add_ipv4(aodv_tree, hf_aodv_dest_ip, tvb, offset, 4,
390                                 dest_addr_v4);
391             proto_item_append_text(ti, ", Dest IP: %s",
392                                    ip_to_str((guint8 *)&dest_addr_v4));
393         }
394         if (check_col(pinfo->cinfo, COL_INFO))
395             col_append_fstr(pinfo->cinfo, COL_INFO, ", D: %s",
396                             ip_to_str((guint8 *)&dest_addr_v4));
397         offset += 4;
398     }
399
400     dest_seqno = tvb_get_ntohl(tvb, offset);
401     if (aodv_tree)
402         proto_tree_add_uint(aodv_tree, hf_aodv_dest_seqno, tvb, offset, 4,
403                             dest_seqno);
404     offset += 4;
405
406     if (is_ipv6) {
407         tvb_memcpy(tvb, (guint8 *)&orig_addr_v6, offset, INET6_ADDRLEN);
408         if (aodv_tree) {
409             proto_tree_add_ipv6(aodv_tree, hf_aodv_orig_ipv6, tvb, offset,
410                                 INET6_ADDRLEN, (guint8 *)&orig_addr_v6);
411             proto_item_append_text(ti, ", Dest IP: %s",
412                                    ip6_to_str(&orig_addr_v6));
413         }
414         if (check_col(pinfo->cinfo, COL_INFO))
415             col_append_fstr(pinfo->cinfo, COL_INFO, ", D: %s",
416                             ip6_to_str(&orig_addr_v6));
417         offset += INET6_ADDRLEN;
418     } else {
419         tvb_memcpy(tvb, (guint8 *)&orig_addr_v4, offset, 4);
420         if (aodv_tree) {
421             proto_tree_add_ipv4(aodv_tree, hf_aodv_orig_ip, tvb, offset, 4,
422                                 orig_addr_v4);
423             proto_item_append_text(ti, ", Orig IP: %s",
424                                    ip_to_str((guint8 *)&orig_addr_v4));
425         }
426         if (check_col(pinfo->cinfo, COL_INFO))
427             col_append_fstr(pinfo->cinfo, COL_INFO, ", O: %s",
428                             ip_to_str((guint8 *)&orig_addr_v4));
429         offset += 4;
430     }
431
432     lifetime = tvb_get_ntohl(tvb, offset);
433     if (aodv_tree) {
434         proto_tree_add_uint(aodv_tree, hf_aodv_lifetime, tvb, offset, 4,
435                             lifetime);
436         proto_item_append_text(ti, ", Lifetime=%u", lifetime);
437     }
438     if (check_col(pinfo->cinfo, COL_INFO))
439         col_append_fstr(pinfo->cinfo, COL_INFO, " Hcnt=%u DSN=%u Lifetime=%u",
440                         hop_count,
441                         dest_seqno,
442                         lifetime);
443     offset += 4;
444
445     if (aodv_tree) {
446         extlen = tvb_reported_length_remaining(tvb, offset);
447         if (extlen > 0)
448             dissect_aodv_ext(tvb, offset, aodv_tree);
449     }
450 }
451
452 static void
453 dissect_aodv_rerr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *aodv_tree,
454                   gboolean is_ipv6)
455 {
456     int offset = 1;
457     proto_item *tj;
458     proto_tree *aodv_flags_tree;
459     proto_tree *aodv_unreach_dest_tree;
460     guint8 flags;
461     guint8 dest_count;
462     int i;
463
464     flags = tvb_get_guint8(tvb, offset);
465     if (aodv_tree) {
466         tj = proto_tree_add_text(aodv_tree, tvb, offset, 1, "Flags:");
467         aodv_flags_tree = proto_item_add_subtree(tj, ett_aodv_flags);
468         proto_tree_add_boolean(aodv_flags_tree, hf_aodv_flags_rerr_nodelete,
469                                tvb, offset, 1, flags);
470         if (flags & RERR_NODEL)
471             proto_item_append_text(tj, " N");
472     }
473     offset += 2;        /* skip reserved byte */
474
475     dest_count = tvb_get_guint8(tvb, offset);
476     if (aodv_tree)
477         proto_tree_add_uint(aodv_tree, hf_aodv_destcount, tvb, offset, 1,
478                             dest_count);
479     if (check_col(pinfo->cinfo, COL_INFO))
480         col_append_fstr(pinfo->cinfo, COL_INFO, ", Dest Count=%u",
481                         dest_count);
482     offset += 1;
483
484     if (is_ipv6) {
485         tj = proto_tree_add_text(aodv_tree, tvb, offset,
486                                  (INET6_ADDRLEN + 4)*dest_count,
487                                  "Unreachable Destinations");
488         aodv_unreach_dest_tree = proto_item_add_subtree(tj, ett_aodv_unreach_dest);
489         for (i = 0; i < dest_count; i++) {
490             proto_tree_add_item(aodv_unreach_dest_tree,
491                                 hf_aodv_unreach_dest_ipv6,
492                                 tvb, offset, INET6_ADDRLEN, FALSE);
493             proto_tree_add_item(aodv_unreach_dest_tree, hf_aodv_dest_seqno,
494                                 tvb, offset, 4, FALSE);
495             offset += INET6_ADDRLEN + 4;
496         }
497     } else {
498         tj = proto_tree_add_text(aodv_tree, tvb, offset, (4 + 4)*dest_count,
499                                  "Unreachable Destinations");
500         aodv_unreach_dest_tree = proto_item_add_subtree(tj, ett_aodv_unreach_dest);
501         for (i = 0; i < dest_count; i++) {
502             proto_tree_add_item(aodv_unreach_dest_tree, hf_aodv_unreach_dest_ip,
503                                 tvb, offset, 4, FALSE);
504             proto_tree_add_item(aodv_unreach_dest_tree, hf_aodv_dest_seqno,
505                                 tvb, offset, 4, FALSE);
506             offset += 4 + 4;
507         }
508     }
509 }
510
511 static void
512 dissect_aodv_draft_01_v6_rreq(tvbuff_t *tvb, packet_info *pinfo,
513                               proto_tree *aodv_tree, proto_item *ti)
514 {
515     int offset = 1;
516     proto_item *tj;
517     proto_tree *aodv_flags_tree;
518     guint8 flags;
519     guint8 hop_count;
520     guint32 rreq_id;
521     guint32 dest_seqno;
522     guint32 orig_seqno;
523     struct e_in6_addr dest_addr_v6;
524     struct e_in6_addr orig_addr_v6;
525     int extlen;
526
527     flags = tvb_get_guint8(tvb, offset);
528     if (aodv_tree) {
529         tj = proto_tree_add_text(aodv_tree, tvb, offset, 1, "Flags:");
530         aodv_flags_tree = proto_item_add_subtree(tj, ett_aodv_flags);
531         proto_tree_add_boolean(aodv_flags_tree, hf_aodv_flags_rreq_join,
532                                tvb, offset, 1, flags);
533         proto_tree_add_boolean(aodv_flags_tree, hf_aodv_flags_rreq_repair,
534                                tvb, offset, 1, flags);
535         proto_tree_add_boolean(aodv_flags_tree, hf_aodv_flags_rreq_gratuitous,
536                                tvb, offset, 1, flags);
537         if (flags & RREQ_JOIN)
538             proto_item_append_text(tj, " J");
539         if (flags & RREQ_REP)
540             proto_item_append_text(tj, " R");
541         if (flags & RREQ_GRAT)
542             proto_item_append_text(tj, " G");
543     }
544     offset += 2;        /* skip reserved byte */
545
546     hop_count = tvb_get_guint8(tvb, offset);
547     if (aodv_tree)
548         proto_tree_add_uint(aodv_tree, hf_aodv_hopcount, tvb, offset, 1,
549                              hop_count);
550     offset += 1;
551
552     rreq_id = tvb_get_ntohl(tvb, offset);
553     if (aodv_tree)
554         proto_tree_add_uint(aodv_tree, hf_aodv_rreq_id, tvb, offset, 4,
555                             rreq_id);
556     offset += 4;
557
558     dest_seqno = tvb_get_ntohl(tvb, offset);
559     if (aodv_tree)
560         proto_tree_add_uint(aodv_tree, hf_aodv_dest_seqno, tvb, offset, 4,
561                             dest_seqno);
562     offset += 4;
563
564     orig_seqno = tvb_get_ntohl(tvb, offset);
565     if (aodv_tree)
566         proto_tree_add_uint(aodv_tree, hf_aodv_orig_seqno, tvb, offset, 4,
567                             orig_seqno);
568     offset += 4;
569
570     tvb_memcpy(tvb, (guint8 *)&dest_addr_v6, offset, INET6_ADDRLEN);
571     if (aodv_tree) {
572         proto_tree_add_ipv6(aodv_tree, hf_aodv_dest_ipv6, tvb, offset,
573                             INET6_ADDRLEN, (guint8 *)&dest_addr_v6);
574         proto_item_append_text(ti, ", Dest IP: %s",
575                                ip6_to_str(&dest_addr_v6));
576     }
577     if (check_col(pinfo->cinfo, COL_INFO))
578         col_append_fstr(pinfo->cinfo, COL_INFO, ", D: %s",
579                         ip6_to_str(&dest_addr_v6));
580     offset += INET6_ADDRLEN;
581
582     tvb_memcpy(tvb, (guint8 *)&orig_addr_v6, offset, INET6_ADDRLEN);
583     if (aodv_tree) {
584         proto_tree_add_ipv6(aodv_tree, hf_aodv_orig_ipv6, tvb, offset,
585                             INET6_ADDRLEN, (guint8 *)&orig_addr_v6);
586         proto_item_append_text(ti, ", Orig IP: %s",
587                                ip6_to_str(&orig_addr_v6));
588     }
589     if (check_col(pinfo->cinfo, COL_INFO))
590         col_append_fstr(pinfo->cinfo, COL_INFO,
591                         ", O: %s Id=%u Hcnt=%u DSN=%u OSN=%u",
592                         ip6_to_str(&orig_addr_v6),
593                         rreq_id,
594                         hop_count,
595                         dest_seqno,
596                         orig_seqno);
597     offset += INET6_ADDRLEN;
598
599     if (aodv_tree) {
600         extlen = tvb_reported_length_remaining(tvb, offset);
601         if (extlen > 0)
602             dissect_aodv_ext(tvb, offset, aodv_tree);
603     }
604 }
605
606 static void
607 dissect_aodv_draft_01_v6_rrep(tvbuff_t *tvb, packet_info *pinfo,
608                               proto_tree *aodv_tree, proto_item *ti)
609 {
610     int offset = 1;
611     proto_item *tj;
612     proto_tree *aodv_flags_tree;
613     guint8 flags;
614     guint8 prefix_sz;
615     guint8 hop_count;
616     guint32 dest_seqno;
617     struct e_in6_addr dest_addr_v6;
618     struct e_in6_addr orig_addr_v6;
619     guint32 lifetime;
620     int extlen;
621
622     flags = tvb_get_guint8(tvb, offset);
623     if (aodv_tree) {
624         tj = proto_tree_add_text(aodv_tree, tvb, offset, 1, "Flags:");
625         aodv_flags_tree = proto_item_add_subtree(tj, ett_aodv_flags);
626         proto_tree_add_boolean(aodv_flags_tree, hf_aodv_flags_rrep_repair,
627                                tvb, offset, 1, flags);
628         proto_tree_add_boolean(aodv_flags_tree, hf_aodv_flags_rrep_ack, tvb,
629                                offset, 1, flags);
630         if (flags & RREP_REP)
631             proto_item_append_text(tj, " R");
632         if (flags & RREP_ACK_REQ)
633             proto_item_append_text(tj, " A");
634     }
635     offset += 1;
636
637     prefix_sz = tvb_get_guint8(tvb, offset) & 0x1F;
638     if (aodv_tree)
639         proto_tree_add_uint(aodv_tree, hf_aodv_prefix_sz, tvb, offset, 1,
640                             prefix_sz);
641     offset += 1;
642
643     hop_count = tvb_get_guint8(tvb, offset);
644     if (aodv_tree)
645         proto_tree_add_uint(aodv_tree, hf_aodv_hopcount, tvb, offset, 1,
646                             hop_count);
647     offset += 1;
648
649     dest_seqno = tvb_get_ntohl(tvb, offset);
650     if (aodv_tree)
651         proto_tree_add_uint(aodv_tree, hf_aodv_dest_seqno, tvb, offset, 4,
652                             dest_seqno);
653     offset += 4;
654
655     tvb_memcpy(tvb, (guint8 *)&dest_addr_v6, offset, INET6_ADDRLEN);
656     if (aodv_tree) {
657         proto_tree_add_ipv6(aodv_tree, hf_aodv_dest_ipv6, tvb, offset,
658                             INET6_ADDRLEN, (guint8 *)&dest_addr_v6);
659         proto_item_append_text(ti, ", Dest IP: %s",
660                                ip6_to_str(&dest_addr_v6));
661     }
662     if (check_col(pinfo->cinfo, COL_INFO))
663         col_append_fstr(pinfo->cinfo, COL_INFO, ", D: %s",
664                         ip6_to_str(&dest_addr_v6));
665     offset += INET6_ADDRLEN;
666
667     tvb_memcpy(tvb, (guint8 *)&orig_addr_v6, offset, INET6_ADDRLEN);
668     if (aodv_tree) {
669         proto_tree_add_ipv6(aodv_tree, hf_aodv_orig_ipv6, tvb, offset,
670                             INET6_ADDRLEN, (guint8 *)&orig_addr_v6);
671         proto_item_append_text(ti, ", Dest IP: %s",
672                                ip6_to_str(&orig_addr_v6));
673     }
674     if (check_col(pinfo->cinfo, COL_INFO))
675         col_append_fstr(pinfo->cinfo, COL_INFO, ", D: %s",
676                         ip6_to_str(&orig_addr_v6));
677     offset += INET6_ADDRLEN;
678
679     lifetime = tvb_get_ntohl(tvb, offset);
680     if (aodv_tree) {
681         proto_tree_add_uint(aodv_tree, hf_aodv_lifetime, tvb, offset, 4,
682                             lifetime);
683         proto_item_append_text(ti, ", Lifetime=%u", lifetime);
684     }
685     if (check_col(pinfo->cinfo, COL_INFO))
686         col_append_fstr(pinfo->cinfo, COL_INFO, " Hcnt=%u DSN=%u Lifetime=%u",
687                         hop_count,
688                         dest_seqno,
689                         lifetime);
690     offset += 4;
691
692     if (aodv_tree) {
693         extlen = tvb_reported_length_remaining(tvb, offset);
694         if (extlen > 0)
695             dissect_aodv_ext(tvb, offset, aodv_tree);
696     }
697 }
698
699 static void
700 dissect_aodv_draft_01_v6_rerr(tvbuff_t *tvb, packet_info *pinfo,
701                               proto_tree *aodv_tree)
702 {
703     int offset = 1;
704     proto_item *tj;
705     proto_tree *aodv_flags_tree;
706     proto_tree *aodv_unreach_dest_tree;
707     guint8 flags;
708     guint8 dest_count;
709     int i;
710
711     flags = tvb_get_guint8(tvb, offset);
712     if (aodv_tree) {
713         tj = proto_tree_add_text(aodv_tree, tvb, offset, 1, "Flags:");
714         aodv_flags_tree = proto_item_add_subtree(tj, ett_aodv_flags);
715         proto_tree_add_boolean(aodv_flags_tree, hf_aodv_flags_rerr_nodelete,
716                                tvb, offset, 1, flags);
717         if (flags & RERR_NODEL)
718             proto_item_append_text(tj, " N");
719     }
720     offset += 2;        /* skip reserved byte */
721
722     dest_count = tvb_get_guint8(tvb, offset);
723     if (aodv_tree)
724         proto_tree_add_uint(aodv_tree, hf_aodv_destcount, tvb, offset, 1,
725                             dest_count);
726     if (check_col(pinfo->cinfo, COL_INFO))
727         col_append_fstr(pinfo->cinfo, COL_INFO, ", Dest Count=%u",
728                         dest_count);
729     offset += 1;
730
731     tj = proto_tree_add_text(aodv_tree, tvb, offset,
732                              (4 + INET6_ADDRLEN)*dest_count,
733                              "Unreachable Destinations");
734     aodv_unreach_dest_tree = proto_item_add_subtree(tj, ett_aodv_unreach_dest);
735     for (i = 0; i < dest_count; i++) {
736         proto_tree_add_item(aodv_unreach_dest_tree, hf_aodv_dest_seqno,
737                             tvb, offset, 4, FALSE);
738         proto_tree_add_item(aodv_unreach_dest_tree,
739                             hf_aodv_unreach_dest_ipv6,
740                             tvb, offset, INET6_ADDRLEN, FALSE);
741         offset += 4 + INET6_ADDRLEN;
742     }
743 }
744
745 static int
746 dissect_aodv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
747 {
748     proto_item *ti = NULL;
749     proto_tree *aodv_tree = NULL;
750     gboolean is_ipv6;
751     guint8 type;
752
753 /* Make entries in Protocol column and Info column on summary display */
754     if (check_col(pinfo->cinfo, COL_PROTOCOL))
755         col_set_str(pinfo->cinfo, COL_PROTOCOL, "AODV");
756
757     if (check_col(pinfo->cinfo, COL_INFO))
758         col_clear(pinfo->cinfo, COL_INFO);
759
760     /* Is this running over IPv6? */
761     is_ipv6 = (pinfo->src.type == AT_IPv6);
762
763     /* Check the type of AODV packet. */
764     type = tvb_get_guint8(tvb, 0);
765     if (match_strval(type, type_vals) == NULL) {
766         /*
767          * We assume this is not an AODV packet.
768          */
769         return 0;
770     }
771
772     if (check_col(pinfo->cinfo, COL_INFO))
773         col_add_fstr(pinfo->cinfo, COL_INFO, "%s",
774                      val_to_str(type, type_vals,
775                                 "Unknown AODV Packet Type (%u)"));
776     if (tree) {
777         ti = proto_tree_add_protocol_format(tree, proto_aodv, tvb, 0, -1,
778             "Ad hoc On-demand Distance Vector Routing Protocol, %s",
779             val_to_str(type, type_vals, "Unknown AODV Packet Type (%u)"));
780         aodv_tree = proto_item_add_subtree(ti, ett_aodv);
781
782         proto_tree_add_uint(aodv_tree, hf_aodv_type, tvb, 0, 1, type);
783     }
784
785     switch (type) {
786     case RREQ:
787         dissect_aodv_rreq(tvb, pinfo, tree, ti, is_ipv6);
788         break;
789     case RREP:
790         dissect_aodv_rrep(tvb, pinfo, tree, ti, is_ipv6);
791         break;
792     case RERR:
793         dissect_aodv_rerr(tvb, pinfo, tree, is_ipv6);
794         break;
795     case RREP_ACK:
796         break;
797     case DRAFT_01_V6_RREQ:
798         dissect_aodv_draft_01_v6_rreq(tvb, pinfo, tree, ti);
799         break;
800     case DRAFT_01_V6_RREP:
801         dissect_aodv_draft_01_v6_rrep(tvb, pinfo, tree, ti);
802         break;
803     case DRAFT_01_V6_RERR:
804         dissect_aodv_draft_01_v6_rerr(tvb, pinfo, tree);
805         break;
806     case DRAFT_01_V6_RREP_ACK:
807         break;
808     default:
809         proto_tree_add_text(aodv_tree, tvb, 0, -1,
810                             "Unknown AODV Packet Type (%u)", type);
811     }
812
813     return tvb_length(tvb);
814 }
815
816
817 /* Register the protocol with Ethereal */
818 void
819 proto_register_aodv(void)
820 {
821     static hf_register_info hf[] = {
822         { &hf_aodv_type,
823           { "Type", "aodv.type",
824             FT_UINT8, BASE_DEC, VALS(type_vals), 0x0,
825             "AODV packet type", HFILL }
826         },
827         { &hf_aodv_flags,
828           { "Flags", "aodv.flags",
829             FT_UINT16, BASE_DEC, NULL, 0x0,
830             "Flags", HFILL }
831         },
832         { &hf_aodv_flags_rreq_join,
833           { "RREQ Join", "aodv.flags.rreq_join",
834             FT_BOOLEAN, 8, TFS(&flags_set_truth), RREQ_JOIN,
835             "", HFILL }
836         },
837         { &hf_aodv_flags_rreq_repair,
838           { "RREQ Repair", "aodv.flags.rreq_repair",
839             FT_BOOLEAN, 8, TFS(&flags_set_truth), RREQ_REP,
840             "", HFILL }
841         },
842         { &hf_aodv_flags_rreq_gratuitous,
843           { "RREQ Gratuitous", "aodv.flags.rreq_gratuitous",
844             FT_BOOLEAN, 8, TFS(&flags_set_truth), RREQ_GRAT,
845             "", HFILL }
846         },
847         { &hf_aodv_flags_rrep_repair,
848           { "RREP Repair", "aodv.flags.rrep_repair",
849             FT_BOOLEAN, 8, TFS(&flags_set_truth), RREP_REP,
850             "", HFILL }
851         },
852         { &hf_aodv_flags_rrep_ack,
853           { "RREP Acknowledgement", "aodv.flags.rrep_ack",
854             FT_BOOLEAN, 8, TFS(&flags_set_truth), RREP_ACK_REQ,
855             "", HFILL }
856         },
857         { &hf_aodv_flags_rerr_nodelete,
858           { "RERR No Delete", "aodv.flags.rerr_nodelete",
859             FT_BOOLEAN, 8, TFS(&flags_set_truth), RERR_NODEL,
860             "", HFILL }
861         },
862         { &hf_aodv_prefix_sz,
863           { "Prefix Size", "aodv.prefix_sz",
864             FT_UINT8, BASE_DEC, NULL, 0x0,
865             "Prefix Size", HFILL }
866         },
867         { &hf_aodv_hopcount,
868           { "Hop Count", "aodv.hopcount",
869             FT_UINT8, BASE_DEC, NULL, 0x0,
870             "Hop Count", HFILL }
871         },
872         { &hf_aodv_rreq_id,
873           { "RREQ Id", "aodv.rreq_id",
874             FT_UINT32, BASE_DEC, NULL, 0x0,
875             "RREQ Id", HFILL }
876         },
877         { &hf_aodv_dest_ip,
878           { "Destination IP", "aodv.dest_ip",
879             FT_IPv4, BASE_NONE, NULL, 0x0,
880             "Destination IP Address", HFILL }
881         },
882         { &hf_aodv_dest_ipv6,
883           { "Destination IPv6", "aodv.dest_ipv6",
884             FT_IPv6, BASE_NONE, NULL, 0x0,
885             "Destination IPv6 Address", HFILL}
886         },
887         { &hf_aodv_dest_seqno,
888           { "Destination Sequence Number", "aodv.dest_seqno",
889             FT_UINT32, BASE_DEC, NULL, 0x0,
890             "Destination Sequence Number", HFILL }
891         },
892         { &hf_aodv_orig_ip,
893           { "Originator IP", "aodv.orig_ip",
894             FT_IPv4, BASE_NONE, NULL, 0x0,
895             "Originator IP Address", HFILL }
896         },
897         { &hf_aodv_orig_ipv6,
898           { "Originator IPv6", "aodv.orig_ipv6",
899             FT_IPv6, BASE_NONE, NULL, 0x0,
900             "Originator IPv6 Address", HFILL}
901         },
902         { &hf_aodv_orig_seqno,
903           { "Originator Sequence Number", "aodv.orig_seqno",
904             FT_UINT32, BASE_DEC, NULL, 0x0,
905             "Originator Sequence Number", HFILL }
906         },
907         { &hf_aodv_lifetime,
908           { "Lifetime", "aodv.lifetime",
909             FT_UINT32, BASE_DEC, NULL, 0x0,
910             "Lifetime", HFILL }
911         },
912         { &hf_aodv_destcount,
913           { "Destination Count", "aodv.destcount",
914             FT_UINT8, BASE_DEC, NULL, 0x0,
915             "Unreachable Destinations Count", HFILL }
916         },
917         { &hf_aodv_unreach_dest_ip,
918           { "Unreachable Destination IP", "aodv.unreach_dest_ip",
919             FT_IPv4, BASE_NONE, NULL, 0x0,
920             "Unreachable Destination IP Address", HFILL }
921         },
922         { &hf_aodv_unreach_dest_ipv6,
923           { "Unreachable Destination IPv6", "aodv.unreach_dest_ipv6",
924             FT_IPv6, BASE_NONE, NULL, 0x0,
925             "Unreachable Destination IPv6 Address", HFILL}
926         },
927         { &hf_aodv_unreach_dest_seqno,
928           { "Unreachable Destination Sequence Number", "aodv.unreach_dest_seqno",
929             FT_UINT32, BASE_DEC, NULL, 0x0,
930             "Unreachable Destination Sequence Number", HFILL }
931         },
932         { &hf_aodv_ext_type,
933           { "Extension Type", "aodv.ext_type",
934             FT_UINT8, BASE_DEC, NULL, 0x0,
935             "Extension Format Type", HFILL}
936         },
937         { &hf_aodv_ext_length,
938           { "Extension Length", "aodv.ext_length",
939             FT_UINT8, BASE_DEC, NULL, 0x0,
940             "Extension Data Length", HFILL}
941         },
942         { &hf_aodv_ext_interval,
943           { "Hello Interval", "aodv.hello_interval",
944             FT_UINT32, BASE_DEC, NULL, 0x0,
945             "Hello Interval Extension", HFILL}
946          },
947         { &hf_aodv_ext_timestamp,
948           { "Timestamp", "aodv.timestamp",
949             FT_UINT64, BASE_DEC, NULL, 0x0,
950             "Timestamp Extension", HFILL}
951          },
952     };
953
954 /* Setup protocol subtree array */
955     static gint *ett[] = {
956         &ett_aodv,
957         &ett_aodv_flags,
958         &ett_aodv_unreach_dest,
959         &ett_aodv_extensions,
960     };
961
962 /* Register the protocol name and description */
963     proto_aodv = proto_register_protocol("Ad hoc On-demand Distance Vector Routing Protocol", "AODV", "aodv");
964
965 /* Required function calls to register the header fields and subtrees used */
966     proto_register_field_array(proto_aodv, hf, array_length(hf));
967     proto_register_subtree_array(ett, array_length(ett));
968 }
969
970
971 void
972 proto_reg_handoff_aodv(void)
973 {
974     dissector_handle_t aodv_handle;
975
976     aodv_handle = new_create_dissector_handle(dissect_aodv,
977                                               proto_aodv);
978     dissector_add("udp.port", UDP_PORT_AODV, aodv_handle);
979 }