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