Eliminate the packet_info pointer argument from routines that don't use
[metze/wireshark/wip.git] / packet-aodv6.c
1 /* packet-aodv6.c
2  * Routines for AODV6 dissection
3  * Copyright 2002, Antti J. Tuominen <ajtuomin@tml.hut.fi>
4  * Loosely based on packet-aodv.c.
5  *
6  * $Id: packet-aodv6.c,v 1.5 2002/08/28 21:00:07 jmayer Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1998 Gerald Combs
11  *
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.
16  *
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.
21  *
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.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <string.h>
32 #include <glib.h>
33 #include <epan/int-64bit.h>
34 #include <epan/packet.h>
35 #include <epan/ipv6-utils.h>
36
37 #ifndef offsetof
38 #define offsetof(type, member)  ((size_t)(&((type *)0)->member))
39 #endif
40
41 #define INET6_ADDRLEN   16
42 #define UDP_PORT_AODV6  654
43
44 /* Message Types */
45 #define AODV6_RREQ      16
46 #define AODV6_RREP      17
47 #define AODV6_RERR      18
48 #define AODV6_RREP_ACK  19
49
50 /* Extension Types */
51 #define AODV6_EXT       1
52 #define AODV6_EXT_INT   2
53 #define AODV6_EXT_NTP   3
54
55 /* Flag bits: */
56 #define RREQ_GRAT    0x20
57 #define RREQ_REP     0x40
58 #define RREQ_JOIN    0x80
59
60 #define RREP_ACK     0x40
61 #define RREP_REP     0x80
62
63 #define RERR_NODEL   0x80
64
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"},
70     {0, NULL}
71 };
72
73 static const value_string exttype_vals[] = {
74     {AODV6_EXT, "None"},
75     {AODV6_EXT_INT, "Hello Interval"},
76     {AODV6_EXT_NTP, "Timestamp"},
77     {0, NULL}
78 };
79
80 typedef struct aodv6_rreq {
81     guint8 type;
82     guint8 flags;
83     guint8 res;
84     guint8 hop_count;
85     guint32 rreq_id;
86     guint32 dest_seqno;
87     guint32 orig_seqno;
88     struct e_in6_addr dest_addr;
89     struct e_in6_addr orig_addr;
90 } rreq_t;
91
92 typedef struct aodv6_rrep {
93     guint8 type;
94     guint8 flags;
95     guint8 prefix_sz;
96     guint8 hop_count;
97     guint32 dest_seqno;
98     struct e_in6_addr dest_addr;
99     struct e_in6_addr orig_addr;
100     guint32 lifetime;
101 } rrep_t;
102
103 typedef struct aodv6_rerr {
104     guint8 type;
105     guint8 flags;
106     guint8 res;
107     guint8 dest_count;
108     guint32 dest_seqno;
109     struct e_in6_addr dest_addr;
110 } rerr_t;
111
112 typedef struct aodv6_rrep_ack {
113     guint8 type;
114     guint8 res;
115 } rrep_ack_t;
116
117 typedef struct aodv6_ext {
118     guint8 type;
119     guint8 length;
120 } aodv6_ext_t;
121
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;
147
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;
153
154
155 static void
156 dissect_aodv6ext(tvbuff_t * tvb, int offset, proto_tree * tree)
157 {
158     proto_tree *aodv6ext_tree;
159     proto_item *ti;
160     aodv6_ext_t aodv6ext, *ext;
161     char *typename;
162     int len;
163
164     if (!tree)
165         return;
166
167   again:
168     if ((int) tvb_reported_length(tvb) <= offset)
169         return;                 /* No more options left */
170
171     ext = &aodv6ext;
172     tvb_memcpy(tvb, (guint8 *) ext, offset, sizeof(*ext));
173     len = ext->length;
174
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);
178
179     if (len == 0) {
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 */
184     }
185
186     switch (ext->type) {
187     case AODV6_EXT_INT:
188         typename = "Hello Interval";
189         break;
190     case AODV6_EXT_NTP:
191         typename = "Timestamp";
192         break;
193     default:
194         typename = "Unknown";
195         break;
196     }
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);
203
204     offset += sizeof(aodv6_ext_t);
205
206     switch (ext->type) {
207     case AODV6_EXT_INT:
208         proto_tree_add_uint(aodv6ext_tree, hf_aodv6_ext_interval,
209                             tvb, offset, 4, tvb_get_ntohl(tvb, offset));
210         break;
211     case AODV6_EXT_NTP:
212         proto_tree_add_item(aodv6ext_tree, hf_aodv6_ext_timestamp,
213                             tvb, offset, 8, FALSE);
214         break;
215     default:
216         break;
217     }
218     /* If multifield extensions appear, we need more
219      * sophisticated handler.  For now, this is okay. */
220
221     offset += ext->length;
222     goto again;
223 }
224
225 static int
226 dissect_aodv6(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
227 {
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;
231     guint8 type;
232     int i, extlen;
233     rreq_t rreq;
234     rrep_t rrep;
235     rerr_t rerr;
236
237     /* Make entries in Protocol column and Info column on summary
238      * display
239      */
240     if (check_col(pinfo->cinfo, COL_PROTOCOL))
241         col_set_str(pinfo->cinfo, COL_PROTOCOL, "AODV6");
242
243     if (check_col(pinfo->cinfo, COL_INFO))
244         col_clear(pinfo->cinfo, COL_INFO);
245
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 */
250     }
251
252     if (tree) {
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);
258
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);
262     }
263
264
265     switch (type) {
266     case AODV6_RREQ:
267         rreq.type = type;
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);
277
278         if (tree) {
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,
296                                 rreq.hop_count);
297             proto_tree_add_uint(aodv6_tree, hf_aodv6_rreq_id, tvb,
298                                 offsetof(rreq_t, rreq_id), 4,
299                                 rreq.rreq_id);
300             proto_tree_add_uint(aodv6_tree, hf_aodv6_dest_seqno, tvb,
301                                 offsetof(rreq_t, dest_seqno), 4,
302                                 rreq.dest_seqno);
303             proto_tree_add_uint(aodv6_tree, hf_aodv6_orig_seqno, tvb,
304                                 offsetof(rreq_t, orig_seqno), 4,
305                                 rreq.orig_seqno);
306             proto_tree_add_ipv6(aodv6_tree, hf_aodv6_dest_ip, tvb,
307                                 offsetof(rreq_t, dest_addr),
308                                 INET6_ADDRLEN,
309                                 (guint8 *) & rreq.dest_addr);
310             proto_tree_add_ipv6(aodv6_tree, hf_aodv6_orig_ip, tvb,
311                                 offsetof(rreq_t, orig_addr),
312                                 INET6_ADDRLEN,
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),
318                                    rreq.rreq_id);
319             extlen = ((int) tvb_reported_length(tvb) - sizeof(rreq_t));
320             if (extlen > 0) {
321                 dissect_aodv6ext(tvb, sizeof(rreq_t), aodv6_tree);
322             }
323         }
324
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),
332                          rreq.rreq_id,
333                          rreq.hop_count, rreq.dest_seqno, rreq.orig_seqno);
334         break;
335     case AODV6_RREP:
336         rrep.type = type;
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));
346
347         if (tree) {
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,
360                                 rrep.prefix_sz);
361             proto_tree_add_uint(aodv6_tree, hf_aodv6_hopcount,
362                                 tvb, offsetof(rrep_t, hop_count), 1,
363                                 rrep.hop_count);
364             proto_tree_add_uint(aodv6_tree, hf_aodv6_dest_seqno,
365                                 tvb, offsetof(rrep_t, dest_seqno), 4,
366                                 rrep.dest_seqno);
367             proto_tree_add_ipv6(aodv6_tree, hf_aodv6_dest_ip,
368                                 tvb, offsetof(rrep_t, dest_addr),
369                                 INET6_ADDRLEN,
370                                 (guint8 *) & rrep.dest_addr);
371             proto_tree_add_ipv6(aodv6_tree, hf_aodv6_orig_ip, tvb,
372                                 offsetof(rrep_t, orig_addr),
373                                 INET6_ADDRLEN,
374                                 (guint8 *) & rrep.orig_addr);
375             proto_tree_add_uint(aodv6_tree, hf_aodv6_lifetime, tvb,
376                                 offsetof(rrep_t, lifetime), 4,
377                                 rrep.lifetime);
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),
382                                    rrep.lifetime);
383             extlen = ((int) tvb_reported_length(tvb) - sizeof(rrep_t));
384             if (extlen > 0) {
385                 dissect_aodv6ext(tvb, sizeof(rrep_t), aodv6_tree);
386             }
387         }
388
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);
397         break;
398     case AODV6_RERR:
399         rerr.type = type;
400         rerr.flags = tvb_get_guint8(tvb, offsetof(rerr_t, flags));
401         rerr.dest_count =
402             tvb_get_guint8(tvb, offsetof(rerr_t, dest_count));
403
404         if (tree) {
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,
412                                 rerr.dest_count);
413             tk = proto_tree_add_text(aodv6_tree, tvb,
414                                      offsetof(rerr_t, dest_addr),
415                                      (4 +
416                                       INET6_ADDRLEN) * rerr.dest_count,
417                                      "Unreachable Destinations");
418
419             aodv6_unreach_dest_tree =
420                 proto_item_add_subtree(tk, ett_aodv6_unreach_dest);
421             for (i = 0; i < rerr.dest_count; i++) {
422                 rerr.dest_seqno =
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,
432                                     rerr.dest_seqno);
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,
437                                     INET6_ADDRLEN,
438                                     (guint8 *) & rerr.dest_addr);
439             }
440         }
441
442         if (check_col(pinfo->cinfo, COL_INFO))
443             col_add_fstr(pinfo->cinfo, COL_INFO,
444                          "%s, Dest Count=%u",
445                          val_to_str(type, type_vals,
446                                     "Unknown AODV6 Packet Type (%u)"),
447                          rerr.dest_count);
448         break;
449     case AODV6_RREP_ACK:
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)"));
454         break;
455     default:
456         proto_tree_add_text(aodv6_tree, tvb, 0, 1,
457                             "Unknown AODV6 Packet Type (%u)", type);
458     }
459
460     return tvb_length(tvb);
461 }
462
463 /* Register the protocol with Ethereal */
464 void
465 proto_register_aodv6(void)
466 {
467     static hf_register_info hf[] = {
468         {&hf_aodv6_type,
469          {"Type", "aodv6.type",
470           FT_UINT8, BASE_DEC, VALS(type_vals), 0x0,
471           "AODV6 packet type", HFILL}
472          },
473         {&hf_aodv6_flags,
474          {"Flags", "aodv6.flags",
475           FT_UINT16, BASE_DEC, NULL, 0x0,
476           "Flags", HFILL}
477          },
478         {&hf_aodv6_flags_rreq_join,
479          {"RREQ Join", "aodv6.flags.rreq_join",
480           FT_BOOLEAN, 8, TFS(&flags_set_truth), RREQ_JOIN,
481           "", HFILL}
482          },
483         {&hf_aodv6_flags_rreq_repair,
484          {"RREQ Repair", "aodv6.flags.rreq_repair",
485           FT_BOOLEAN, 8, TFS(&flags_set_truth), RREQ_REP,
486           "", HFILL}
487          },
488         {&hf_aodv6_flags_rreq_gratuitous,
489          {"RREQ Gratuitous", "aodv6.flags.rreq_gratuitous",
490           FT_BOOLEAN, 8, TFS(&flags_set_truth), RREQ_GRAT,
491           "", HFILL}
492          },
493         {&hf_aodv6_flags_rrep_repair,
494          {"RREP Repair", "aodv6.flags.rrep_repair",
495           FT_BOOLEAN, 8, TFS(&flags_set_truth), RREP_REP,
496           "", HFILL}
497          },
498         {&hf_aodv6_flags_rrep_ack,
499          {"RREP Acknowledgment", "aodv6.flags.rrep_ack",
500           FT_BOOLEAN, 8, TFS(&flags_set_truth), RREP_ACK,
501           "", HFILL}
502          },
503         {&hf_aodv6_flags_rerr_nodelete,
504          {"RERR No Delete", "aodv6.flags.rerr_nodelete",
505           FT_BOOLEAN, 8, TFS(&flags_set_truth), RERR_NODEL,
506           "", HFILL}
507          },
508         {&hf_aodv6_prefix_sz,
509          {"Prefix Size", "aodv6.prefix_sz",
510           FT_UINT8, BASE_DEC, NULL, 0x0,
511           "Prefix Size", HFILL}
512          },
513         {&hf_aodv6_hopcount,
514          {"Hop Count", "aodv6.hopcount",
515           FT_UINT8, BASE_DEC, NULL, 0x0,
516           "Hop Count", HFILL}
517          },
518         {&hf_aodv6_rreq_id,
519          {"RREQ ID", "aodv6.rreq_id",
520           FT_UINT32, BASE_DEC, NULL, 0x0,
521           "RREQ ID", HFILL}
522          },
523         {&hf_aodv6_dest_seqno,
524          {"Destination Sequence Number", "aodv6.dest_seqno",
525           FT_UINT32, BASE_DEC, NULL, 0x0,
526           "Destination Sequence Number", HFILL}
527          },
528         {&hf_aodv6_orig_seqno,
529          {"Originator Sequence Number", "aodv6.orig_seqno",
530           FT_UINT32, BASE_DEC, NULL, 0x0,
531           "Originator Sequence Number", HFILL}
532          },
533         {&hf_aodv6_dest_ip,
534          {"Destination IP", "aodv6.dest_ip",
535           FT_IPv6, BASE_DEC, NULL, 0x0,
536           "Destination IP Address", HFILL}
537          },
538         {&hf_aodv6_orig_ip,
539          {"Originator IP", "aodv6.orig_ip",
540           FT_IPv6, BASE_DEC, NULL, 0x0,
541           "Originator IP Address", HFILL}
542          },
543         {&hf_aodv6_lifetime,
544          {"Lifetime", "aodv6.lifetime",
545           FT_UINT32, BASE_DEC, NULL, 0x0,
546           "Lifetime", HFILL}
547          },
548         {&hf_aodv6_destcount,
549          {"Destination Count", "aodv6.destcount",
550           FT_UINT8, BASE_DEC, NULL, 0x0,
551           "Unreachable Destinations Count", HFILL}
552          },
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}
558          },
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}
563          },
564         {&hf_aodv6_ext_type,
565          {"Extension Type", "aodv6.ext_type",
566           FT_UINT8, BASE_DEC, NULL, 0x0,
567           "Extension Format Type", HFILL}
568          },
569         {&hf_aodv6_ext_length,
570          {"Extension Length", "aodv6.ext_length",
571           FT_UINT8, BASE_DEC, NULL, 0x0,
572           "Extension Data Length", HFILL}
573          },
574         {&hf_aodv6_ext_interval,
575          {"Hello Interval", "aodv6.hello_interval",
576           FT_UINT32, BASE_DEC, NULL, 0x0,
577           "Hello Interval Extension", HFILL}
578          },
579         {&hf_aodv6_ext_timestamp,
580          {"Timestamp", "aodv6.timestamp",
581           FT_UINT64, BASE_DEC, NULL, 0x0,
582           "Timestamp Extension", HFILL}
583          },
584     };
585
586     /* Setup protocol subtree array */
587     static gint *ett[] = {
588         &ett_aodv6,
589         &ett_aodv6_flags,
590         &ett_aodv6_unreach_dest,
591         &ett_aodv6_extensions,
592     };
593
594     /* Register the protocol name and description */
595     proto_aodv6 =
596         proto_register_protocol
597         ("Ad hoc On-demand Distance Vector Routing Protocol v6", "AODV6",
598          "aodv6");
599
600     /* Required function calls to register the header fields and
601      * subtrees
602      */
603     proto_register_field_array(proto_aodv6, hf, array_length(hf));
604     proto_register_subtree_array(ett, array_length(ett));
605 }
606
607 void
608 proto_reg_handoff_aodv6(void)
609 {
610     dissector_handle_t aodv6_handle;
611
612     aodv6_handle = new_create_dissector_handle(dissect_aodv6, proto_aodv6);
613     dissector_add("udp.port", UDP_PORT_AODV6, aodv6_handle);
614 }