bb20433a2c23fc6da39de90f524a846a59acc761
[metze/wireshark/wip.git] / epan / dissectors / packet-olsr.c
1 /* packet-olsr.c
2  * Routines for OLSR (IPv4 & IPv6 compatible) RFC parsing
3  * Compatible with RFC-compliant OLSR implementations such as
4  * NRLOLSRD (http://pf.itd.nrl.navy.mil/projects/olsr/).
5  * Parser created by Aaron Woo <woo@itd.nrl.navy.mil> of
6  * the Naval Research Laboratory
7  * Currently maintained by Jeff Weston <weston@itd.nrl.navy.mil>.
8  *
9  * Updated to Olsr.org and NRLOLSR packages by Henning Rogge <rogge@fgan.de>
10  * http://www.ietf.org/rfc/rfc3626.txt
11  *
12  * $Id$
13  *
14  * Wireshark - Network traffic analyzer
15  * By Gerald Combs <gerald@wireshark.org>
16  * Copyright 1998 Gerald Combs
17  *
18  * This program is free software; you can redistribute it and/or
19  * modify it under the terms of the GNU General Public License
20  * as published by the Free Software Foundation; either version 2
21  * of the License, or (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program; if not, write to the Free Software
30  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31  */
32
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #include <stdlib.h>
38 #include <string.h>
39
40 #ifdef HAVE_SYS_TYPES_H
41 # include <sys/types.h>
42 #endif
43
44 #ifdef HAVE_NETINET_IN_H
45 # include <netinet/in.h>
46 #endif
47
48 #include <glib.h>
49
50 #include <epan/packet.h>
51 #include <epan/prefs.h>
52
53 #define UDP_PORT_OLSR   698
54 #define HELLO   1
55 #define TC      2
56 #define MID     3
57 #define HNA     4
58
59 #define OLSR_ORG_NAMESERVICE 130
60 #define OLSR_ORG_LQ_HELLO    201
61 #define OLSR_ORG_LQ_TC       202
62 #define NRLOLSR_TC_EXTRA     241
63
64 /* Initialize the protocol and registered fields */
65 static int proto_olsr = -1;
66
67 static int hf_olsr_packet_len = -1;
68 static int hf_olsr_packet_seq_num = -1;
69
70 static int hf_olsr_message = -1;
71 static int hf_olsr_message_type = -1;
72 static int hf_olsr_vtime = -1;
73 static int hf_olsr_message_size = -1;
74 static int hf_olsr_ttl = -1;
75 static int hf_olsr_hop_count = -1;
76 static int hf_olsr_message_seq_num = -1;
77
78 static int hf_olsr_htime = -1;
79 static int hf_olsr_willingness = -1;
80
81 static int hf_olsr_link_type = -1;
82 static int hf_olsr_link_message_size = -1;
83 static int hf_olsr_ansn = -1;
84
85 static int hf_olsr_neighbor = -1;
86 static int hf_olsr_origin_addr = -1;
87 static int hf_olsr_neighbor_addr = -1;
88 static int hf_olsr_interface_addr = -1;
89 static int hf_olsr_netmask = -1;
90 static int hf_olsr_network_addr = -1;
91
92 static int hf_olsr_neighbor6 = -1;
93 static int hf_olsr_origin6_addr = -1;
94 static int hf_olsr_neighbor6_addr = -1;
95 static int hf_olsr_interface6_addr = -1;
96 static int hf_olsr_netmask6 = -1;
97 static int hf_olsr_network6_addr = -1;
98
99 static int hf_olsrorg_lq = -1;
100 static int hf_olsrorg_nlq = -1;
101 static int hf_nrlolsr_f1 = -1;
102 static int hf_nrlolsr_f2 = -1;
103
104 static int hf_olsrorg_ns_version = -1;
105 static int hf_olsrorg_ns_count = -1;
106
107 static int hf_olsrorg_ns = -1;
108 static int hf_olsrorg_ns_type = -1;
109 static int hf_olsrorg_ns_length = -1;
110 static int hf_olsrorg_ns_ip = -1;
111 static int hf_olsrorg_ns_ip6 = -1;
112 static int hf_olsrorg_ns_content = -1;
113
114 static int hf_olsr_data = -1;
115
116 /* Initialize the subtree pointers*/
117 static gint ett_olsr = -1;
118 static gint ett_olsr_message[G_MAXUINT8 + 1];
119 static gint ett_olsr_message_linktype = -1;
120 static gint ett_olsr_message_neigh = -1;
121 static gint ett_olsr_message_neigh6 = -1;
122 static gint ett_olsr_message_ns = -1;
123
124 static const value_string message_type_vals[] = {
125     { HELLO, "HELLO" },
126     { TC, "TC" },
127     { MID, "MID" },
128     { HNA, "HNA" },
129     { OLSR_ORG_LQ_HELLO, "HELLO (LQ, olsr.org)" },
130     { OLSR_ORG_LQ_TC, "TC (LQ, olsr.org)" },
131     { OLSR_ORG_NAMESERVICE, "Nameservice (olsr.org)" },
132     { NRLOLSR_TC_EXTRA, "TC (LQ, nrlolsr)" },
133     { 0, NULL }
134 };
135
136 static const value_string link_type_vals[] = {
137     { 0, "Unspecified Link" },
138     { 1, "Asymmetric Link" },
139     { 3, "Lost Link" },
140     { 5, "Pending Link" },
141     { 6, "Symmetric Link" },
142     { 10, "MPR Link" },
143     { 0, NULL }
144 };
145
146 static const value_string willingness_type_vals[] = {
147     { 0, "never" },
148     { 7, "always" },
149     { 0, NULL }
150 };
151
152 static const value_string nameservice_type_vals[] = {
153     { 0, "HOST" },
154     { 1, "FORWARDER" },
155     { 2, "SERVICE" },
156     { 3, "LATLON" },
157     { 0, NULL }
158 };
159
160 static gboolean global_olsr_olsrorg = TRUE;
161 static gboolean global_olsr_nrlolsr = TRUE;
162
163 static double getOlsrTime(guint8 timeval) {
164   int high_bits, low_bits;
165
166   high_bits = ((timeval & 0xF0) >> 4);
167   low_bits = (timeval & 0x0F);
168   return ((1 << low_bits) / 16.0) * (1 + (high_bits / 16.0));
169 }
170
171 /*------------------------- TC Dissecting Code-------------------------*/
172 static int dissect_olsr_tc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *olsr_tree, int offset, int message_end) {
173   if (message_end - offset < 4) {
174     proto_tree_add_bytes_format(olsr_tree, hf_olsr_ansn, tvb, offset, message_end - offset,
175         NULL, "Not enough bytes for TC");
176     return message_end;
177   }
178
179   proto_tree_add_item(olsr_tree, hf_olsr_ansn, tvb, offset, 2, FALSE);
180   offset += 4;
181
182   while (offset < message_end) {
183     if (message_end - offset < pinfo->src.len) {
184       proto_tree_add_bytes_format(olsr_tree, hf_olsr_neighbor_addr, tvb, offset, message_end - offset,
185           NULL, "Not enough bytes for last neighbor");
186       return message_end;
187     }
188     if (pinfo->src.type == AT_IPv4) {
189       proto_tree_add_item(olsr_tree, hf_olsr_neighbor_addr, tvb, offset, 4, FALSE);
190       offset += 4;
191     } else if (pinfo->src.type == AT_IPv6) {
192       proto_tree_add_item(olsr_tree, hf_olsr_neighbor6_addr, tvb, offset, 16, FALSE);
193       offset += 16;
194     } else {
195       break; /* unknown address type should be handled in dissect_olsr, just be sure */
196     }
197   }
198   return message_end;
199 }
200
201 static int dissect_olsrorg_lq_tc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *olsr_tree, int offset, int message_end) {
202
203   if (message_end - offset < 4) {
204     proto_tree_add_bytes_format(olsr_tree, hf_olsr_ansn, tvb, offset, message_end - offset,
205         NULL, "Not enough bytes for Olsr.org LQ-TC");
206     return message_end;
207   }
208   proto_tree_add_item(olsr_tree, hf_olsr_ansn, tvb, offset, 2, FALSE);
209   offset += 4;
210
211   while (offset < message_end) {
212     proto_item *address_group;
213     proto_tree *address_tree;
214     guint8 lq, nlq;
215
216     if (pinfo->src.type == AT_IPv4) {
217       if (message_end - offset < 8) {
218         proto_tree_add_bytes_format(olsr_tree, hf_olsr_neighbor, tvb, offset, message_end - offset,
219             NULL, "Not enough bytes for last entry (need 8 bytes)");
220         return message_end;
221       }
222       lq = tvb_get_guint8(tvb, offset + 4);
223       nlq = tvb_get_guint8(tvb, offset + 5);
224
225       address_group = proto_tree_add_bytes_format(olsr_tree, hf_olsr_neighbor, tvb, offset, 8,
226           NULL, "Neighbor Address: %s (%d/%d)", tvb_ip_to_str(tvb, offset), lq, nlq);
227
228       address_tree = proto_item_add_subtree(address_group, ett_olsr_message_neigh);
229
230       proto_tree_add_item(address_tree, hf_olsr_neighbor_addr, tvb, offset, 4, FALSE);
231       offset += 4;
232     } else if (pinfo->src.type == AT_IPv6) {
233       if (message_end - offset < 20) {
234         proto_tree_add_bytes_format(olsr_tree, hf_olsr_neighbor, tvb, offset, message_end - offset,
235             NULL, "Not enough bytes for last entry (need 20 bytes)");
236         return message_end;
237       }
238       lq = tvb_get_guint8(tvb, offset + 16);
239       nlq = tvb_get_guint8(tvb, offset + 17);
240
241       address_group = proto_tree_add_bytes_format(olsr_tree, hf_olsr_neighbor, tvb, offset, 20,
242           NULL, "Neighbor Address: %s (%d/%d)", tvb_ip6_to_str(tvb, offset), lq, nlq);
243
244       address_tree = proto_item_add_subtree(address_group, ett_olsr_message_neigh);
245
246       proto_tree_add_item(address_tree, hf_olsr_neighbor6_addr, tvb, offset, 16, FALSE);
247       offset += 16;
248     } else {
249       break; /* unknown address type should be handled in dissect_olsr, just be sure */
250     }
251
252     proto_tree_add_item(address_tree, hf_olsrorg_lq, tvb, offset++, 1, FALSE);
253     proto_tree_add_item(address_tree, hf_olsrorg_nlq, tvb, offset++, 1, FALSE);
254     offset += 2;
255   }
256   return message_end;
257 }
258
259 static int dissect_nrlolsr_tc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *olsr_tree, int offset, int message_end) {
260   int field1Ptr, field2Ptr, saneEnd;
261   if (message_end - offset < 4) {
262     proto_tree_add_bytes_format(olsr_tree, hf_olsr_ansn, tvb, offset, message_end - offset,
263         NULL, "Not enough bytes for NRLOLSR LQ-TC");
264     return message_end;
265   }
266
267   proto_tree_add_item(olsr_tree, hf_olsr_ansn, tvb, offset, 2, FALSE);
268   offset += 4;
269
270   field1Ptr = offset + (message_end - offset) / (pinfo->src.len + 2) * (pinfo->src.len);
271   field2Ptr = offset + (message_end - offset) / (pinfo->src.len + 2) * (pinfo->src.len + 1);
272
273   saneEnd = message_end - ((message_end - offset) % (pinfo->src.len + 2));
274   while (field2Ptr < saneEnd) {
275     if (pinfo->src.type == AT_IPv4) {
276       proto_tree_add_item(olsr_tree, hf_olsr_neighbor_addr, tvb, offset, 4, FALSE);
277       offset += 4;
278     } else if (pinfo->src.type == AT_IPv6) {
279       proto_tree_add_item(olsr_tree, hf_olsr_neighbor6_addr, tvb, offset, 16, FALSE);
280       offset += 16;
281     } else {
282       break; /* unknown address type should be handled in dissect_olsr, just be sure */
283     }
284
285     proto_tree_add_item(olsr_tree, hf_nrlolsr_f1, tvb, field1Ptr++, 1, FALSE);
286     proto_tree_add_item(olsr_tree, hf_nrlolsr_f2, tvb, field2Ptr++, 1, FALSE);
287   }
288   return message_end;
289 }
290
291 /*------------------------- Hello Dissecting Code-------------------------*/
292 static int dissect_olsr_hello(tvbuff_t *tvb, packet_info *pinfo, proto_tree *olsr_tree, int offset, int message_end,
293     int(*handleNeighbors)(tvbuff_t *, packet_info *, proto_tree *, int, int)) {
294   double hTime;
295   proto_item *ti;
296   proto_tree *link_type_tree;
297
298   guint16 message_size = 0;
299
300   if (message_end - offset < 4) {
301     proto_tree_add_bytes_format(olsr_tree, hf_olsr_htime, tvb, offset, message_end - offset,
302         NULL, "Not enough bytes for Hello");
303     return message_end;
304   }
305
306   offset += 2;
307
308   /*---------------------Dissect Hello Emission Invertal-------------------*/
309   hTime = getOlsrTime(tvb_get_guint8(tvb, offset));
310   proto_tree_add_double_format(olsr_tree, hf_olsr_htime, tvb, offset, 1, hTime,
311       "Hello Emission Interval: %.3f (in seconds)", hTime);
312   offset++;
313
314   /*-------------------------Dissect Willingness---------------------------*/
315   proto_tree_add_item(olsr_tree, hf_olsr_willingness, tvb, offset++, 1, FALSE);
316
317   while (offset < message_end) {
318     if (message_end - offset < 4) {
319       proto_tree_add_bytes_format(olsr_tree, hf_olsr_link_type, tvb, offset, message_end - offset,
320           NULL, "Not enough bytes for last Hello entry");
321       return message_end;
322     }
323
324     /*------------------------------Dissect Link Type---------------------------------- */
325     ti = proto_tree_add_item(olsr_tree, hf_olsr_link_type, tvb, offset++, 1, FALSE);
326     link_type_tree = proto_item_add_subtree(ti, ett_olsr_message_linktype);
327
328     /* reserved byte */
329     offset++;
330
331     /*----------------------Dissect Link Message Size--------------------------*/
332     message_size = tvb_get_ntohs(tvb, offset);
333     ti = proto_tree_add_item(link_type_tree, hf_olsr_link_message_size, tvb, offset, 2, FALSE);
334     offset += 2;
335
336     if (message_size < 4) {
337       proto_item_append_string(ti, "(too short, must be >= 4)");
338       return message_end;
339     }
340     offset = handleNeighbors(tvb, pinfo, link_type_tree, offset, offset + message_size - 4);
341   }
342   return message_end;
343 }
344
345 static int handle_olsr_hello_rfc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *olsr_tree, int offset,
346     int link_message_end) {
347   /*-------------------Dissect Neighbor Addresses--------------------*/
348   while (offset < link_message_end) {
349     if (link_message_end - offset < pinfo->src.len) {
350       proto_tree_add_bytes_format(olsr_tree, hf_olsr_neighbor, tvb, offset, link_message_end - offset,
351           NULL, "Not enough bytes for last Hello entry");
352       return link_message_end;
353     }
354     if (pinfo->src.type == AT_IPv4) {
355       proto_tree_add_item(olsr_tree, hf_olsr_neighbor_addr, tvb, offset, 4, FALSE);
356       offset += 4;
357     } else if (pinfo->src.type == AT_IPv6) {
358       proto_tree_add_item(olsr_tree, hf_olsr_neighbor6_addr, tvb, offset, 16, FALSE);
359       offset += 16;
360     } else {
361       break; /* unknown address type should be handled in dissect_olsr, just be sure */
362     }
363   } /* end while */
364   return link_message_end;
365 }
366
367 static int handle_olsr_hello_olsrorg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *olsr_tree, int offset,
368     int link_message_end) {
369   /*-------------------Dissect Neighbor Addresses--------------------*/
370
371   while (offset < link_message_end) {
372     proto_item *address_group;
373     proto_tree *address_tree;
374     guint8 lq, nlq;
375
376     if (link_message_end - offset < pinfo->src.len + 4) {
377       proto_tree_add_bytes_format(olsr_tree, hf_olsr_neighbor, tvb, offset, link_message_end - offset,
378           NULL, "Not enough bytes for last Olsr.org LQ-Hello entry");
379       return link_message_end;
380     }
381
382     if (pinfo->src.type == AT_IPv4) {
383       lq = tvb_get_guint8(tvb, offset + 4);
384       nlq = tvb_get_guint8(tvb, offset + 5);
385
386       address_group = proto_tree_add_bytes_format(olsr_tree, hf_olsr_neighbor, tvb, offset, 8,
387            NULL, "Neighbor Address: %s (%d/%d)", tvb_ip_to_str(tvb, offset), lq, nlq);
388
389       address_tree = proto_item_add_subtree(address_group, ett_olsr_message_neigh);
390
391       proto_tree_add_item(address_tree, hf_olsr_neighbor_addr, tvb, offset, 4, FALSE);
392       offset += 4;
393     } else if (pinfo->src.type == AT_IPv6) {
394       lq = tvb_get_guint8(tvb, offset + 16);
395       nlq = tvb_get_guint8(tvb, offset + 17);
396
397       address_group = proto_tree_add_bytes_format(olsr_tree, hf_olsr_neighbor, tvb, offset, 20,
398           NULL, "Neighbor Address: %s (%d/%d)", tvb_ip6_to_str(tvb, offset), lq, nlq);
399
400       address_tree = proto_item_add_subtree(address_group, ett_olsr_message_neigh);
401
402       proto_tree_add_item(address_tree, hf_olsr_neighbor6_addr, tvb, offset, 16, FALSE);
403       offset += 16;
404     } else {
405       break; /* unknown address type should be handled in dissect_olsr, just be sure */
406     }
407
408     proto_tree_add_item(address_tree, hf_olsrorg_lq, tvb, offset++, 1, FALSE);
409     proto_tree_add_item(address_tree, hf_olsrorg_nlq, tvb, offset++, 1, FALSE);
410     offset += 2;
411   } /* end while */
412   return link_message_end;
413 }
414
415 /*------------------------- MID Dissecting Code-------------------------*/
416 static int dissect_olsr_mid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *olsr_tree, int offset, int message_end) {
417   while (offset < message_end) {
418     if (message_end - offset < pinfo->src.len) {
419       proto_tree_add_bytes_format(olsr_tree, hf_olsr_interface_addr, tvb, offset, message_end - offset,
420           NULL, "Not enough bytes for last MID entry");
421       return message_end;
422     }
423     if (pinfo->src.type == AT_IPv4) {
424       proto_tree_add_item(olsr_tree, hf_olsr_interface_addr, tvb, offset, 4, FALSE);
425       offset += 4;
426     } else if (pinfo->src.type == AT_IPv6) {
427       proto_tree_add_item(olsr_tree, hf_olsr_interface6_addr, tvb, offset, 16, FALSE);
428       offset += 16;
429     } else {
430       break; /* unknown address type should be handled in dissect_olsr, just be sure */
431     }
432   } /* end while for MID */
433   return message_end;
434 }
435
436 /*------------------------- HNA Dissecting Code-------------------------*/
437 static int dissect_olsr_hna(tvbuff_t *tvb, packet_info *pinfo, proto_tree *olsr_tree, int offset, int message_end) {
438   while (offset < message_end) {
439     if (message_end - offset < pinfo->src.len * 2) {
440       proto_tree_add_bytes_format(olsr_tree, hf_olsr_network_addr, tvb, offset, message_end - offset,
441           NULL, "Not enough bytes for last HNA entry");
442       return message_end;
443     }
444
445     if (pinfo->src.type == AT_IPv4) {
446       proto_tree_add_item(olsr_tree, hf_olsr_network_addr, tvb, offset, 4, FALSE);
447       offset += 4;
448       proto_tree_add_item(olsr_tree, hf_olsr_netmask, tvb, offset, 4, FALSE);
449       offset += 4;
450     } else if (pinfo->src.type == AT_IPv6) {
451       proto_tree_add_item(olsr_tree, hf_olsr_network6_addr, tvb, offset, 4, FALSE);
452       offset += 16;
453       proto_tree_add_item(olsr_tree, hf_olsr_netmask6, tvb, offset, 4, FALSE);
454       offset += 16;
455     } else {
456       break; /* unknown address type should be handled in dissect_olsr, just be sure */
457     }
458   } /* end while for HNA */
459   return message_end;
460 }
461
462 /*------------------------- MID Dissecting Code-------------------------*/
463 static int dissect_olsrorg_nameservice(tvbuff_t *tvb, packet_info *pinfo, proto_tree *olsr_tree, int offset,
464     int message_end) {
465   guint16 version, count;
466
467   proto_item *olsr_ns_item;
468   proto_tree *olsr_ns_tree;
469
470   if (message_end - offset < 4) {
471     proto_tree_add_bytes_format(olsr_tree, hf_olsrorg_ns_version, tvb, offset, message_end - offset,
472         NULL, "Not enough bytes for Olsr.org Nameservice message");
473     return message_end;
474   }
475
476   version = tvb_get_ntohs(tvb, offset);
477   proto_tree_add_item(olsr_tree, hf_olsrorg_ns_version, tvb, offset, 2, FALSE);
478
479   count = tvb_get_ntohs(tvb, offset + 2);
480   proto_tree_add_item(olsr_tree, hf_olsrorg_ns_count, tvb, offset + 2, 2, FALSE);
481
482   offset += 4;
483
484   if (version != 1) {
485     proto_tree_add_bytes_format(olsr_tree, hf_olsr_data, tvb, offset, message_end - offset,
486         NULL, "Unkown nameservice protocol version %d", version);
487     return message_end;
488   }
489
490   while (offset < message_end && count-- > 0) {
491     guint16 type, length;
492     int total_length;
493
494     if (message_end - offset < 20) {
495       proto_tree_add_bytes_format(olsr_tree, hf_olsrorg_ns, tvb, offset, message_end - offset,
496           NULL, "Not enough bytes for last nameservice entry");
497       return message_end;
498     }
499
500     type = tvb_get_ntohs(tvb, offset);
501     length = tvb_get_ntohs(tvb, offset + 2);
502
503     total_length = 4 + 16 + ((length - 1) | 3) + 1;
504
505     olsr_ns_item = proto_tree_add_bytes_format(olsr_tree, hf_olsrorg_ns, tvb, offset, total_length,
506         NULL, "Nameservice: %s (%d)", val_to_str(type, nameservice_type_vals, "UNKNOWN"), type);
507
508     olsr_ns_tree = proto_item_add_subtree(olsr_ns_item, ett_olsr_message_ns);
509
510     proto_tree_add_item(olsr_ns_tree, hf_olsrorg_ns_type, tvb, offset, 2, FALSE);
511     proto_tree_add_uint(olsr_ns_tree, hf_olsrorg_ns_length, tvb, offset + 2, 2, length);
512
513     if (pinfo->src.type == AT_IPv4) {
514       proto_tree_add_item(olsr_ns_tree, hf_olsrorg_ns_ip, tvb, offset + 4, 4, FALSE);
515     } else if (pinfo->src.type == AT_IPv6) {
516       proto_tree_add_item(olsr_ns_tree, hf_olsrorg_ns_ip6, tvb, offset + 4, 16, FALSE);
517     } else {
518       break; /* unknown address type should be handled in dissect_olsr, just be sure */
519     }
520
521     if (message_end - offset < total_length) {
522       proto_tree_add_bytes_format(olsr_tree, hf_olsrorg_ns, tvb, offset, message_end - offset,
523           NULL, "Not enough bytes for content of last nameservice entry");
524       return message_end;
525     }
526     proto_tree_add_item(olsr_ns_tree, hf_olsrorg_ns_content, tvb, offset + 20, length, FALSE);
527     offset += 4 + 16 + ((length - 1) | 3) + 1;
528   }
529   return message_end;
530 }
531
532 /*------------------------- Packet Dissecting Code-------------------------*/
533 static int dissect_olsr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
534   proto_item *ti;
535   proto_tree *olsr_tree;
536
537   int offset, message_len, message_end;
538   guint message_type;
539   double vTime;
540
541   guint16 packet_len;
542
543   /* Does this packet have a valid message type at the beginning? */
544   if (tvb_length(tvb) < 4) {
545     if (check_col(pinfo->cinfo, COL_INFO)) {
546       col_add_fstr(pinfo->cinfo, COL_INFO, "OLSR Packet,  Length: %u Bytes (not enough data in packet)",
547           tvb_length(tvb));
548     }
549     return 0; /* not enough bytes for the packet length */
550   }
551   packet_len = tvb_get_ntohs(tvb, 0);
552   if (packet_len > tvb_length(tvb)) {
553     if (check_col(pinfo->cinfo, COL_INFO)) {
554       col_add_fstr(pinfo->cinfo, COL_INFO, "OLSR Packet,  Length: %u Bytes (not enough data in packet)", packet_len);
555     }
556     return 0;
557   }
558   /*-------------Setting the Protocol and Info Columns in the Wireshark Display----------*/
559   col_set_str(pinfo->cinfo, COL_PROTOCOL, "OLSR v1");
560   col_clear(pinfo->cinfo, COL_INFO);
561
562   if ((pinfo->src.type != AT_IPv4) && (pinfo->src.type != AT_IPv6)) {
563     if (check_col(pinfo->cinfo, COL_INFO)) {
564       col_add_fstr(pinfo->cinfo, COL_INFO, "OLSR (unknown address type) Packet,  Length: %u Bytes", packet_len);
565     }
566     return 0;
567   }
568   if (check_col(pinfo->cinfo, COL_INFO) && (pinfo->src.type == AT_IPv4)) {
569     col_add_fstr(pinfo->cinfo, COL_INFO, "OLSR (IPv4) Packet,  Length: %u Bytes", packet_len);
570   } else if (check_col(pinfo->cinfo, COL_INFO) && (pinfo->src.type == AT_IPv6)) {
571     col_add_fstr(pinfo->cinfo, COL_INFO, "OLSR (IPv6) Packet,  Length: %u Bytes", packet_len);
572   }
573
574   /*-----------------Fetching Info from IP Packet and Adding to Tree------------------------*/
575   if (tree) {
576     ti = proto_tree_add_item(tree, proto_olsr, tvb, 0, -1, FALSE);
577     olsr_tree = proto_item_add_subtree(ti, ett_olsr);
578
579     proto_tree_add_item(olsr_tree, hf_olsr_packet_len, tvb, 0, 2, FALSE);
580     proto_tree_add_item(olsr_tree, hf_olsr_packet_seq_num, tvb, 2, 2, FALSE);
581
582     offset = 4;
583
584     while (offset < packet_len) {
585       proto_item *message_item;
586       proto_tree *message_tree;
587
588       if (packet_len - offset < 4) {
589         proto_tree_add_bytes_format(olsr_tree, hf_olsr_message, tvb, offset, packet_len - offset,
590             NULL, "Message too short !");
591         break;
592       }
593
594       message_type = tvb_get_guint8(tvb, offset);
595       vTime = getOlsrTime(tvb_get_guint8(tvb, offset + 1));
596       message_len = tvb_get_ntohs(tvb, offset + 2);
597
598       message_item = proto_tree_add_bytes_format(olsr_tree, hf_olsr_message, tvb, offset, message_len,
599           NULL, "Message: %s (%d)", val_to_str(message_type, message_type_vals, "UNKNOWN"),
600           message_type);
601       message_tree = proto_item_add_subtree(message_item, ett_olsr_message[message_type]);
602
603       proto_tree_add_uint(message_tree, hf_olsr_message_type, tvb, offset, 1, message_type);
604       offset++;
605
606       /*-------------Dissect Validity Time-------------------------*/
607       proto_tree_add_double_format(message_tree, hf_olsr_vtime, tvb, offset, 1, vTime,
608           "Validity Time: %.3f (in seconds)", vTime);
609       offset++;
610
611       /*-------------Dissect Message Size---------------------------*/
612       ti = proto_tree_add_item(message_tree, hf_olsr_message_size, tvb, offset, 2, FALSE);
613       offset += 2;
614
615       if (message_len < 8 + pinfo->src.len) {
616         proto_item_append_text(ti, "(too short, must be >= %d)", 8 + pinfo->src.len);
617         break;
618       }
619
620       message_end = offset + message_len - 4;
621       if (message_end > packet_len) {
622         proto_item_append_string(ti, "(not enough data for message)");
623         break;
624       }
625
626       /*-----------------Dissecting: Origin Addr, TTL, Hop Count, and Message Seq Number*/
627       if (pinfo->src.type == AT_IPv4) {
628         proto_tree_add_item(message_tree, hf_olsr_origin_addr, tvb, offset, 4, FALSE);
629         offset += 4;
630       } else if (pinfo->src.type == AT_IPv6) {
631         proto_tree_add_item(message_tree, hf_olsr_origin6_addr, tvb, offset, 16, FALSE);
632         offset += 16;
633       } else {
634         break; /* unknown address type should be handled before this loop, just be sure */
635       }
636
637       proto_tree_add_item(message_tree, hf_olsr_ttl, tvb, offset, 1, FALSE);
638       proto_tree_add_item(message_tree, hf_olsr_hop_count, tvb, offset + 1, 1, FALSE);
639       proto_tree_add_item(message_tree, hf_olsr_message_seq_num, tvb, offset + 2, 2, FALSE);
640       offset += 4;
641
642       if (offset < message_end) {
643         /* --------------Dissecting TC message--------------------- */
644         if (message_type == TC) {
645           dissect_olsr_tc(tvb, pinfo, message_tree, offset, message_end);
646         }
647         /* -------------Dissect HELLO message----------------------- */
648         else if (message_type == HELLO) {
649           dissect_olsr_hello(tvb, pinfo, message_tree, offset, message_end, &handle_olsr_hello_rfc);
650         }
651         /*---------------------------------Dissect MID Message----------------------------------*/
652         else if (message_type == MID) {
653           dissect_olsr_mid(tvb, pinfo, message_tree, offset, message_end);
654         }
655         /*-----------------------------Dissect HNA Message--------------------------------*/
656         else if (message_type == HNA) {
657           dissect_olsr_hna(tvb, pinfo, message_tree, offset, message_end);
658         }
659         /*-----------------------------Dissect Olsr.org Hello Message--------------------------------*/
660         else if (global_olsr_olsrorg && message_type == OLSR_ORG_LQ_HELLO) {
661           dissect_olsr_hello(tvb, pinfo, message_tree, offset, message_end, &handle_olsr_hello_olsrorg);
662         }
663         /*-----------------------------Dissect Olsr.org TC Message--------------------------------*/
664         else if (global_olsr_olsrorg && message_type == OLSR_ORG_LQ_TC) {
665           dissect_olsrorg_lq_tc(tvb, pinfo, message_tree, offset, message_end);
666         }
667
668         /*-----------------------------Dissect Olsr.org NS Message--------------------------------*/
669         else if (global_olsr_olsrorg && message_type == OLSR_ORG_NAMESERVICE) {
670           dissect_olsrorg_nameservice(tvb, pinfo, message_tree, offset, message_end);
671         }
672         /*-----------------------Dissect NRL OLSR TC Message-------------------------------------*/
673         else if (global_olsr_nrlolsr && message_type == NRLOLSR_TC_EXTRA) {
674           dissect_nrlolsr_tc(tvb, pinfo, message_tree, offset, message_end);
675         }
676
677         /*-----------------------------Undefined message types-----------------------------*/
678         else {
679           if ((message_len - 12) % 4) {
680             proto_tree_add_bytes_format(message_tree, hf_olsr_data, tvb, offset, message_len - 12,
681                 NULL, "Data (%u bytes) (must be aligned on 32 bits)", message_len - 12);
682             break;
683           }
684           proto_tree_add_bytes_format(message_tree, hf_olsr_data, tvb, offset, message_len - 12,
685               NULL, "Data (%u bytes)", message_len - 12);
686           offset += message_len - 12;
687         } /* end if for undefined message types */
688       }
689       offset = message_end;
690     } /* end while for message alive */
691   }
692
693   return tvb_length(tvb);
694 } /* end Dissecting */
695
696 /*-----------Register the Dissector for OLSR--------------*/
697 void proto_register_olsr(void) {
698   static hf_register_info hf[] = {
699     { &hf_olsr_packet_len,
700       { "Packet Length", "olsr.packet_len",
701         FT_UINT16, BASE_DEC, NULL, 0,
702         "Packet Length in Bytes", HFILL
703       }
704     },
705
706     { &hf_olsr_packet_seq_num,
707       { "Packet Sequence Number", "olsr.packet_seq_num",
708         FT_UINT16, BASE_DEC, NULL, 0,
709         NULL, HFILL
710       }
711     },
712
713     { &hf_olsr_message,
714       { "Message", "olsr.message",
715         FT_BYTES, BASE_NONE, NULL, 0,
716         NULL, HFILL
717       }
718     },
719
720     { &hf_olsr_message_type,
721       { "Message Type", "olsr.message_type",
722         FT_UINT8, BASE_DEC, VALS(message_type_vals), 0,
723         NULL, HFILL
724       }
725     },
726
727     { &hf_olsr_message_size,
728       { "Message", "olsr.message_size",
729         FT_UINT16, BASE_DEC, NULL, 0,
730         "Message Size in Bytes", HFILL
731       }
732     },
733
734     { &hf_olsr_message_seq_num,
735       { "Message Sequence Number", "olsr.message_seq_num",
736         FT_UINT16, BASE_DEC, NULL, 0,
737         NULL, HFILL
738       }
739     },
740
741     { &hf_olsr_vtime,
742       { "Validity Time", "olsr.vtime",
743         FT_DOUBLE, BASE_NONE, NULL, 0,
744         "Validity Time in seconds", HFILL
745       }
746     },
747
748     { &hf_olsr_ansn,
749       { "Advertised Neighbor Sequence Number (ANSN)", "olsr.ansn",
750         FT_UINT16, BASE_DEC, NULL, 0,
751         NULL, HFILL
752       }
753     },
754
755     { &hf_olsr_htime,
756       { "Hello emission interval", "olsr.htime",
757         FT_DOUBLE, BASE_NONE, NULL, 0,
758         "Hello emission interval in seconds", HFILL
759       }
760     },
761
762     { &hf_olsr_willingness,
763       { "Willingness to forward messages", "olsr.willingness",
764         FT_UINT8, BASE_DEC, VALS(willingness_type_vals), 0,
765         NULL, HFILL
766       }
767     },
768
769     { &hf_olsr_ttl,
770       { "TTL", "olsr.ttl",
771         FT_UINT8, BASE_DEC, NULL, 0,
772         "Time to Live in hops", HFILL
773       }
774     },
775
776     { &hf_olsr_link_type,
777       { "Link Type", "olsr.link_type",
778         FT_UINT8, BASE_DEC, VALS(link_type_vals), 0,
779         NULL, HFILL
780       }
781     },
782
783     { &hf_olsr_link_message_size,
784       { "Link Message Size", "olsr.link_message_size",
785         FT_UINT16, BASE_DEC, NULL, 0,
786         "Link Message Size in bytes", HFILL
787       }
788     },
789
790     { &hf_olsr_hop_count,
791       { "Hop Count", "olsr.hop_count",
792         FT_UINT8, BASE_DEC, NULL, 0,
793         NULL, HFILL
794       }
795     },
796
797     { &hf_olsr_neighbor,
798       { "Neighbor Address", "olsr.neighbor",
799         FT_BYTES, BASE_NONE, NULL, 0,
800         NULL, HFILL
801       }
802     },
803
804     { &hf_olsr_origin_addr,
805       { "Originator Address", "olsr.origin_addr",
806         FT_IPv4, BASE_NONE, NULL, 0,
807         NULL, HFILL
808       }
809     },
810
811     { &hf_olsr_neighbor_addr,
812       { "Neighbor Address", "olsr.neighbor_addr",
813         FT_IPv4, BASE_NONE, NULL, 0,
814         NULL, HFILL
815       }
816     },
817
818     { &hf_olsr_network_addr,
819       { "Network Address", "olsr.network_addr",
820         FT_IPv4, BASE_NONE, NULL, 0,
821         NULL, HFILL
822       }
823     },
824
825     { &hf_olsr_interface_addr,
826       { "Interface Address", "olsr.interface_addr",
827         FT_IPv4, BASE_NONE, NULL, 0,
828         NULL, HFILL
829       }
830     },
831
832     { &hf_olsr_netmask,
833       { "Netmask", "olsr.netmask",
834         FT_IPv4, BASE_NONE, NULL, 0,
835         NULL, HFILL
836       }
837     },
838
839     { &hf_olsr_neighbor6,
840       { "Neighbor Address", "olsr.neighbor6",
841         FT_BYTES, BASE_NONE, NULL, 0,
842         NULL, HFILL
843       }
844     },
845
846     { &hf_olsr_origin6_addr,
847       { "Originator Address", "olsr.origin6_addr",
848         FT_IPv6, BASE_NONE, NULL, 0,
849         NULL, HFILL
850       }
851     },
852
853     { &hf_olsr_neighbor6_addr,
854       { "Neighbor Address", "olsr.neighbor6_addr",
855         FT_IPv6, BASE_NONE, NULL, 0,
856         NULL, HFILL
857       }
858     },
859
860     { &hf_olsr_network6_addr,
861       { "Network Address", "olsr.network6_addr",
862         FT_IPv6, BASE_NONE, NULL, 0,
863         NULL, HFILL
864       }
865     },
866
867     { &hf_olsr_interface6_addr,
868       { "Interface Address", "olsr.interface6_addr",
869         FT_IPv6, BASE_NONE, NULL, 0,
870         NULL, HFILL
871       }
872     },
873
874     { &hf_olsr_netmask6,
875       { "Netmask", "olsr.netmask6",
876         FT_IPv6, BASE_NONE, NULL, 0,
877         NULL, HFILL
878       }
879     },
880
881     { &hf_olsr_data,
882       { "Data", "olsr.data",
883         FT_BYTES, BASE_NONE, NULL, 0,
884         NULL, HFILL
885       }
886     },
887
888     { &hf_olsrorg_lq,
889       { "LQ", "olsr.lq",
890         FT_UINT8, BASE_DEC, NULL, 0,
891         "Link quality", HFILL
892       }
893     },
894     { &hf_olsrorg_nlq,
895       { "NLQ", "olsr.nlq",
896         FT_UINT8, BASE_DEC, NULL, 0,
897         "Neighbor link quality", HFILL
898       }
899     },
900
901     { &hf_olsrorg_ns,
902       { "Nameservice message", "olsr.ns",
903         FT_BYTES, BASE_NONE, NULL, 0,
904         NULL, HFILL
905       }
906     },
907     { &hf_olsrorg_ns_version,
908       { "Version", "olsr.ns.version",
909         FT_UINT16, BASE_DEC, NULL, 0,
910         NULL, HFILL
911       }
912     },
913     { &hf_olsrorg_ns_count,
914       { "Count", "olsr.nlq",
915         FT_UINT16, BASE_DEC, NULL, 0,
916         "Number of nameservice messages", HFILL
917       }
918     },
919     { &hf_olsrorg_ns_type,
920       { "Message Type", "olsr.ns.type",
921         FT_UINT16, BASE_DEC, VALS(nameservice_type_vals), 0,
922         NULL, HFILL
923       }
924     },
925     { &hf_olsrorg_ns_length,
926       { "Length", "olsr.ns.length",
927         FT_UINT16, BASE_DEC, NULL, 0,
928         NULL, HFILL
929       }
930     },
931     { &hf_olsrorg_ns_ip,
932       { "Address", "olsr.ns.ip",
933         FT_IPv4, BASE_NONE, NULL, 0,
934         NULL, HFILL
935       }
936     },
937     { &hf_olsrorg_ns_ip6,
938       { "Address", "olsr.ns.ip6",
939         FT_IPv6, BASE_NONE, NULL, 0,
940         NULL, HFILL
941       }
942     },
943     { &hf_olsrorg_ns_content,
944       { "Content", "olsr.ns.content",
945         FT_STRING, BASE_NONE, NULL, 0,
946         NULL, HFILL
947       }
948     },
949
950     { &hf_nrlolsr_f1,
951       { "NRL MINMAX", "olsr.nrl.minmax",
952         FT_UINT8, BASE_DEC, NULL, 0,
953         NULL, HFILL
954       }
955     },
956     { &hf_nrlolsr_f2,
957       { "NRL SPF", "olsr.nrl.spf",
958         FT_UINT8, BASE_DEC, NULL, 0,
959         NULL, HFILL
960       }
961     }
962   };
963
964   static gint *ett_base[] = {
965     &ett_olsr,
966     &ett_olsr_message_linktype,
967     &ett_olsr_message_neigh,
968     &ett_olsr_message_neigh6,
969     &ett_olsr_message_ns
970   };
971
972   gint *ett[array_length(ett_base) + (G_MAXUINT8+1)];
973
974   module_t *olsr_module;
975   int i,j;
976
977   memcpy(ett, ett_base, sizeof(ett_base));
978   j = array_length(ett_base);
979   for (i=0; i<G_MAXUINT8+1; i++) {
980     ett_olsr_message[i] = -1;
981     ett[j++] = &ett_olsr_message[i];
982   }
983
984   proto_olsr = proto_register_protocol("Optimized Link State Routing Protocol", "OLSR", "olsr");
985
986   proto_register_field_array(proto_olsr, hf, array_length(hf));
987   proto_register_subtree_array(ett, array_length(ett));
988
989   olsr_module = prefs_register_protocol(proto_olsr, NULL);
990   prefs_register_bool_preference(olsr_module, "ff_olsrorg",
991                                  "Dissect olsr.org messages","Dissect custom olsr.org message types (compatible with rfc routing agents)",
992                                  &global_olsr_olsrorg);
993   prefs_register_bool_preference(olsr_module, "nrlolsr",
994                                  "Dissect NRL-Olsr TC messages", "Dissect custom nrlolsr tc message (incompatible with rfc routing agents)",
995                                  &global_olsr_nrlolsr);
996 }
997
998 void proto_reg_handoff_olsr(void) {
999   dissector_handle_t olsr_handle;
1000
1001   olsr_handle = new_create_dissector_handle(dissect_olsr, proto_olsr);
1002   dissector_add_uint("udp.port", UDP_PORT_OLSR, olsr_handle);
1003 }