From Graeme Hewson:
[obnox/wireshark/wip.git] / 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  * http://www.ietf.org/rfc/rfc3626.txt
10  *
11  * $Id: packet-olsr.c,v 1.4 2004/01/18 16:48:24 gerald Exp $
12  *
13  * Ethereal - Network traffic analyzer
14  * By Gerald Combs <gerald@ethereal.com>
15  * Copyright 1998 Gerald Combs
16  * 
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License
19  * as published by the Free Software Foundation; either version 2
20  * of the License, or (at your option) any later version.
21  * 
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  * 
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30  */
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <stdio.h>
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/ipv6-utils.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 /* Initialize the protocol and registered fields */
60 static int proto_olsr = -1;
61 static int hf_olsr_packet_len = -1;
62 static int hf_olsr_packet_seq_num = -1;
63 static int hf_olsr_message_type = -1;
64 static int hf_olsr_vtime = -1;
65 static int hf_olsr_message_size = -1;
66 static int hf_olsr_ttl = -1;
67 static int hf_olsr_hop_count = -1;
68 static int hf_olsr_message_seq_num = -1;
69
70 static int hf_olsr_htime = -1;
71 static int hf_olsr_willingness = -1;
72
73 static int hf_olsr_link_type = -1;
74 static int hf_olsr_link_message_size = -1;
75 static int hf_olsr_ansn = -1;
76
77 static int hf_olsr_origin_addr = -1;
78 static int hf_olsr_neighbor_addr = -1;
79 static int hf_olsr_interface_addr = -1;
80 static int hf_olsr_netmask      = -1;
81 static int hf_olsr_network_addr = -1;
82 static int hf_olsr_origin6_addr = -1;
83 static int hf_olsr_neighbor6_addr = -1;
84 static int hf_olsr_interface6_addr = -1;
85 static int hf_olsr_netmask6 = -1;
86 static int hf_olsr_network6_addr = -1;
87
88 /* Initialize the subtree pointers*/
89 static gint ett_olsr = -1;
90
91 static const value_string message_type_vals[] = {
92         { HELLO, "HELLO" },
93         { TC,    "TC" },
94         { MID,   "MID" },
95         { HNA,   "HNA" },
96         { 0,     NULL }
97 };
98
99 /*------------------------- Packet Dissecting Code-------------------------*/
100 static int
101 dissect_olsr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
102 {
103         proto_item *ti;
104         proto_tree *olsr_tree;
105         
106         int offset, link_message_size, message_size, message_type, packet_size, position;
107         int high_bits, low_bits, vtime, htime;
108         double Vtime, Htime;
109         
110         guint16 packet_len;
111         
112         guint32 origin_addr;
113         guint32 neighbor_addr;
114         guint32 interface_addr;
115         guint32 network_addr;
116         guint32 netmask;
117         struct e_in6_addr origin6_addr, *origin=&origin6_addr;
118         struct e_in6_addr neighbor6_addr, *neighbor=&neighbor6_addr;
119         struct e_in6_addr interface6_addr, *theinterface=&interface6_addr;
120         struct e_in6_addr network6_addr, *network=&network6_addr;
121         struct e_in6_addr netmask6, *netmask_v6=&netmask6;
122         
123
124         /* Does this packet have a valid message type at the beginning? */
125         if (!tvb_bytes_exist(tvb, 0, 2))
126                 return 0;       /* not enough bytes for the packet length */
127         packet_len = tvb_get_ntohs(tvb, 0);
128         if (packet_len < 4)
129                 return 0;       /* length not enough for a packet header */
130         if (packet_len > 4) {
131                 /*
132                  * The packet claims to have more than just a packet
133                  * header.
134                  */
135                 if (packet_len < 8) {
136                         /*
137                          * ...but it doesn't claim to have enough for
138                          * a full message header.
139                          */
140                         return 0;
141                 }
142
143                 /*
144                  * OK, let's look at the type of the first message and
145                  * at its size field.
146                  */
147                 if (!tvb_bytes_exist(tvb, 4, 4))
148                         return 0;       /* not enough bytes for them */
149                 message_type = tvb_get_guint8(tvb, 4);
150                 if (match_strval(message_type, message_type_vals) == NULL)
151                         return 0;       /* not valid */
152                 /* OK, what about the message length? */
153                 message_size = tvb_get_ntohs(tvb, 4+2);
154                 if (message_size < 4)
155                         return 0;       /* length not enough for a message header */
156         }
157
158         /*-------------Setting the Protocol and Info Columns in the Ethereal Display----------*/
159         if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
160                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "UDP");
161         if (check_col(pinfo->cinfo, COL_INFO)) 
162                 col_clear(pinfo->cinfo, COL_INFO);
163
164         if (check_col(pinfo->cinfo, COL_INFO) && (pinfo->src.type==AT_IPv4))
165                 col_add_fstr(pinfo->cinfo, COL_INFO, "OLSR (IPv4) Packet,  Length: %u Bytes", packet_len);
166         else if(check_col(pinfo->cinfo, COL_INFO) && (pinfo->src.type==AT_IPv6))
167                 col_add_fstr(pinfo->cinfo, COL_INFO, "OLSR (IPv6) Packet,  Length: %u Bytes", packet_len);
168
169 /*-----------------------------------------------------Fetching Info from IPv4 Packet and Adding to Tree-------------------------------------------*/
170         if (tree && (pinfo->src.type==AT_IPv4)) {
171                 ti = proto_tree_add_item(tree, proto_olsr, tvb, 0, -1, FALSE);
172                 olsr_tree = proto_item_add_subtree(ti, ett_olsr);
173
174                 proto_tree_add_uint_format(olsr_tree, hf_olsr_packet_len, tvb, 0, 2, packet_len, "Packet Length: %u bytes", packet_len);
175                 proto_tree_add_item(olsr_tree, hf_olsr_packet_seq_num, tvb, 2, 2, FALSE);
176                 
177                 packet_size = (packet_len - 4) / 4;
178                 position = 4;
179
180                 while(packet_size>0)   {
181                         message_type = tvb_get_guint8(tvb, position);
182                         proto_tree_add_uint(olsr_tree, hf_olsr_message_type, tvb, position, 1, message_type);
183                         
184                         /*-------------Dissect Validity Time-------------------------*/
185                         vtime = tvb_get_guint8(tvb, position+1);
186                         high_bits = ((vtime & 0xF0) >> 4);
187                         low_bits = (vtime & 0x0F);
188                         Vtime = ((1<<low_bits)/16.0)*(1+(high_bits/16.0));
189                         proto_tree_add_double_format(olsr_tree, hf_olsr_vtime, tvb, position+1, 1, Vtime, "Validity Time: %.3f (in seconds)", Vtime);
190                         
191                         /*-------------Dissect Message Size---------------------------*/
192                         message_size = tvb_get_ntohs(tvb, position+2);
193                         if (message_size < 4) {
194                                 proto_tree_add_uint_format(olsr_tree, hf_olsr_message_size, tvb, position+2, 2, message_size,"Message Size: %u bytes (too short, must be >= 4)", message_size);
195                                 break;
196                         }
197                         proto_tree_add_uint_format(olsr_tree, hf_olsr_message_size, tvb, position+2, 2, message_size,"Message Size: %u bytes", message_size);
198                         
199                         packet_size--;
200                         message_size = (message_size - 4) /4;
201                         offset = position + 4;
202                         position = offset;
203                         
204                         /*-----------------Dissecting: Origin Addr, TTL, Hop Count, and Message Seq Number*/
205                         if(message_size > 0)    {
206                                 tvb_memcpy(tvb, (guint8*)&origin_addr, offset, 4);
207                                 proto_tree_add_ipv4(olsr_tree, hf_olsr_origin_addr, tvb, offset, 4, origin_addr);
208                                 message_size--;
209                                 packet_size--;
210                                 offset+=4;
211                         }
212                         if(message_size > 0)    {
213                                 proto_tree_add_item(olsr_tree, hf_olsr_ttl, tvb, offset, 1, FALSE);
214                                 proto_tree_add_item(olsr_tree, hf_olsr_hop_count, tvb, offset+1, 1, FALSE);
215                                 proto_tree_add_item(olsr_tree, hf_olsr_message_seq_num, tvb, offset+2, 2, FALSE);
216                                 message_size--;
217                                 packet_size--;
218                                 offset+=4;
219                         }
220                         
221                         position = offset;
222                         
223                         /* --------------Dissecting TC message--------------------- */
224                         if(message_size>0 && message_type == TC)   {
225                                 proto_tree_add_item(olsr_tree, hf_olsr_ansn, tvb, offset, 2, FALSE);
226
227                                 offset+=4;
228                                 message_size--;
229                                 packet_size--;
230
231                                 while(message_size>0)  {
232                                         tvb_memcpy(tvb, (guint8*)&neighbor_addr, offset, 4);
233                                         proto_tree_add_ipv4(olsr_tree, hf_olsr_neighbor_addr, tvb, offset, 4, neighbor_addr);
234                                         message_size--;
235                                         offset+=4;
236                                         packet_size--;
237                                         }
238                                 position = offset;
239                         }
240
241                         /* -------------Dissect HELLO message----------------------- */
242                         else if(message_size>0 && message_type == HELLO)  {
243                                 /*---------------------Dissect Hello Emission Invertal-------------------*/
244                                 htime = tvb_get_guint8(tvb, offset+2);
245                                 high_bits = ((htime & 0xF0) >> 4);
246                                 low_bits = (htime & 0x0F);
247                                 Htime = ((1<<low_bits)/16.0)*(1+(high_bits/16.0));
248                                 proto_tree_add_double_format(olsr_tree, hf_olsr_htime, tvb, offset+2, 1, Htime, "Hello Emission Interval: %.3f (in seconds)", Htime);
249                                 
250                                 /*-------------------------Dissect Willingness---------------------------*/
251                                 switch(tvb_get_guint8(tvb, offset+3))   {
252                                         case 0:
253                                                 proto_tree_add_uint_format(olsr_tree, hf_olsr_willingness, tvb, offset+3, 1, tvb_get_guint8(tvb, offset+2), "Willingness: Never");
254                                                 break;
255                                         case 1:
256                                                 proto_tree_add_uint_format(olsr_tree, hf_olsr_willingness, tvb, offset+3, 1, tvb_get_guint8(tvb, offset+2), "Willingness: Low");
257                                                 break;
258                                         case 3:
259                                                 proto_tree_add_uint_format(olsr_tree, hf_olsr_willingness, tvb, offset+3, 1, tvb_get_guint8(tvb, offset+2), "Willingness: Default");
260                                                 break;
261                                         case 6:
262                                                 proto_tree_add_uint_format(olsr_tree, hf_olsr_willingness, tvb, offset+3, 1, tvb_get_guint8(tvb, offset+2), "Willingness: High");
263                                                 break;
264                                         case 7: 
265                                                 proto_tree_add_uint_format(olsr_tree, hf_olsr_willingness, tvb, offset+3, 1, tvb_get_guint8(tvb, offset+2), "Willingness: Always");
266                                                 break;
267                                         default :
268                                                 proto_tree_add_uint_format(olsr_tree, hf_olsr_willingness, tvb, offset+3, 1, tvb_get_guint8(tvb, offset+2), "Willingness: Invalid!");
269                                                 break;
270                                 }/* end switch Willingness */
271                                 
272                                 offset+=4;
273                                 message_size--;
274                                 packet_size--;
275                                 
276                                 while(message_size>0)   {
277                                         /*------------------------------Dissect Link Type---------------------------------- */
278                                         switch(tvb_get_guint8(tvb, offset))     {
279                                                 case 0:
280                                                         proto_tree_add_uint_format(olsr_tree, hf_olsr_link_type, tvb, offset, 1, tvb_get_guint8(tvb, offset), "Link Type: Unspecified Link");
281                                                         break;
282                                                 case 1:
283                                                         proto_tree_add_uint_format(olsr_tree, hf_olsr_link_type, tvb, offset, 1, tvb_get_guint8(tvb, offset), "Link Type: Asymmetric Link");
284                                                         break;
285                                                 case 6:
286                                                         proto_tree_add_uint_format(olsr_tree, hf_olsr_link_type, tvb, offset, 1, tvb_get_guint8(tvb, offset), "Link Type: Symmetric Link");
287                                                         break;
288                                                 case 3:
289                                                         proto_tree_add_uint_format(olsr_tree, hf_olsr_link_type, tvb, offset, 1, tvb_get_guint8(tvb, offset), "Link Type: Lost Link");
290                                                         break;
291                                                 case 10:
292                                                         proto_tree_add_uint_format(olsr_tree, hf_olsr_link_type, tvb, offset, 1, tvb_get_guint8(tvb, offset), "Link Type: MPR Link");
293                                                         break;
294                                                 case 5:
295                                                         proto_tree_add_uint_format(olsr_tree, hf_olsr_link_type, tvb, offset, 1, tvb_get_guint8(tvb, offset), "Link Type: Pending");
296                                                         break;
297                                                 default:
298                                                         proto_tree_add_uint_format(olsr_tree, hf_olsr_link_type, tvb, offset, 1, tvb_get_guint8(tvb, offset), "Link Type: Invalid");
299                                                         break;
300                                         }/* end switch Link Type */
301
302                                         /*----------------------Dissect Link Message Size--------------------------*/
303                                         proto_tree_add_uint_format(olsr_tree, hf_olsr_link_message_size, tvb, offset+2, 2, tvb_get_ntohs(tvb, offset+2), "Link Message Size: %u bytes", tvb_get_ntohs(tvb, offset+2));
304
305                                         link_message_size = (tvb_get_ntohs(tvb, offset+2) - 4) / 4;
306                                         offset+=4;
307                                         message_size--;
308                                         packet_size--;
309                                                                                         
310                                         /*-------------------Dissect Neighbor Addresses--------------------*/
311                                         while(link_message_size>0)   {
312                                                 tvb_memcpy(tvb, (guint8*)&neighbor_addr, offset, 4);
313                                                 proto_tree_add_ipv4(olsr_tree, hf_olsr_neighbor_addr, tvb, offset, 4, neighbor_addr);
314                                                 offset+=4;
315                                                 message_size--;
316                                                 packet_size--;
317                                                 link_message_size--;
318                                         } /* end while */
319                                 } /* end while */
320                                 position = offset;
321                         } /* end if for Hello */
322                         /*---------------------------------Dissect MID Message----------------------------------*/
323                         else if(message_size>0 && message_type==MID)    {
324                                 while(message_size>0)   {
325                                         tvb_memcpy(tvb, (guint8*)&interface_addr, offset, 4);
326                                         proto_tree_add_ipv4(olsr_tree, hf_olsr_interface_addr, tvb, offset, 4, interface_addr);
327                                         message_size--;
328                                         offset+=4;
329                                         packet_size--;
330                                 } /* end while for MID */
331                                 position = offset;
332                         } /* end if for MID */
333                         /*-----------------------------Dissect HNA Message--------------------------------*/
334                         else if(message_size>0 && message_type==HNA)    {
335                                 while(message_size>0)   {
336                                         tvb_memcpy(tvb, (guint8*)&network_addr, offset, 4);
337                                         proto_tree_add_ipv4(olsr_tree, hf_olsr_network_addr, tvb, offset, 4, network_addr);
338                                         message_size--;
339                                         packet_size--;
340                                         offset+=4;
341                                         tvb_memcpy(tvb, (guint8*)&netmask, offset, 4);
342                                         proto_tree_add_ipv4(olsr_tree, hf_olsr_netmask, tvb, offset, 4, netmask);
343                                         message_size--;
344                                         packet_size--;
345                                         offset+=4;
346                                 } /* end while for HNA */
347                                 position = offset;
348                         } /* end if for HNA */
349                         
350                 } /* end while for message alive */
351         } /* end if for IPV4 */
352
353
354 /*-----------------------------------------------------Fetching Info from IPv6 Packet and Adding to Tree-------------------------------------------------*/
355         if (tree && (pinfo->src.type==AT_IPv6)) {
356                 ti = proto_tree_add_item(tree, proto_olsr, tvb, 0, -1, FALSE);
357                 olsr_tree = proto_item_add_subtree(ti, ett_olsr);
358
359                 proto_tree_add_uint_format(olsr_tree, hf_olsr_packet_len, tvb, 0, 2, packet_len, "Packet Length: %u bytes", packet_len);
360                 proto_tree_add_item(olsr_tree, hf_olsr_packet_seq_num, tvb, 2, 2, FALSE);
361
362                 
363                 packet_size = (packet_len - 4) / 4;
364                 position = 4;
365
366                 while(packet_size>0)   {
367                         message_type = tvb_get_guint8(tvb, position);
368                         proto_tree_add_uint(olsr_tree, hf_olsr_message_type, tvb, position, 1, message_type);
369
370                         /*-------------Dissect Validity Time-------------------------*/
371                         vtime = tvb_get_guint8(tvb, position+1);
372                         high_bits = ((vtime & 0xF0) >> 4);
373                         low_bits = (vtime & 0x0F);
374                         Vtime = ((1<<low_bits)/16.0)*(1.0+(high_bits/16.0));
375                         proto_tree_add_double_format(olsr_tree, hf_olsr_vtime, tvb, position+1, 1, Vtime, "Validity Time: %.3f (in seconds)", Vtime);
376                                  
377                         /*-------------Dissect Message Size---------------------------*/
378                         message_size = tvb_get_ntohs(tvb, position+2);
379                         if (message_size < 4) {
380                                 proto_tree_add_uint_format(olsr_tree, hf_olsr_message_size, tvb, position+2, 2, message_size,"Message Size: %u bytes (too short, must be >= 4)", message_size);
381                                 break;
382                         }
383                         proto_tree_add_uint_format(olsr_tree, hf_olsr_message_size, tvb, position+2, 2, message_size,"Message Size: %u bytes", message_size);
384                         
385                         packet_size--;
386                         message_size = (message_size - 4) /4;
387
388                         offset = position + 4;
389                         position = offset;
390
391                         /*-----------------Dissecting: Origin Addr, TTL, Hop Count, and Message Seq Number */
392                         if(message_size > 0)    {
393                                 tvb_memcpy(tvb, (guint8*)&origin6_addr, offset, 16);
394                                 proto_tree_add_ipv6(olsr_tree, hf_olsr_origin6_addr, tvb, offset, 16, (guint8*)origin);
395                                 offset+=16;
396                                 message_size-=4;
397                                 packet_size-=4;
398                         }
399                         if(message_size > 0)    {
400                                 proto_tree_add_item(olsr_tree, hf_olsr_ttl, tvb, offset, 1, FALSE);
401                                 proto_tree_add_item(olsr_tree, hf_olsr_hop_count, tvb, offset+1, 1, FALSE);
402                                 proto_tree_add_item(olsr_tree, hf_olsr_message_seq_num, tvb, offset+2, 2, FALSE);
403                                 message_size--;
404                                 packet_size--;
405                                 offset+=4;
406                         }
407         
408                         position = offset;
409                         
410                         /* --------------Dissecting TC message--------------------- */
411                         if(message_size>0 && message_type == TC)   {
412                                 proto_tree_add_item(olsr_tree, hf_olsr_ansn, tvb, offset, 2, FALSE);
413
414                                 offset+=4;
415                                 message_size--;
416                                 packet_size--;
417
418                                 while(message_size>0)  {
419                                         tvb_memcpy(tvb, (guint8*)&neighbor6_addr, offset, 16);
420                                         proto_tree_add_ipv6(olsr_tree, hf_olsr_neighbor6_addr, tvb, offset, 16, (guint8*)neighbor);
421                                         message_size-=4;
422                                         offset+=16;
423                                         packet_size-=4;
424                                         }
425                                 position = offset;
426                         }
427
428                         /* -------------Dissect HELLO message----------------------- */
429                         else if(message_size>0 && message_type == HELLO)  {
430                                 /*---------------------Dissect Hellow Emission Invertal-------------------*/
431                                 htime = tvb_get_guint8(tvb, offset+2);
432                                 high_bits = ((htime & 0xF0) >> 4);
433                                 low_bits = (htime & 0x0F);
434                                 Htime = ((1<<low_bits)/16.0)*(1.0+(high_bits/16.0));
435                                 proto_tree_add_double_format(olsr_tree, hf_olsr_htime, tvb, offset+2, 1, Htime, "Hello Emission Interval: %.3f (in seconds)", Htime);
436
437                                 /*---------------------Dissect Willingness----------------------------------*/
438                                 switch(tvb_get_guint8(tvb, offset+3))   {
439                                         case 0:
440                                                 proto_tree_add_uint_format(olsr_tree, hf_olsr_willingness, tvb, offset+3, 1, tvb_get_guint8(tvb, offset+2), "Willingness: Never");
441                                                 break;
442                                         case 1:
443                                                 proto_tree_add_uint_format(olsr_tree, hf_olsr_willingness, tvb, offset+3, 1, tvb_get_guint8(tvb, offset+2), "Willingness: Low");
444                                                 break;
445                                         case 3:
446                                                 proto_tree_add_uint_format(olsr_tree, hf_olsr_willingness, tvb, offset+3, 1, tvb_get_guint8(tvb, offset+2), "Willingness: Default");
447                                                 break;
448                                         case 6:
449                                                 proto_tree_add_uint_format(olsr_tree, hf_olsr_willingness, tvb, offset+3, 1, tvb_get_guint8(tvb, offset+2), "Willingness: High");
450                                                 break;
451                                         case 7: 
452                                                 proto_tree_add_uint_format(olsr_tree, hf_olsr_willingness, tvb, offset+3, 1, tvb_get_guint8(tvb, offset+2), "Willingness: Always");
453                                                 break;
454                                         default :
455                                                 proto_tree_add_uint_format(olsr_tree, hf_olsr_willingness, tvb, offset+3, 1, tvb_get_guint8(tvb, offset+2), "Willingness: Invalid!");
456                                                 break;
457                                 } /* end switch for willingness */
458                                 
459                                 offset+=4;
460                                 message_size--;
461                                 packet_size--;
462                                 
463                                 while(message_size>0)   {
464                                         /*----------------------Dissect Link Type------------------------------------*/
465                                         switch(tvb_get_guint8(tvb, offset))     {
466                                                 case 0:
467                                                         proto_tree_add_uint_format(olsr_tree, hf_olsr_link_type, tvb, offset, 1, tvb_get_guint8(tvb, offset), "Link Type: Unspecified Link");
468                                                         break;
469                                                 case 1:
470                                                         proto_tree_add_uint_format(olsr_tree, hf_olsr_link_type, tvb, offset, 1, tvb_get_guint8(tvb, offset), "Link Type: Asymmetric Link");
471                                                         break;
472                                                 case 6:
473                                                         proto_tree_add_uint_format(olsr_tree, hf_olsr_link_type, tvb, offset, 1, tvb_get_guint8(tvb, offset), "Link Type: Symmetric Link");
474                                                         break;
475                                                 case 3:
476                                                         proto_tree_add_uint_format(olsr_tree, hf_olsr_link_type, tvb, offset, 1, tvb_get_guint8(tvb, offset), "Link Type: Lost Link");
477                                                         break;
478                                                 case 10:
479                                                         proto_tree_add_uint_format(olsr_tree, hf_olsr_link_type, tvb, offset, 1, tvb_get_guint8(tvb, offset), "Link Type: MPR Link");
480                                                         break;
481                                                 case 5:
482                                                         proto_tree_add_uint_format(olsr_tree, hf_olsr_link_type, tvb, offset, 1, tvb_get_guint8(tvb, offset), "Link Type: Pending");
483                                                         break;
484                                                 default:
485                                                         proto_tree_add_uint_format(olsr_tree, hf_olsr_link_type, tvb, offset, 1, tvb_get_guint8(tvb, offset), "Link Type: Invalid");
486                                                         break;
487                                         } /* end switch Link Type */
488                                 
489                                         /*-------------------------Dissect Link Message Size-----------------------------*/
490                                         proto_tree_add_uint_format(olsr_tree, hf_olsr_link_message_size, tvb, offset+2, 2, tvb_get_ntohs(tvb, offset+2), "Link Message Size: %u bytes", tvb_get_ntohs(tvb, offset+2));
491
492                                         link_message_size = (tvb_get_ntohs(tvb, offset+2) - 4) / 4;
493                                         offset+=4;
494                                         message_size--;
495                                         packet_size--;
496                                                                                         
497                                         /*--------------------------Dissect Neighbor Addresses---------------------------*/
498                                         while(link_message_size>0)   {
499                                                 tvb_memcpy(tvb, (guint8*)&neighbor6_addr, offset, 16);
500                                                 proto_tree_add_ipv6(olsr_tree, hf_olsr_neighbor6_addr, tvb, offset, 16, (guint8*)neighbor);
501                                                 offset+=16;
502                                                 message_size-=4;
503                                                 packet_size-=4;
504                                                 link_message_size-=4;
505                                         } /* end while */
506                                 } /* end while */
507                                 position = offset;
508                         } /* end if for Hello */
509                         /*---------------------------------Dissect MID Message----------------------------------*/
510                         else if(message_size>0 && message_type==MID)    {
511                                 while(message_size>0)   {
512                                         tvb_memcpy(tvb, (guint8*)&interface6_addr, offset, 16);
513                                         proto_tree_add_ipv6(olsr_tree, hf_olsr_interface6_addr, tvb, offset, 16, (guint8*)theinterface);
514                                         message_size-=4;
515                                         offset+=16;
516                                         packet_size-=4;
517                                 } /* end while for MID */
518                                 position = offset;
519                         } /* end if for MID */
520                         /*-----------------------------Dissect HNA Message--------------------------------*/
521                         else if(message_size>0 && message_type==HNA)    {
522                                 while(message_size>0)   {
523                                         tvb_memcpy(tvb, (guint8*)&network6_addr, offset, 16);
524                                         proto_tree_add_ipv6(olsr_tree, hf_olsr_network6_addr, tvb, offset, 16, (guint8*)network);
525                                         offset+=16;
526                                         message_size-=4;
527                                         packet_size-=4;
528                                         tvb_memcpy(tvb, (guint8*)&netmask6, offset, 16);
529                                         proto_tree_add_ipv6(olsr_tree, hf_olsr_netmask6, tvb, offset, 16, (guint8*)netmask_v6);
530                                         message_size-=4;
531                                         packet_size-=4;
532                                         offset+=16;
533                                 } /* end while for HNA */
534                                 position = offset;
535                         } /* end if for HNA */
536                 } /* end while for message alive */
537         } /* end if for IPV6 */
538         return tvb_length(tvb);
539 } /* end Dissecting */
540         
541 /*-----------Register the Dissector for OLSR--------------*/
542 void
543 proto_register_olsr(void)
544 {                 
545         static hf_register_info hf[] = {
546                 { &hf_olsr_packet_len,
547                         { "Packet Length", "olsr.packet_len",
548                            FT_UINT16, BASE_DEC, NULL, 0,          
549                           "Packet Length in Bytes", HFILL }},
550
551                 { &hf_olsr_packet_seq_num,
552                         { "Packet Sequence Number", "olsr.packet_seq_num",
553                            FT_UINT16, BASE_DEC, NULL, 0,
554                           "Packet Sequence Number", HFILL }},
555
556                 { &hf_olsr_message_type,
557                         { "Message Type", "olsr.message_type",
558                            FT_UINT8, BASE_DEC, VALS(message_type_vals), 0,
559                           "Message Type", HFILL }},
560
561                 { &hf_olsr_message_size,
562                         { "Message", "olsr.message_size",
563                            FT_UINT16, BASE_DEC, NULL, 0,          
564                           "Message Size in Bytes", HFILL }},
565
566                 { &hf_olsr_message_seq_num,
567                         { "Message Sequence Number", "olsr.message_seq_num",
568                            FT_UINT16, BASE_DEC, NULL, 0,          
569                           "Message Sequence Number", HFILL }},
570
571                 { &hf_olsr_vtime,
572                         { "Validity Time", "olsr.vtime",
573                            FT_DOUBLE, BASE_NONE, NULL, 0,
574                           "Validity Time", HFILL }},
575                 
576                 { &hf_olsr_ansn,
577                         { "Advertised Neighbor Sequence Number (ANSN)", "olsr.ansn",
578                            FT_UINT16, BASE_DEC, NULL, 0,
579                           "Advertised Neighbor Sequence Number (ANSN)", HFILL }},
580
581                 { &hf_olsr_htime,
582                         { "Hello emission interval", "olsr.htime",
583                            FT_DOUBLE, BASE_NONE, NULL, 0,
584                           "Hello emission interval", HFILL }},
585
586                 { &hf_olsr_willingness,
587                         { "Willingness to Carry and Forward", "olsr.willingness",
588                            FT_UINT8, BASE_DEC, NULL, 0,
589                           "Willingness to Carry and Forward", HFILL }},
590                           
591                 { &hf_olsr_ttl,
592                         { "Time to Live", "olsr.ttl",
593                            FT_UINT8, BASE_DEC, NULL, 0,
594                           "Time to Live", HFILL }},
595                                                   
596                 { &hf_olsr_link_type,
597                         { "Link Type", "olsr.link_type",
598                            FT_UINT8, BASE_DEC, NULL, 0,
599                           "Link Type", HFILL }},
600
601                 { &hf_olsr_link_message_size,
602                         { "Link Message Size", "olsr.link_message_size",
603                            FT_UINT16, BASE_DEC, NULL, 0,
604                           "Link Message Size", HFILL }},
605
606                 { &hf_olsr_hop_count,
607                         { "Hop Count", "olsr.hop_count",
608                            FT_UINT8, BASE_DEC, NULL, 0,
609                           "Hop Count", HFILL }},
610
611                 { &hf_olsr_origin_addr,
612                         { "Originator Address", "olsr.origin_addr",
613                            FT_IPv4, BASE_NONE, NULL, 0,
614                           "Originator Address", HFILL }},
615
616                 { &hf_olsr_neighbor_addr,
617                         { "Neighbor Address", "olsr.neighbor_addr",
618                            FT_IPv4, BASE_NONE, NULL, 0,
619                           "Neighbor Address", HFILL }},
620
621                 
622                 { &hf_olsr_network_addr,
623                         { "Network Address", "olsr.network_addr",
624                            FT_IPv4, BASE_NONE, NULL, 0,
625                           "Network Address", HFILL }},
626
627                 { &hf_olsr_interface_addr,
628                         { "Interface Address", "olsr.interface_addr",
629                            FT_IPv4, BASE_NONE, NULL, 0,
630                           "Interface Address", HFILL }},
631
632                 { &hf_olsr_netmask,
633                         { "Netmask", "olsr.netmask",
634                            FT_IPv4, BASE_NONE, NULL, 0,
635                           "Netmask", HFILL }},
636                           
637                 { &hf_olsr_origin6_addr,
638                         { "Originator Address", "olsr.origin6_addr",
639                            FT_IPv6, BASE_NONE, NULL, 0,
640                           "Originator Address", HFILL }},
641
642                 { &hf_olsr_neighbor6_addr,
643                         { "Neighbor Address", "olsr.neighbor6_addr",
644                            FT_IPv6, BASE_NONE, NULL, 0,
645                           "Neighbor Address", HFILL }},
646
647                 { &hf_olsr_network6_addr,
648                         { "Network Address", "olsr.network6_addr",
649                            FT_IPv6, BASE_NONE, NULL, 0,
650                           "Network Address", HFILL }},
651
652                 { &hf_olsr_interface6_addr,
653                         { "Interface Address", "olsr.interface6_addr",
654                            FT_IPv6, BASE_NONE, NULL, 0,
655                           "Interface Address", HFILL }},
656
657                 { &hf_olsr_netmask6,
658                         { "Netmask", "olsr.netmask6",
659                            FT_IPv6, BASE_NONE, NULL, 0,
660                           "Netmask", HFILL }},
661         };
662
663
664         static gint *ett[] = {
665                 &ett_olsr,
666         };
667
668
669         proto_olsr = proto_register_protocol("Optimized Link State Routing Protocol",
670             "OLSR", "olsr");
671
672         proto_register_field_array(proto_olsr, hf, array_length(hf));
673         proto_register_subtree_array(ett, array_length(ett));
674 }
675
676 void
677 proto_reg_handoff_olsr(void)
678 {
679         dissector_handle_t olsr_handle;
680
681         olsr_handle = new_create_dissector_handle(dissect_olsr, proto_olsr);
682         dissector_add("udp.port", UDP_PORT_OLSR, olsr_handle);
683 }