Put the "-s" option in the SYNOPSIS section.
[obnox/wireshark/wip.git] / packet-ospf.c
1 /* packet-ospf.c
2  * Routines for OSPF packet disassembly
3  * (c) Copyright Hannes R. Boehm <hannes@boehm.org>
4  *
5  * $Id: packet-ospf.c,v 1.53 2001/12/10 00:25:31 guy Exp $
6  *
7  * At this time, this module is able to analyze OSPF
8  * packets as specified in RFC2328. MOSPF (RFC1584) and other
9  * OSPF Extensions which introduce new Packet types
10  * (e.g the External Atributes LSA) are not supported.
11  * Furthermore RFC2740 (OSPFv3 - OSPF for IPv6) is now supported
12  *   - (c) 2001 Palle Lyckegaard <palle[AT]lyckegaard.dk>
13  *
14  * TOS - support is not fully implemented
15  * 
16  * Ethereal - Network traffic analyzer
17  * By Gerald Combs <gerald@ethereal.com>
18  * Copyright 1998 Gerald Combs
19  * 
20  * This program is free software; you can redistribute it and/or
21  * modify it under the terms of the GNU General Public License
22  * as published by the Free Software Foundation; either version 2
23  * of the License, or (at your option) any later version.
24  * 
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28  * GNU General Public License for more details.
29  * 
30  * You should have received a copy of the GNU General Public License
31  * along with this program; if not, write to the Free Software
32  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
33  */
34  
35 #ifdef HAVE_CONFIG_H
36 # include "config.h"
37 #endif
38
39 #ifdef HAVE_SYS_TYPES_H
40 # include <sys/types.h>
41 #endif
42
43 #ifdef HAVE_NETINET_IN_H
44 # include <netinet/in.h>
45 #endif
46
47 #include <stdio.h>
48 #include <string.h>
49
50 #include <glib.h>
51 #include "packet.h"
52 #include "ipproto.h"
53 #include "in_cksum.h"
54 #include "ieee-float.h"
55
56 #define OSPF_VERSION_2 2
57 #define OSPF_VERSION_3 3
58 #define OSPF_VERSION_2_HEADER_LENGTH    24
59 #define OSPF_VERSION_3_HEADER_LENGTH    16
60
61
62 #define OSPF_HELLO      1
63 #define OSPF_DB_DESC    2
64 #define OSPF_LS_REQ     3
65 #define OSPF_LS_UPD     4
66 #define OSPF_LS_ACK     5
67
68 static const value_string pt_vals[] = {
69         {OSPF_HELLO,   "Hello Packet"   },
70         {OSPF_DB_DESC, "DB Descr."      },
71         {OSPF_LS_REQ,  "LS Request"     },
72         {OSPF_LS_UPD,  "LS Update"      },
73         {OSPF_LS_ACK,  "LS Acknowledge" },
74         {0,             NULL            }
75 };
76
77 #define OSPF_AUTH_NONE          0
78 #define OSPF_AUTH_SIMPLE        1
79 #define OSPF_AUTH_CRYPT         2
80
81 static const value_string auth_vals[] = {
82         {OSPF_AUTH_NONE,   "Null"            },
83         {OSPF_AUTH_SIMPLE, "Simple password" },
84         {OSPF_AUTH_CRYPT,  "Cryptographic"   },
85         {0,                NULL              }
86 };
87
88 #define OSPF_V2_OPTIONS_E               0x02
89 #define OSPF_V2_OPTIONS_MC              0x04
90 #define OSPF_V2_OPTIONS_NP              0x08
91 #define OSPF_V2_OPTIONS_EA              0x10
92 #define OSPF_V2_OPTIONS_DC              0x20
93 #define OSPF_V2_OPTIONS_O               0x40
94 #define OSPF_V2_OPTIONS_DN              0x01
95 #define OSPF_V3_OPTIONS_V6              0x01    
96 #define OSPF_V3_OPTIONS_E               0x02
97 #define OSPF_V3_OPTIONS_MC              0x04
98 #define OSPF_V3_OPTIONS_N               0x08
99 #define OSPF_V3_OPTIONS_R               0x10
100 #define OSPF_V3_OPTIONS_DC              0x20
101
102
103 #define OSPF_DBD_FLAG_MS        1
104 #define OSPF_DBD_FLAG_M         2
105 #define OSPF_DBD_FLAG_I         4
106
107 #define OSPF_LS_REQ_LENGTH      12
108
109 #define OSPF_LSTYPE_ROUTER      1
110 #define OSPF_LSTYPE_NETWORK     2
111 #define OSPF_LSTYPE_SUMMERY     3
112 #define OSPF_LSTYPE_ASBR        4
113 #define OSPF_LSTYPE_ASEXT       5
114 #define OSPF_LSTYPE_GRPMEMBER   6
115 #define OSPF_LSTYPE_ASEXT7      7
116 #define OSPF_LSTYPE_EXTATTR     8
117 #define OSPF_V3_LSTYPE_ROUTER                0x2001
118 #define OSPF_V3_LSTYPE_NETWORK               0x2002
119 #define OSPF_V3_LSTYPE_INTER_AREA_PREFIX     0x2003
120 #define OSPF_V3_LSTYPE_INTER_AREA_ROUTER     0x2004
121 #define OSPF_V3_LSTYPE_AS_EXTERNAL           0x4005
122 #define OSPF_V3_LSTYPE_GROUP_MEMBERSHIP      0x2006     
123 #define OSPF_V3_LSTYPE_TYPE_7                0x2007
124 #define OSPF_V3_LSTYPE_LINK                  0x0008
125 #define OSPF_V3_LSTYPE_INTRA_AREA_PREFIX     0x2009
126
127 /* Opaque LSA types */
128 #define OSPF_LSTYPE_OP_LINKLOCAL 9
129 #define OSPF_LSTYPE_OP_AREALOCAL 10
130 #define OSPF_LSTYPE_OP_ASWIDE    11
131
132 #define OSPF_LINK_PTP           1
133 #define OSPF_LINK_TRANSIT       2
134 #define OSPF_LINK_STUB          3
135 #define OSPF_LINK_VIRTUAL       4
136
137 #define OSPF_V3_LINK_PTP        1
138 #define OSPF_V3_LINK_TRANSIT    2
139 #define OSPF_V3_LINK_RESERVED   3
140 #define OSPF_V3_LINK_VIRTUAL    4
141
142 #define OSPF_LSA_HEADER_LENGTH  20
143
144 /* Known opaque LSAs */
145 #define OSPF_LSA_MPLS_TE        1
146
147
148 static const value_string ls_type_vals[] = {
149         {OSPF_LSTYPE_ROUTER,                  "Router-LSA"                   },
150         {OSPF_LSTYPE_NETWORK,                 "Network-LSA"                  },
151         {OSPF_LSTYPE_SUMMERY,                 "Summary-LSA (IP network)"     },
152         {OSPF_LSTYPE_ASBR,                    "Summary-LSA (ASBR)"           },
153         {OSPF_LSTYPE_ASEXT,                   "AS-External-LSA (ASBR)"       },
154         {OSPF_LSTYPE_GRPMEMBER,               "Group Membership LSA"         },
155         {OSPF_LSTYPE_ASEXT7,                  "NSSA AS-External-LSA"         },
156         {OSPF_LSTYPE_EXTATTR,                 "External Attributes LSA"      },
157         {OSPF_LSTYPE_OP_LINKLOCAL,            "Opaque LSA, Link-local scope" },
158         {OSPF_LSTYPE_OP_AREALOCAL,            "Opaque LSA, Area-local scope" },
159         {0,                                   NULL                           }
160
161 };
162
163 static const value_string v3_ls_type_vals[] = {
164         {OSPF_V3_LSTYPE_ROUTER,               "Router-LSA"                   }, 
165         {OSPF_V3_LSTYPE_NETWORK,              "Network-LSA"                  }, 
166         {OSPF_V3_LSTYPE_INTER_AREA_PREFIX,    "Inter-Area-Prefix-LSA"        }, 
167         {OSPF_V3_LSTYPE_INTER_AREA_ROUTER,    "Inter-Area-Router-LSA"        }, 
168         {OSPF_V3_LSTYPE_AS_EXTERNAL,          "AS-External-LSA"              }, 
169         {OSPF_V3_LSTYPE_GROUP_MEMBERSHIP,     "Group-Membership-LSA"         }, 
170         {OSPF_V3_LSTYPE_TYPE_7,               "Type-LSA"                     }, 
171         {OSPF_V3_LSTYPE_LINK,                 "Link-LSA"                     },
172         {OSPF_V3_LSTYPE_INTRA_AREA_PREFIX,    "Intra-Area-Prefix-LSA"        },
173         {0,                                   NULL                           }
174
175 };
176
177
178 #define OSPF_V3_ROUTER_LSA_FLAG_B 0x01
179 #define OSPF_V3_ROUTER_LSA_FLAG_E 0x02
180 #define OSPF_V3_ROUTER_LSA_FLAG_V 0x04
181 #define OSPF_V3_ROUTER_LSA_FLAG_W 0x08
182
183 #define OSPF_V3_PREFIX_OPTION_NU 0x01
184 #define OSPF_V3_PREFIX_OPTION_LA 0x02
185 #define OSPF_V3_PREFIX_OPTION_MC 0x04
186 #define OSPF_V3_PREFIX_OPTION_P  0x08
187
188 #define OSPF_V3_AS_EXTERNAL_FLAG_T 0x01
189 #define OSPF_V3_AS_EXTERNAL_FLAG_F 0x02
190 #define OSPF_V3_AS_EXTERNAL_FLAG_E 0x04
191
192
193 static int proto_ospf = -1;
194
195 static gint ett_ospf = -1;
196 static gint ett_ospf_hdr = -1;
197 static gint ett_ospf_hello = -1;
198 static gint ett_ospf_desc = -1;
199 static gint ett_ospf_lsr = -1;
200 static gint ett_ospf_lsa = -1;
201 static gint ett_ospf_lsa_upd = -1;
202
203 /* Trees for opaque LSAs */
204 static gint ett_ospf_lsa_mpls = -1;
205 static gint ett_ospf_lsa_mpls_router = -1;
206 static gint ett_ospf_lsa_mpls_link = -1;
207 static gint ett_ospf_lsa_mpls_link_stlv = -1;
208
209 static dissector_handle_t data_handle;
210
211 static void dissect_ospf_hello(tvbuff_t*, int, proto_tree*, guint8);
212 static void dissect_ospf_db_desc(tvbuff_t*, int, proto_tree*, guint8); 
213 static void dissect_ospf_ls_req(tvbuff_t*, int, proto_tree*, guint8); 
214 static void dissect_ospf_ls_upd(tvbuff_t*, int, proto_tree*, guint8); 
215 static void dissect_ospf_ls_ack(tvbuff_t*, int, proto_tree*, guint8); 
216
217 /* dissect_ospf_v[23]lsa returns the offset of the next LSA
218  * if disassemble_body is set to FALSE (e.g. in LSA ACK 
219  * packets), the offset is set to the offset of the next
220  * LSA header
221  */
222 static int dissect_ospf_v2_lsa(tvbuff_t*, int, proto_tree*, gboolean disassemble_body); 
223 static int dissect_ospf_v3_lsa(tvbuff_t*, int, proto_tree*, gboolean disassemble_body); 
224
225 static void dissect_ospf_options(tvbuff_t *, int, proto_tree *, guint8);
226
227 static void dissect_ospf_v3_prefix_options(tvbuff_t *, int, proto_tree *);
228
229 static void dissect_ospf_v3_address_prefix(tvbuff_t *, int, int, proto_tree *);
230
231 static void 
232 dissect_ospf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
233 {
234     proto_tree *ospf_tree = NULL;
235     proto_item *ti; 
236     proto_tree *ospf_header_tree;
237     guint8  version;
238     guint8  packet_type;
239     guint16 ospflen;
240     vec_t cksum_vec[4];
241     int cksum_vec_len;
242     guint32 phdr[2];
243     guint16 cksum, computed_cksum;
244     guint length, reported_length;
245     guint16 auth_type;
246     char auth_data[8];
247     int crypto_len;
248     unsigned int ospf_header_length;
249     guint8 instance_ID;
250     guint8 reserved;
251     guint32 areaid;
252
253
254     if (check_col(pinfo->cinfo, COL_PROTOCOL))
255         col_set_str(pinfo->cinfo, COL_PROTOCOL, "OSPF");
256     if (check_col(pinfo->cinfo, COL_INFO))
257         col_clear(pinfo->cinfo, COL_INFO);
258
259     version = tvb_get_guint8(tvb, 0);
260     switch (version) {
261         case OSPF_VERSION_2:
262             ospf_header_length = OSPF_VERSION_2_HEADER_LENGTH;
263             break;
264         case OSPF_VERSION_3:
265             ospf_header_length = OSPF_VERSION_3_HEADER_LENGTH;
266             break;
267         default:
268             ospf_header_length = 0;
269             break;
270     }
271
272     packet_type = tvb_get_guint8(tvb, 1);
273     if (check_col(pinfo->cinfo, COL_INFO)) {
274         col_add_str(pinfo->cinfo, COL_INFO,
275                     val_to_str(packet_type, pt_vals, "Unknown (%u)"));
276     }  
277
278     if (tree) {
279         ospflen = tvb_get_ntohs(tvb, 2);
280
281         ti = proto_tree_add_item(tree, proto_ospf, tvb, 0, ospflen, FALSE);
282         ospf_tree = proto_item_add_subtree(ti, ett_ospf);
283
284         ti = proto_tree_add_text(ospf_tree, tvb, 0, ospf_header_length,
285                                  "OSPF Header"); 
286         ospf_header_tree = proto_item_add_subtree(ti, ett_ospf_hdr);
287
288         proto_tree_add_text(ospf_header_tree, tvb, 0, 1, "OSPF Version: %u",
289                             version);  
290         proto_tree_add_text(ospf_header_tree, tvb, 1, 1, "OSPF Packet Type: %u (%s)",
291                             packet_type,
292                             val_to_str(packet_type, pt_vals, "Unknown"));
293         proto_tree_add_text(ospf_header_tree, tvb, 2, 2, "Packet Length: %u",
294                             ospflen);
295         proto_tree_add_text(ospf_header_tree, tvb, 4, 4, "Source OSPF Router ID: %s",
296                             ip_to_str(tvb_get_ptr(tvb, 4, 4)));
297         areaid=tvb_get_ntohl(tvb,8);
298         proto_tree_add_text(ospf_header_tree, tvb, 8, 4, "Area ID: %s%s",
299                                ip_to_str(tvb_get_ptr(tvb, 8, 4)), areaid == 0 ? " (Backbone)" : "");
300         cksum = tvb_get_ntohs(tvb, 12);
301         length = tvb_length(tvb);
302         /* XXX - include only the length from the OSPF header? */
303         reported_length = tvb_reported_length(tvb);
304         if (cksum == 0) {
305                 /* No checksum supplied in the packet. */
306                 proto_tree_add_text(ospf_header_tree, tvb, 12, 2,
307                     "Packet Checksum: 0x%04x (none)", cksum);
308         } else if (!pinfo->fragmented && length >= reported_length
309                 && length >= ospf_header_length
310                 && (version == OSPF_VERSION_2 || version == OSPF_VERSION_3)) {
311             /* The packet isn't part of a fragmented datagram and isn't
312                truncated, and we know how to checksum this version of
313                OSPF, so we can checksum it. */
314
315             switch (version) {
316
317             case OSPF_VERSION_2:
318                 /* Header, not including the authentication data (the OSPFv2
319                    checksum excludes the 64-bit authentication field). */
320                 cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, 16);
321                 cksum_vec[0].len = 16;
322                 if (length > ospf_header_length) {
323                     /* Rest of the packet, again not including the
324                        authentication data. */
325                     reported_length -= ospf_header_length;
326                     cksum_vec[1].ptr = tvb_get_ptr(tvb, ospf_header_length, reported_length);
327                     cksum_vec[1].len = reported_length;
328                     cksum_vec_len = 2;
329                 } else {
330                     /* There's nothing but a header. */
331                     cksum_vec_len = 1;
332                 }
333                 break;
334
335             case OSPF_VERSION_3:
336                 /* IPv6-style checksum, covering the entire OSPF packet
337                    and a prepended IPv6 pseudo-header. */
338
339                 /* Set up the fields of the pseudo-header. */
340                 cksum_vec[0].ptr = pinfo->src.data;
341                 cksum_vec[0].len = pinfo->src.len;
342                 cksum_vec[1].ptr = pinfo->dst.data;
343                 cksum_vec[1].len = pinfo->dst.len;
344                 cksum_vec[2].ptr = (const guint8 *)&phdr;
345                 phdr[0] = htonl(ospflen);
346                 phdr[1] = htonl(IP_PROTO_OSPF);
347                 cksum_vec[2].len = 8;
348
349                 cksum_vec[3].ptr = tvb_get_ptr(tvb, 0, reported_length);
350                 cksum_vec[3].len = reported_length;
351                 cksum_vec_len = 4;
352                 break;
353
354             default:
355                 g_assert_not_reached();
356                 cksum_vec_len = 0;
357             }
358             computed_cksum = in_cksum(cksum_vec, cksum_vec_len);
359             if (computed_cksum == 0) {
360                 proto_tree_add_text(ospf_header_tree, tvb, 12, 2,
361                         "Packet Checksum: 0x%04x (correct)", cksum);
362             } else {
363                 proto_tree_add_text(ospf_header_tree, tvb, 12, 2,
364                         "Packet Checksum: 0x%04x (incorrect, should be 0x%04x)",
365                         cksum, in_cksum_shouldbe(cksum, computed_cksum));
366             }
367         } else {
368             proto_tree_add_text(ospf_header_tree, tvb, 12, 2,
369                 "Packet Checksum: 0x%04x", cksum);
370         }
371
372
373         /* Authentication is only valid for OSPFv2 */
374         if ( version == OSPF_VERSION_2 ) {        
375             auth_type = tvb_get_ntohs(tvb, 14);
376             proto_tree_add_text(ospf_header_tree, tvb, 14, 2, "Auth Type: %s",
377                             val_to_str(auth_type, auth_vals, "Unknown (%u)"));
378             switch (auth_type) {
379
380             case OSPF_AUTH_NONE:
381                 proto_tree_add_text(ospf_header_tree, tvb, 16, 8, "Auth Data (none)");
382                 break;
383
384             case OSPF_AUTH_SIMPLE:
385                 tvb_get_nstringz0(tvb, 16, 8, auth_data);
386                 proto_tree_add_text(ospf_header_tree, tvb, 16, 8, "Auth Data: %s", auth_data);
387                 break;
388
389             case OSPF_AUTH_CRYPT:
390                 proto_tree_add_text(ospf_header_tree, tvb, 18, 1, "Auth Key ID: %u",
391                                 tvb_get_guint8(tvb, 18));
392                 crypto_len = tvb_get_guint8(tvb, 19);
393                 proto_tree_add_text(ospf_header_tree, tvb, 19, 1, "Auth Data Length: %u",
394                                 crypto_len);
395                 proto_tree_add_text(ospf_header_tree, tvb, 20, 4, "Auth Crypto Sequence Number: 0x%x",
396                                 tvb_get_ntohl(tvb, 20));
397   
398                 /* Show the message digest that was appended to the end of the
399                    OSPF message - but only if it's present (we don't want
400                    to get an exception before we've tried dissecting OSPF
401                    message). */
402                 if (tvb_bytes_exist(tvb, ospflen, crypto_len)) {
403                     proto_tree_add_text(ospf_header_tree, tvb, ospflen, crypto_len,
404                                     "Auth Data: %s",
405                                     tvb_bytes_to_str(tvb, ospflen, crypto_len));
406                 }
407                 break;
408
409             default:
410                 proto_tree_add_text(ospf_header_tree, tvb, 16, 8, "Auth Data (unknown)");
411                 break;
412             }
413
414         }
415
416         /* Instance ID and "reserved" is OSPFv3-only */
417         if ( version == OSPF_VERSION_3 ) {
418             instance_ID = tvb_get_guint8(tvb, 14);
419             proto_tree_add_text(ospf_header_tree, tvb, 14, 1, "Instance ID: %u",
420                             instance_ID);
421             reserved = tvb_get_guint8(tvb, 15);
422             proto_tree_add_text(ospf_header_tree, tvb, 15, 1, (reserved == 0 ? "Reserved: %u" : "Reserved: %u (incorrect, should be 0)"),
423                                 reserved);
424
425         }
426
427         /* Adjust the length of the tvbuff to match the size of the OSPF
428          * packet (since the dissect routines use it to work out where the
429          * end of the OSPF packet is).
430          */
431         tvb_set_reported_length(tvb, ospflen);
432
433         switch (packet_type){
434
435         case OSPF_HELLO:
436             dissect_ospf_hello(tvb, ospf_header_length, ospf_tree, version);
437             break;
438
439         case OSPF_DB_DESC:
440             dissect_ospf_db_desc(tvb, ospf_header_length, ospf_tree, version);
441             break;
442
443         case OSPF_LS_REQ:
444             dissect_ospf_ls_req(tvb, ospf_header_length, ospf_tree, version);
445             break;
446
447         case OSPF_LS_UPD:
448             dissect_ospf_ls_upd(tvb, ospf_header_length, ospf_tree, version);
449             break;
450
451         case OSPF_LS_ACK:
452             dissect_ospf_ls_ack(tvb, ospf_header_length, ospf_tree, version);
453             break;
454
455         default:
456             call_dissector(data_handle,tvb_new_subset(tvb, ospf_header_length,-1,tvb_reported_length_remaining(tvb,ospf_header_length)), pinfo, tree);
457             break;
458         }
459     }
460 }
461
462 static void
463 dissect_ospf_hello(tvbuff_t *tvb, int offset, proto_tree *tree, guint8 version)
464 {
465     proto_tree *ospf_hello_tree;
466     proto_item *ti; 
467
468     ti = proto_tree_add_text(tree, tvb, offset,
469                              tvb_length_remaining(tvb, offset),
470                              "OSPF Hello Packet");
471     ospf_hello_tree = proto_item_add_subtree(ti, ett_ospf_hello);
472     
473     switch (version ) {
474         case OSPF_VERSION_2:
475             proto_tree_add_text(ospf_hello_tree, tvb, offset, 4, "Network Mask: %s",
476                         ip_to_str(tvb_get_ptr(tvb, offset, 4)));
477             proto_tree_add_text(ospf_hello_tree, tvb, offset + 4, 2,
478                         "Hello Interval: %u seconds",
479                         tvb_get_ntohs(tvb, offset + 4));
480
481             dissect_ospf_options(tvb, offset + 6, ospf_hello_tree, version);
482             proto_tree_add_text(ospf_hello_tree, tvb, offset + 7, 1, "Router Priority: %u",
483                         tvb_get_guint8(tvb, offset + 7));
484             proto_tree_add_text(ospf_hello_tree, tvb, offset + 8, 4, "Router Dead Interval: %u seconds",
485                         tvb_get_ntohl(tvb, offset + 8));
486             proto_tree_add_text(ospf_hello_tree, tvb, offset + 12, 4, "Designated Router: %s",
487                         ip_to_str(tvb_get_ptr(tvb, offset + 12, 4)));
488             proto_tree_add_text(ospf_hello_tree, tvb, offset + 16, 4, "Backup Designated Router: %s",
489                         ip_to_str(tvb_get_ptr(tvb, offset + 16, 4)));
490
491             offset += 20;
492             while (tvb_reported_length_remaining(tvb, offset) != 0) {
493                 proto_tree_add_text(ospf_hello_tree, tvb, offset, 4,
494                             "Active Neighbor: %s",
495                             ip_to_str(tvb_get_ptr(tvb, offset, 4)));
496                 offset += 4;
497             }
498             break;
499         case OSPF_VERSION_3:
500             proto_tree_add_text(ospf_hello_tree, tvb, offset + 0, 4, "Interface ID: %u",
501                         tvb_get_ntohl(tvb, offset + 0));
502             proto_tree_add_text(ospf_hello_tree, tvb, offset + 4, 1, "Router Priority: %u",
503                         tvb_get_guint8(tvb, offset + 4));
504             dissect_ospf_options(tvb, offset + 5, ospf_hello_tree, version);
505             proto_tree_add_text(ospf_hello_tree, tvb, offset + 8, 2,
506                         "Hello Interval: %u seconds",
507                         tvb_get_ntohs(tvb, offset + 8));
508             proto_tree_add_text(ospf_hello_tree, tvb, offset + 10, 2, "Router Dead Interval: %u seconds",
509                         tvb_get_ntohs(tvb, offset + 10));
510             proto_tree_add_text(ospf_hello_tree, tvb, offset + 12, 4, "Designated Router: %s",
511                         ip_to_str(tvb_get_ptr(tvb, offset + 12, 4)));
512             proto_tree_add_text(ospf_hello_tree, tvb, offset + 16, 4, "Backup Designated Router: %s",
513                         ip_to_str(tvb_get_ptr(tvb, offset + 16, 4)));
514             offset += 20;
515             while (tvb_reported_length_remaining(tvb, offset) != 0) {
516                 proto_tree_add_text(ospf_hello_tree, tvb, offset, 4,
517                             "Active Neighbor: %s",
518                             ip_to_str(tvb_get_ptr(tvb, offset, 4)));
519                 offset += 4;
520             }
521
522             break;
523
524         default:    
525             break;
526     }
527 }
528
529 static void
530 dissect_ospf_db_desc(tvbuff_t *tvb, int offset, proto_tree *tree, guint8 version)
531 {
532     proto_tree *ospf_db_desc_tree=NULL;
533     proto_item *ti; 
534     guint8 flags;
535     guint8 reserved;
536     char flags_string[20] = "";
537
538     if (tree) {
539         ti = proto_tree_add_text(tree, tvb, offset,
540                                  tvb_length_remaining(tvb, offset),
541                                  "OSPF DB Description"); 
542         ospf_db_desc_tree = proto_item_add_subtree(ti, ett_ospf_desc);
543
544         switch (version ) {
545  
546             case OSPF_VERSION_2:
547
548                 proto_tree_add_text(ospf_db_desc_tree, tvb, offset, 2, "Interface MTU: %u",
549                             tvb_get_ntohs(tvb, offset));
550
551                 dissect_ospf_options(tvb, offset + 2, ospf_db_desc_tree, version);
552
553                 flags = tvb_get_guint8(tvb, offset + 3);
554                 if (flags & OSPF_DBD_FLAG_MS)
555                     strcat(flags_string, "MS");
556                 if (flags & OSPF_DBD_FLAG_M) {
557                     if (flags_string[0] != '\0')
558                         strcat(flags_string, "/");
559                     strcat(flags_string, "M");
560                 }
561                 if (flags & OSPF_DBD_FLAG_I) {
562                     if (flags_string[0] != '\0')
563                         strcat(flags_string, "/");
564                     strcat(flags_string, "I");
565                 }
566                 proto_tree_add_text(ospf_db_desc_tree, tvb, offset + 3, 1, "Flags: 0x%x (%s)",
567                             flags, flags_string);
568                 proto_tree_add_text(ospf_db_desc_tree, tvb, offset + 4, 4, "DD Sequence: %u",
569                             tvb_get_ntohl(tvb, offset + 4));
570
571                 offset += 8;
572                 break;
573
574             case OSPF_VERSION_3:
575
576                 reserved = tvb_get_guint8(tvb, offset);
577                 proto_tree_add_text(ospf_db_desc_tree, tvb, offset, 1, (reserved == 0 ? "Reserved: %u" : "Reserved: %u (incorrect, should be 0)"),
578                                 reserved);
579
580                 dissect_ospf_options(tvb, offset + 1, ospf_db_desc_tree, version);
581
582                 proto_tree_add_text(ospf_db_desc_tree, tvb, offset + 4, 2, "Interface MTU: %u",
583                             tvb_get_ntohs(tvb, offset+4));
584
585                 reserved = tvb_get_guint8(tvb, offset + 6);
586                 proto_tree_add_text(ospf_db_desc_tree, tvb, offset + 6, 1, (reserved == 0 ? "Reserved: %u" : "Reserved: %u (incorrect, should be 0)"),
587                                 reserved);
588
589                 flags = tvb_get_guint8(tvb, offset + 7);
590                 if (flags & OSPF_DBD_FLAG_MS)
591                     strcat(flags_string, "MS");
592                 if (flags & OSPF_DBD_FLAG_M) {
593                     if (flags_string[0] != '\0')
594                         strcat(flags_string, "/");
595                     strcat(flags_string, "M");
596                 }
597                 if (flags & OSPF_DBD_FLAG_I) {
598                     if (flags_string[0] != '\0')
599                         strcat(flags_string, "/");
600                     strcat(flags_string, "I");
601                 }
602                 proto_tree_add_text(ospf_db_desc_tree, tvb, offset + 7, 1, "Flags: 0x%x (%s)",
603                             flags, flags_string);
604
605                 proto_tree_add_text(ospf_db_desc_tree, tvb, offset + 8, 4, "DD Sequence: %u",
606                             tvb_get_ntohl(tvb, offset + 8));
607
608                 offset += 12;
609                 break;
610
611             default:
612                 break;
613         }
614     }
615
616     /* LS Headers will be processed here */
617     /* skip to the end of DB-Desc header */
618     while (tvb_reported_length_remaining(tvb, offset) != 0) {
619       if ( version == OSPF_VERSION_2)
620           offset = dissect_ospf_v2_lsa(tvb, offset, tree, FALSE);
621       else
622           if ( version == OSPF_VERSION_3)
623               offset = dissect_ospf_v3_lsa(tvb, offset, tree, FALSE);
624     }
625
626 }
627
628 static void
629 dissect_ospf_ls_req(tvbuff_t *tvb, int offset, proto_tree *tree, guint8 version)
630 {
631     proto_tree *ospf_lsr_tree;
632     proto_item *ti;
633     guint32 ls_type;
634     guint8 reserved;
635
636     /* zero or more LS requests may be within a LS Request */
637     /* we place every request for a LSA in a single subtree */
638     while (tvb_reported_length_remaining(tvb, offset) != 0) {
639         ti = proto_tree_add_text(tree, tvb, offset, OSPF_LS_REQ_LENGTH,
640                                  "Link State Request"); 
641         ospf_lsr_tree = proto_item_add_subtree(ti, ett_ospf_lsr);
642       
643         reserved = tvb_get_guint8(tvb, offset);
644         proto_tree_add_text(ospf_lsr_tree, tvb, offset, 1,
645            (reserved == 0 ? "Reserved: %u" : "Reserved: %u (incorrect, should be 0)"),
646                                 reserved);
647
648         switch ( version ) {
649
650             case OSPF_VERSION_2:
651                 ls_type = tvb_get_ntohl(tvb, offset);
652                 proto_tree_add_text(ospf_lsr_tree, tvb, offset, 4, "LS Type: %s (%u)",
653                             val_to_str(ls_type, ls_type_vals, "Unknown"),
654                             ls_type);
655                 break;
656             case OSPF_VERSION_3:
657                 ls_type = tvb_get_ntohs(tvb, offset+2);
658                 proto_tree_add_text(ospf_lsr_tree, tvb, offset+2, 2, "LS Type: %s (0x%04x)",
659                             val_to_str(ls_type, v3_ls_type_vals, "Unknown"),
660                             ls_type);
661                   break;
662             default:
663                  ls_type=0;
664                  break;
665         }
666
667
668         proto_tree_add_text(ospf_lsr_tree, tvb, offset + 4, 4, "Link State ID: %s", 
669                             ip_to_str(tvb_get_ptr(tvb, offset + 4, 4)));
670         proto_tree_add_text(ospf_lsr_tree, tvb, offset + 8, 4, "Advertising Router: %s", 
671                             ip_to_str(tvb_get_ptr(tvb, offset + 8, 4)));
672
673         offset += 12;
674     }
675 }
676
677 static void
678 dissect_ospf_ls_upd(tvbuff_t *tvb, int offset, proto_tree *tree, guint8 version)
679 {
680     proto_tree *ospf_lsa_upd_tree=NULL;
681     proto_item *ti;
682     guint32 lsa_nr;
683     guint32 lsa_counter; 
684
685     ti = proto_tree_add_text(tree, tvb, offset,
686                              tvb_length_remaining(tvb, offset),
687                              "LS Update Packet");
688     ospf_lsa_upd_tree = proto_item_add_subtree(ti, ett_ospf_lsa_upd);
689
690     lsa_nr = tvb_get_ntohl(tvb, offset);
691     proto_tree_add_text(ospf_lsa_upd_tree, tvb, offset, 4, "Number of LSAs: %u",
692                         lsa_nr);
693     /* skip to the beginning of the first LSA */
694     offset += 4; /* the LS Upd Packet contains only a 32 bit #LSAs field */
695     
696     lsa_counter = 0;
697     while (lsa_counter < lsa_nr) {
698         if ( version == OSPF_VERSION_2)
699             offset = dissect_ospf_v2_lsa(tvb, offset, ospf_lsa_upd_tree, TRUE);
700         else
701             if ( version == OSPF_VERSION_3)
702                 offset = dissect_ospf_v3_lsa(tvb, offset, ospf_lsa_upd_tree, TRUE);
703         lsa_counter += 1;
704     }
705 }
706
707 static void
708 dissect_ospf_ls_ack(tvbuff_t *tvb, int offset, proto_tree *tree, guint8 version)
709 {
710     /* the body of a LS Ack packet simply contains zero or more LSA Headers */
711     while (tvb_reported_length_remaining(tvb, offset) != 0) {
712         if ( version == OSPF_VERSION_2)
713             offset = dissect_ospf_v2_lsa(tvb, offset, tree, FALSE);
714         else
715             if ( version == OSPF_VERSION_3)
716               offset = dissect_ospf_v3_lsa(tvb, offset, tree, FALSE);
717     }
718 }
719
720 /*
721  * Returns if an LSA is opaque, i.e. requires special treatment 
722  */
723 static int
724 is_opaque(int lsa_type)
725 {
726     return (lsa_type >= OSPF_LSTYPE_OP_LINKLOCAL &&
727         lsa_type <= OSPF_LSTYPE_OP_ASWIDE);
728 }
729
730 /* MPLS/TE TLV types */
731 #define MPLS_TLV_ROUTER    1
732 #define MPLS_TLV_LINK      2
733
734 /* MPLS/TE Link STLV types */
735 enum {
736     MPLS_LINK_TYPE       = 1,
737     MPLS_LINK_ID,
738     MPLS_LINK_LOCAL_IF,
739     MPLS_LINK_REMOTE_IF,
740     MPLS_LINK_TE_METRIC,
741     MPLS_LINK_MAX_BW,
742     MPLS_LINK_MAX_RES_BW,
743     MPLS_LINK_UNRES_BW,
744     MPLS_LINK_COLOR,
745 };
746
747 static const value_string mpls_link_stlv_str[] = {
748     {MPLS_LINK_TYPE, "Link Type"},
749     {MPLS_LINK_ID, "Link ID"},
750     {MPLS_LINK_LOCAL_IF, "Local Interface IP Address"},
751     {MPLS_LINK_REMOTE_IF, "Remote Interface IP Address"},
752     {MPLS_LINK_TE_METRIC, "Traffic Engineering Metric"},
753     {MPLS_LINK_MAX_BW, "Maximum Bandwidth"},
754     {MPLS_LINK_MAX_RES_BW, "Maximum Reservable Bandwidth"},
755     {MPLS_LINK_UNRES_BW, "Unreserved Bandwidth"},
756     {MPLS_LINK_COLOR, "Resource Class/Color"},
757     {0, NULL},
758 };
759
760 /* 
761  * Dissect MPLS/TE opaque LSA 
762  */
763 static void
764 dissect_ospf_lsa_mpls(tvbuff_t *tvb, int offset, proto_tree *tree,
765                       guint32 length)
766 {
767     proto_item *ti; 
768     proto_tree *mpls_tree;
769     proto_tree *tlv_tree;
770     proto_tree *stlv_tree;
771
772     int tlv_type;
773     int tlv_length;
774     int tlv_end_offset;
775
776     int stlv_type, stlv_len, stlv_offset;
777     char *stlv_name;
778     int i;
779
780     ti = proto_tree_add_text(tree, tvb, offset, length,
781                              "MPLS Traffic Engineering LSA");
782     mpls_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls);
783
784     while (length != 0) {
785         tlv_type = tvb_get_ntohs(tvb, offset);
786         tlv_length = tvb_get_ntohs(tvb, offset + 2);
787         tlv_end_offset = offset + tlv_length + 4;
788
789         switch (tlv_type) {
790
791         case MPLS_TLV_ROUTER:
792             ti = proto_tree_add_text(mpls_tree, tvb, offset, tlv_length+4,
793                                      "Router Address: %s", 
794                                      ip_to_str(tvb_get_ptr(tvb, offset+4, 4)));
795             tlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_router);
796             proto_tree_add_text(tlv_tree, tvb, offset, 2, "TLV Type: 1 - Router Address");
797             proto_tree_add_text(tlv_tree, tvb, offset+2, 2, "TLV Length: %u",
798                                 tlv_length);
799             proto_tree_add_text(tlv_tree, tvb, offset+4, 4, "Router Address: %s",
800                                 ip_to_str(tvb_get_ptr(tvb, offset+4, 4)));
801             break;
802
803         case MPLS_TLV_LINK:
804             ti = proto_tree_add_text(mpls_tree, tvb, offset, tlv_length+4,
805                                      "Link Information");
806             tlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link);
807             proto_tree_add_text(tlv_tree, tvb, offset, 2, "TLV Type: 2 - Link Information");
808             proto_tree_add_text(tlv_tree, tvb, offset+2, 2, "TLV Length: %u",
809                                 tlv_length);
810             stlv_offset = offset + 4;
811
812             /* Walk down the sub-TLVs for link information */
813             while (stlv_offset < tlv_end_offset) {
814                 stlv_type = tvb_get_ntohs(tvb, stlv_offset);
815                 stlv_len = tvb_get_ntohs(tvb, stlv_offset + 2);
816                 stlv_name = val_to_str(stlv_type, mpls_link_stlv_str, "Unknown sub-TLV");
817                 switch (stlv_type) {
818
819                 case MPLS_LINK_TYPE:
820                     ti = proto_tree_add_text(tlv_tree, tvb, stlv_offset, stlv_len+4,
821                                              "%s: %u", stlv_name,
822                                              tvb_get_guint8(tvb, stlv_offset + 4));
823                     stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
824                     proto_tree_add_text(stlv_tree, tvb, stlv_offset, 2,
825                                         "TLV Type: %u: %s", stlv_type, stlv_name);
826                     proto_tree_add_text(stlv_tree, tvb, stlv_offset+2, 2, "TLV Length: %u",
827                                         stlv_len);
828                     proto_tree_add_text(stlv_tree, tvb, stlv_offset+4, 1, "%s: %u", stlv_name,
829                                         tvb_get_guint8(tvb, stlv_offset + 4));
830                     break;
831
832                 case MPLS_LINK_ID:
833                     ti = proto_tree_add_text(tlv_tree, tvb, stlv_offset, stlv_len+4,
834                                              "%s: %s (%x)", stlv_name,
835                                              ip_to_str(tvb_get_ptr(tvb, stlv_offset + 4, 4)),
836                                              tvb_get_ntohl(tvb, stlv_offset + 4));
837                     stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
838                     proto_tree_add_text(stlv_tree, tvb, stlv_offset, 2,
839                                         "TLV Type: %u: %s", stlv_type, stlv_name);
840                     proto_tree_add_text(stlv_tree, tvb, stlv_offset+2, 2, "TLV Length: %u",
841                                         stlv_len);
842                     proto_tree_add_text(stlv_tree, tvb, stlv_offset+4, 4, "%s: %s (%x)", stlv_name,
843                                         ip_to_str(tvb_get_ptr(tvb, stlv_offset + 4, 4)),
844                                         tvb_get_ntohl(tvb, stlv_offset + 4));
845                     break;
846
847                 case MPLS_LINK_LOCAL_IF:
848                 case MPLS_LINK_REMOTE_IF:
849                     ti = proto_tree_add_text(tlv_tree, tvb, stlv_offset, stlv_len+4,
850                                              "%s", stlv_name);
851                     stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
852                     proto_tree_add_text(stlv_tree, tvb, stlv_offset, 2,
853                                         "TLV Type: %u: %s", stlv_type, stlv_name);
854                     proto_tree_add_text(stlv_tree, tvb, stlv_offset+2, 2, "TLV Length: %u",
855                                         stlv_len);
856                     /*   The Local/Remote Interface IP Address sub-TLV is TLV type 3/4, and is 4N
857                        octets in length, where N is the number of neighbor addresses. */
858                     for (i=0; i < stlv_len; i+=4)
859                       proto_tree_add_text(stlv_tree, tvb, stlv_offset+4+i, 4, "%s: %s", stlv_name,
860                                           ip_to_str(tvb_get_ptr(tvb, stlv_offset+4+i, 4)));
861                     break;
862
863                 case MPLS_LINK_TE_METRIC:
864                 case MPLS_LINK_COLOR:
865                     ti = proto_tree_add_text(tlv_tree, tvb, stlv_offset, stlv_len+4,
866                                              "%s: %u", stlv_name,
867                                              tvb_get_ntohl(tvb, stlv_offset + 4));
868                     stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
869                     proto_tree_add_text(stlv_tree, tvb, stlv_offset, 2,
870                                         "TLV Type: %u: %s", stlv_type, stlv_name);
871                     proto_tree_add_text(stlv_tree, tvb, stlv_offset+2, 2, "TLV Length: %u",
872                                         stlv_len);
873                     proto_tree_add_text(stlv_tree, tvb, stlv_offset+4, 4, "%s: %u", stlv_name,
874                                         tvb_get_ntohl(tvb, stlv_offset + 4));
875                     break;
876
877                 case MPLS_LINK_MAX_BW:
878                 case MPLS_LINK_MAX_RES_BW:
879                     ti = proto_tree_add_text(tlv_tree, tvb, stlv_offset, stlv_len+4,
880                                              "%s: %ld", stlv_name,
881                                              tvb_ieee_to_long(tvb, stlv_offset + 4));
882                     stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
883                     proto_tree_add_text(stlv_tree, tvb, stlv_offset, 2,
884                                         "TLV Type: %u: %s", stlv_type, stlv_name);
885                     proto_tree_add_text(stlv_tree, tvb, stlv_offset+2, 2, "TLV Length: %u",
886                                         stlv_len);
887                     proto_tree_add_text(stlv_tree, tvb, stlv_offset+4, 4, "%s: %ld", stlv_name,
888                                         tvb_ieee_to_long(tvb, stlv_offset + 4));
889                     break;
890
891                 case MPLS_LINK_UNRES_BW:
892                     ti = proto_tree_add_text(tlv_tree, tvb, stlv_offset, stlv_len+4,
893                                              "%s", stlv_name);
894                     stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
895                     proto_tree_add_text(stlv_tree, tvb, stlv_offset, 2,
896                                         "TLV Type: %u: %s", stlv_type, stlv_name);
897                     proto_tree_add_text(stlv_tree, tvb, stlv_offset+2, 2, "TLV Length: %u",
898                                         stlv_len);
899                     for (i = 0; i < 8; i++) {
900                         proto_tree_add_text(stlv_tree, tvb, stlv_offset+4+(i*4), 4,
901                                             "Pri %d: %ld", i,
902                                             tvb_ieee_to_long(tvb, stlv_offset + 4 + i*4));
903                     }
904                     break;
905
906                 default:
907                     proto_tree_add_text(tlv_tree, tvb, stlv_offset, stlv_len+4,
908                                         "Unknown Link sub-TLV: %u", stlv_type);
909                     break;
910                 }
911                 stlv_offset += ((stlv_len+4+3)/4)*4;
912             }
913             break;
914
915         default:
916             ti = proto_tree_add_text(mpls_tree, tvb, offset, tlv_length+4, 
917                                      "Unknown LSA: %u", tlv_type);
918             tlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link);
919             proto_tree_add_text(tlv_tree, tvb, offset, 2, "TLV Type: %u - Unknown",
920                                 tlv_type);
921             proto_tree_add_text(tlv_tree, tvb, offset+2, 2, "TLV Length: %u",
922                                 tlv_length);
923             proto_tree_add_text(tlv_tree, tvb, offset+4, tlv_length, "TLV Data");
924             break;
925         }
926
927         offset += tlv_length + 4;
928         length -= tlv_length + 4;
929     }
930 }
931
932 /*
933  * Dissect opaque LSAs
934  */
935 void
936 dissect_ospf_lsa_opaque(tvbuff_t *tvb, int offset, proto_tree *tree,
937                         guint8 ls_id_type, guint32 length)
938 {
939     switch (ls_id_type) {
940
941     case OSPF_LSA_MPLS_TE:
942         dissect_ospf_lsa_mpls(tvb, offset, tree, length);
943         break;
944
945     default:
946         proto_tree_add_text(tree, tvb, offset, length,
947                             "Unknown LSA Type %u", ls_id_type);
948         break;
949     } /* switch on opaque LSA id */
950 }
951
952 static int
953 dissect_ospf_v2_lsa(tvbuff_t *tvb, int offset, proto_tree *tree,
954                  gboolean disassemble_body)
955 {
956     proto_tree *ospf_lsa_tree;
957     proto_item *ti; 
958
959     guint8               ls_type;
960     guint16              ls_length;
961     int                  end_offset;
962     guint8               nr_links;
963     guint16              nr_tos;
964
965     /* router LSA */
966     guint8               link_type;
967     guint16              link_counter;
968     guint8               tos_counter;
969     char                *link_type_str;
970     char                *link_id;
971
972     /* AS-external LSA */
973     guint8               options;
974
975     /* opaque LSA */
976     guint8               ls_id_type;
977
978     ls_type = tvb_get_guint8(tvb, offset + 3);
979     ls_length = tvb_get_ntohs(tvb, offset + 18);
980     end_offset = offset + ls_length;
981
982     if (disassemble_body) {
983         ti = proto_tree_add_text(tree, tvb, offset, ls_length,
984                                  "%s (Type: %u)", val_to_str(ls_type, ls_type_vals,"Unkown"), ls_type); 
985     } else {
986         ti = proto_tree_add_text(tree, tvb, offset, OSPF_LSA_HEADER_LENGTH,
987                                  "LSA Header"); 
988     }
989     ospf_lsa_tree = proto_item_add_subtree(ti, ett_ospf_lsa);
990
991     proto_tree_add_text(ospf_lsa_tree, tvb, offset, 2, "LS Age: %u seconds",
992                         tvb_get_ntohs(tvb, offset));
993     dissect_ospf_options(tvb, offset + 2, ospf_lsa_tree, OSPF_VERSION_2);
994     proto_tree_add_text(ospf_lsa_tree, tvb, offset + 3, 1, "LSA Type: %u (%s)",
995                         ls_type, val_to_str(ls_type,ls_type_vals,"Unknown"));
996
997     if (is_opaque(ls_type)) {
998         ls_id_type = tvb_get_guint8(tvb, offset + 4);
999         proto_tree_add_text(ospf_lsa_tree, tvb, offset + 4, 1, "Link State ID Opaque Type: %u",
1000                             ls_id_type);
1001         proto_tree_add_text(ospf_lsa_tree, tvb, offset + 5, 3, "Link State ID Opaque ID: %u",
1002                             tvb_get_ntoh24(tvb, offset + 5));
1003     } else {
1004         ls_id_type = 0;
1005         proto_tree_add_text(ospf_lsa_tree, tvb, offset + 4, 4, "Link State ID: %s",
1006                             ip_to_str(tvb_get_ptr(tvb, offset + 4, 4)));
1007     }
1008
1009     proto_tree_add_text(ospf_lsa_tree, tvb, offset + 8, 4, "Advertising Router: %s",
1010                         ip_to_str(tvb_get_ptr(tvb, offset + 8, 4)));
1011     proto_tree_add_text(ospf_lsa_tree, tvb, offset + 12, 4, "LS Sequence Number: 0x%04x",
1012                         tvb_get_ntohl(tvb, offset + 12));
1013     proto_tree_add_text(ospf_lsa_tree, tvb, offset + 16, 2, "LS Checksum: %04x",
1014                         tvb_get_ntohs(tvb, offset + 16));
1015
1016     proto_tree_add_text(ospf_lsa_tree, tvb, offset + 18, 2, "Length: %u",
1017                         ls_length);
1018
1019     /* skip past the LSA header to the body */
1020     offset += OSPF_LSA_HEADER_LENGTH;
1021     ls_length -= OSPF_LSA_HEADER_LENGTH;
1022
1023     if (!disassemble_body)
1024         return offset;
1025
1026     switch (ls_type){
1027
1028     case OSPF_LSTYPE_ROUTER:
1029         /* again: flags should be secified in detail */
1030         proto_tree_add_text(ospf_lsa_tree, tvb, offset, 1, "Flags: 0x%02x",
1031                             tvb_get_guint8(tvb, offset));
1032         nr_links = tvb_get_ntohs(tvb, offset + 2);
1033         proto_tree_add_text(ospf_lsa_tree, tvb, offset + 2, 2, "Number of Links: %u",
1034                             nr_links);
1035         offset += 4;
1036         /* nr_links links follow 
1037          * maybe we should put each of the links into its own subtree ???
1038          */
1039         for (link_counter = 1; link_counter <= nr_links; link_counter++) {
1040             /* check the Link Type and ID */
1041             link_type = tvb_get_guint8(tvb, offset + 8);
1042             switch (link_type) {
1043
1044             case OSPF_LINK_PTP:
1045                 link_type_str="Point-to-point connection to another router";
1046                 link_id="Neighboring router's Router ID";
1047                 break;
1048
1049             case OSPF_LINK_TRANSIT:
1050                 link_type_str="Connection to a transit network";
1051                 link_id="IP address of Designated Router";
1052                 break;
1053
1054             case OSPF_LINK_STUB:
1055                 link_type_str="Connection to a stub network";
1056                 link_id="IP network/subnet number";
1057                 break;
1058
1059             case OSPF_LINK_VIRTUAL:
1060                 link_type_str="Virtual link";
1061                 link_id="Neighboring router's Router ID";
1062                 break;
1063
1064             default:
1065                 link_type_str="Unknown link type";
1066                 link_id="Unknown link ID";
1067                 break;
1068             }
1069
1070             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "%s: %s", link_id,
1071                                 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
1072
1073             /* link_data should be specified in detail (e.g. network mask) (depends on link type)*/
1074             proto_tree_add_text(ospf_lsa_tree, tvb, offset + 4, 4, "Link Data: %s",
1075                                 ip_to_str(tvb_get_ptr(tvb, offset + 4, 4)));
1076
1077             proto_tree_add_text(ospf_lsa_tree, tvb, offset + 8, 1, "Link Type: %u - %s",
1078                                 link_type, link_type_str);
1079             nr_tos = tvb_get_guint8(tvb, offset + 9);
1080             proto_tree_add_text(ospf_lsa_tree, tvb, offset + 9, 1, "Number of TOS metrics: %u",
1081                                 nr_tos);
1082             proto_tree_add_text(ospf_lsa_tree, tvb, offset + 10, 2, "TOS 0 metric: %u",
1083                                 tvb_get_ntohs(tvb, offset + 10));
1084
1085             offset += 12;
1086
1087             /* nr_tos metrics may follow each link 
1088              * ATTENTION: TOS metrics are not tested (I don't have TOS
1089              * based routing)
1090              * please send me a mail if it is/isn't working
1091              */
1092             for (tos_counter = 1; tos_counter <= nr_tos; tos_counter++) {
1093                 proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "TOS: %u, Metric: %u",
1094                                     tvb_get_guint8(tvb, offset),
1095                                     tvb_get_ntohs(tvb, offset + 2));
1096                 offset += 4;
1097             }
1098         }
1099         break;
1100
1101     case OSPF_LSTYPE_NETWORK:
1102         proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "Netmask: %s",
1103                                 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
1104         offset += 4;
1105
1106         while (offset < end_offset) {
1107             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "Attached Router: %s",
1108                                 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
1109             offset += 4;
1110         }
1111         break;
1112
1113     case OSPF_LSTYPE_SUMMERY:
1114     /* Type 3 and 4 LSAs have the same format */
1115     case OSPF_LSTYPE_ASBR:
1116         proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "Netmask: %s",
1117                             ip_to_str(tvb_get_ptr(tvb, offset, 4)));
1118         offset += 4;
1119
1120         proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "Metric: %u",
1121                             tvb_get_ntoh24(tvb, offset + 1));
1122         offset += 4;
1123
1124         /* TOS-specific information, if any */
1125         while (offset < end_offset) {
1126             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "TOS: %u, Metric: %u",
1127                                 tvb_get_guint8(tvb, offset),
1128                                 tvb_get_ntoh24(tvb, offset + 1));
1129             offset += 4;
1130         }
1131         break;
1132
1133     case OSPF_LSTYPE_ASEXT:
1134     case OSPF_LSTYPE_ASEXT7:
1135         proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "Netmask: %s", 
1136                             ip_to_str(tvb_get_ptr(tvb, offset, 4)));
1137         offset += 4;
1138
1139         options = tvb_get_guint8(tvb, offset);
1140         if (options & 0x80) { /* check wether or not E bit is set */
1141             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 1,
1142                     "External Type: Type 2 (metric is larger than any other link state path)");
1143         } else {
1144             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 1,
1145                     "External Type: Type 1 (metric is specified in the same units as interface cost)");
1146         }
1147         /* the metric field of a AS-external LAS is specified in 3 bytes */
1148         proto_tree_add_text(ospf_lsa_tree, tvb, offset + 1, 3, "Metric: %u",
1149                             tvb_get_ntoh24(tvb, offset + 1));
1150         offset += 4;
1151
1152         proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "Forwarding Address: %s", 
1153                             ip_to_str(tvb_get_ptr(tvb, offset, 4)));
1154         offset += 4;
1155
1156         proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "External Route Tag: %u",
1157                             tvb_get_ntohl(tvb, offset));
1158         offset += 4;
1159
1160         /* TOS-specific information, if any */
1161         while (offset < end_offset) {
1162             options = tvb_get_guint8(tvb, offset);
1163             if (options & 0x80) { /* check wether or not E bit is set */
1164                 proto_tree_add_text(ospf_lsa_tree, tvb, offset, 1,
1165                         "External Type: Type 2 (metric is larger than any other link state path)");
1166             } else {
1167                 proto_tree_add_text(ospf_lsa_tree, tvb, offset, 1,
1168                         "External Type: Type 1 (metric is specified in the same units as interface cost)");
1169             }
1170             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "TOS: %u, Metric: %u",
1171                                 options & 0x7F,
1172                                 tvb_get_ntoh24(tvb, offset + 1));
1173             offset += 4;
1174
1175             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "Forwarding Address: %s", 
1176                                 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
1177             offset += 4;
1178
1179             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "External Route Tag: %u",
1180                                 tvb_get_ntohl(tvb, offset));
1181             offset += 4;
1182         }
1183         break;
1184
1185     case OSPF_LSTYPE_OP_LINKLOCAL:
1186     case OSPF_LSTYPE_OP_AREALOCAL:
1187     case OSPF_LSTYPE_OP_ASWIDE:
1188         dissect_ospf_lsa_opaque(tvb, offset, ospf_lsa_tree, ls_id_type,
1189                                 ls_length);
1190         offset += ls_length;
1191         break;
1192
1193     default:
1194         /* unknown LSA type */
1195         proto_tree_add_text(ospf_lsa_tree, tvb, offset, ls_length,
1196                             "Unknown LSA Type");
1197         offset += ls_length;
1198         break;
1199     }
1200     /* return the offset of the next LSA */
1201     return offset;
1202 }
1203
1204 static int
1205 dissect_ospf_v3_lsa(tvbuff_t *tvb, int offset, proto_tree *tree,
1206                  gboolean disassemble_body)
1207 {
1208     proto_tree *ospf_lsa_tree;
1209     proto_item *ti; 
1210
1211     guint16              ls_type;
1212     guint16              ls_length;
1213     int                  end_offset;
1214     guint8               reserved;
1215
1216     /* router LSA */
1217     guint8               link_type;
1218     char                *link_type_str;
1219     guint32              metric;
1220
1221     guint8               router_lsa_flags;
1222     char                 router_lsa_flags_string[5];
1223
1224     guint8               router_priority;
1225     guint32              number_prefixes;
1226     guint8               prefix_length;
1227     guint16              reserved16;
1228
1229     guint16              referenced_ls_type;
1230
1231     guint8               flags;
1232     guint8               flags_string[4];
1233     guint32              external_route_tag;
1234
1235
1236     ls_type = tvb_get_ntohs(tvb, offset + 2);
1237     ls_length = tvb_get_ntohs(tvb, offset + 18);
1238     end_offset = offset + ls_length;
1239
1240     if (disassemble_body) {
1241         ti = proto_tree_add_text(tree, tvb, offset, ls_length,
1242                                  "%s (Type: 0x%04x)", val_to_str(ls_type, v3_ls_type_vals,"Unknown"), ls_type); 
1243     } else {
1244         ti = proto_tree_add_text(tree, tvb, offset, OSPF_LSA_HEADER_LENGTH,
1245                                  "LSA Header"); 
1246     }
1247     ospf_lsa_tree = proto_item_add_subtree(ti, ett_ospf_lsa);
1248
1249     proto_tree_add_text(ospf_lsa_tree, tvb, offset, 2, "LS Age: %u seconds",
1250                         tvb_get_ntohs(tvb, offset));
1251
1252     proto_tree_add_text(ospf_lsa_tree, tvb, offset + 2, 2, "LSA Type: 0x%04x (%s)",
1253                         ls_type, val_to_str(ls_type, v3_ls_type_vals,"Unkown"));
1254
1255     proto_tree_add_text(ospf_lsa_tree, tvb, offset + 4, 4, "Link State ID: %s",
1256                             ip_to_str(tvb_get_ptr(tvb, offset + 4, 4)));
1257
1258     proto_tree_add_text(ospf_lsa_tree, tvb, offset + 8, 4, "Advertising Router: %s",
1259                         ip_to_str(tvb_get_ptr(tvb, offset + 8, 4)));
1260     proto_tree_add_text(ospf_lsa_tree, tvb, offset + 12, 4, "LS Sequence Number: %d",
1261                         tvb_get_ntohl(tvb, offset + 12));
1262     proto_tree_add_text(ospf_lsa_tree, tvb, offset + 16, 2, "LS Checksum: %04x",
1263                         tvb_get_ntohs(tvb, offset + 16));
1264
1265     proto_tree_add_text(ospf_lsa_tree, tvb, offset + 18, 2, "Length: %u",
1266                         ls_length);
1267
1268     /* skip past the LSA header to the body */
1269     offset += OSPF_LSA_HEADER_LENGTH;
1270     ls_length -= OSPF_LSA_HEADER_LENGTH;
1271
1272     if (!disassemble_body)
1273         return offset;
1274
1275     switch (ls_type){
1276
1277
1278     case OSPF_V3_LSTYPE_ROUTER:
1279
1280       /* flags field in an router-lsa */
1281         router_lsa_flags=tvb_get_guint8(tvb,offset);
1282         if (router_lsa_flags & OSPF_V3_ROUTER_LSA_FLAG_B)
1283             router_lsa_flags_string[3] = 'B';
1284         else
1285             router_lsa_flags_string[3] = '.';
1286         if (router_lsa_flags & OSPF_V3_ROUTER_LSA_FLAG_E)
1287             router_lsa_flags_string[2] = 'E';
1288         else
1289             router_lsa_flags_string[2] = '.';
1290         if (router_lsa_flags & OSPF_V3_ROUTER_LSA_FLAG_V)
1291             router_lsa_flags_string[1] = 'V';
1292         else
1293             router_lsa_flags_string[1] = '.';
1294         if (router_lsa_flags & OSPF_V3_ROUTER_LSA_FLAG_W)
1295             router_lsa_flags_string[0] = 'W';
1296         else
1297             router_lsa_flags_string[0] = '.';
1298
1299         router_lsa_flags_string[4]=0;
1300
1301         proto_tree_add_text(ospf_lsa_tree, tvb, offset, 1, "Flags: 0x%02x (%s)",
1302                             router_lsa_flags, router_lsa_flags_string);
1303
1304         /* options field in an router-lsa */
1305         dissect_ospf_options(tvb, offset + 1, ospf_lsa_tree, OSPF_VERSION_3);
1306
1307         /* skip the router-lsa flags and options */
1308         offset+=4;
1309         ls_length-=4;
1310
1311         if (ls_length > 0)
1312              proto_tree_add_text(ospf_lsa_tree, tvb, offset, ls_length,
1313                    "Router Interfaces:"); 
1314
1315         /* scan all router-lsa router interfaces */
1316         /* maybe we should put each of the links into its own subtree ??? */
1317         while (ls_length > 0 ) {
1318
1319             /* check the type */
1320             link_type = tvb_get_guint8(tvb, offset);
1321             switch (link_type) {
1322
1323                 case OSPF_V3_LINK_PTP:
1324                     link_type_str="Point-to-point connection to another router";
1325                     break;
1326
1327                 case OSPF_V3_LINK_TRANSIT:
1328                     link_type_str="Connection to a transit network";
1329                     break;
1330
1331                 case OSPF_V3_LINK_RESERVED:
1332                     link_type_str="Connection to a stub network";
1333                     break;
1334
1335                 case OSPF_V3_LINK_VIRTUAL:
1336                     link_type_str="Virtual link";
1337                     break;
1338
1339                 default:
1340                     link_type_str="Unknown link type";
1341                     break;
1342             }
1343
1344             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 1, "Type: %u (%s)", link_type,link_type_str);
1345
1346             /* reserved field */
1347             reserved = tvb_get_guint8(tvb, offset+1);
1348             proto_tree_add_text(ospf_lsa_tree, tvb, offset+1, 1,
1349                (reserved == 0 ? "Reserved: %u" : "Reserved: %u (incorrect, should be 0)"),reserved);
1350
1351             /* metric */
1352             metric=tvb_get_ntohs(tvb, offset+2);
1353             proto_tree_add_text(ospf_lsa_tree, tvb, offset + 2, 2,"Metric: %u",metric);
1354
1355             /* Interface ID */
1356             proto_tree_add_text(ospf_lsa_tree, tvb, offset + 4, 4, "Interface ID: %u",
1357                         tvb_get_ntohl(tvb, offset + 4));
1358
1359             /* Neighbor Interface ID */
1360             proto_tree_add_text(ospf_lsa_tree, tvb, offset + 8, 4, "Neighbor Interface ID: %u",
1361                         tvb_get_ntohl(tvb, offset + 8));
1362
1363             /* Neighbor Router ID */
1364             proto_tree_add_text(ospf_lsa_tree, tvb, offset + 12, 4, "Neighbor Router ID: %s",
1365                 ip_to_str(tvb_get_ptr(tvb, offset + 12, 4)));
1366
1367             /* skip to the (possible) next entry */
1368             offset+=16;
1369             ls_length-=16;
1370
1371         }
1372         break;
1373
1374     case OSPF_V3_LSTYPE_NETWORK:
1375
1376         /* reserved field */
1377         reserved = tvb_get_guint8(tvb, offset);
1378         proto_tree_add_text(ospf_lsa_tree, tvb, offset, 1,
1379                (reserved == 0 ? "Reserved: %u" : "Reserved: %u (incorrect, should be 0)"),reserved);
1380
1381         /* options field in an network-lsa */
1382         dissect_ospf_options(tvb, offset + 1, ospf_lsa_tree, OSPF_VERSION_3);
1383
1384         offset += 4;
1385         ls_length-=4;
1386
1387         while (ls_length > 0 ) {
1388             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "Attached Router: %s",
1389                                 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
1390             ls_length-=4;
1391             offset += 4;
1392         }
1393         break;
1394
1395
1396     case OSPF_V3_LSTYPE_INTER_AREA_PREFIX:
1397
1398         /* reserved field */
1399         reserved = tvb_get_guint8(tvb, offset);
1400         proto_tree_add_text(ospf_lsa_tree, tvb, offset, 1,
1401                (reserved == 0 ? "Reserved: %u" : "Reserved: %u (incorrect, should be 0)"),reserved);
1402
1403         /* metric */
1404         metric=tvb_get_ntoh24(tvb, offset+11);
1405         proto_tree_add_text(ospf_lsa_tree, tvb, offset + 1, 3,"Metric: %u",metric);
1406
1407         /* prefix length */
1408         prefix_length=tvb_get_guint8(tvb, offset+4);
1409         proto_tree_add_text(ospf_lsa_tree, tvb, offset+4, 1, "PrefixLength: %u",prefix_length);
1410
1411         /* prefix options */
1412         dissect_ospf_v3_prefix_options(tvb, offset+5, ospf_lsa_tree);
1413
1414         /* 16 bits reserved */
1415         reserved16=tvb_get_ntohs(tvb, offset+6);
1416         proto_tree_add_text(ospf_lsa_tree, tvb, offset+6, 2,
1417                (reserved16 == 0 ? "Reserved: %u" : "Reserved: %u (incorrect, should be 0)"),reserved16);
1418
1419         offset+=8;
1420
1421         /* address_prefix */
1422         dissect_ospf_v3_address_prefix(tvb, offset, prefix_length, ospf_lsa_tree);
1423
1424         offset+=(prefix_length+31)/32*4;
1425
1426         break;
1427
1428
1429     case OSPF_V3_LSTYPE_INTER_AREA_ROUTER:
1430
1431         /* reserved field */
1432         reserved = tvb_get_guint8(tvb, offset);
1433         proto_tree_add_text(ospf_lsa_tree, tvb, offset, 1,
1434                (reserved == 0 ? "Reserved: %u" : "Reserved: %u (incorrect, should be 0)"),reserved);
1435
1436         /* options field in an inter-area-router-lsa */
1437         dissect_ospf_options(tvb, offset + 1, ospf_lsa_tree, OSPF_VERSION_3);
1438
1439         /* reserved field */
1440         reserved = tvb_get_guint8(tvb, offset+4);
1441         proto_tree_add_text(ospf_lsa_tree, tvb, offset+4, 1,
1442                (reserved == 0 ? "Reserved: %u" : "Reserved: %u (incorrect, should be 0)"),reserved);
1443
1444         /* metric */
1445         metric=tvb_get_ntoh24(tvb, offset+6);
1446         proto_tree_add_text(ospf_lsa_tree, tvb, offset + 6, 3,"Metric: %u",metric);
1447
1448         /* Destination Router ID */
1449         proto_tree_add_text(ospf_lsa_tree, tvb, offset + 8, 4, "Destination Router ID: %s",
1450                 ip_to_str(tvb_get_ptr(tvb, offset + 8, 4)));
1451
1452         offset+=12;
1453         break;
1454
1455
1456     case OSPF_V3_LSTYPE_AS_EXTERNAL:
1457
1458         /* flags */
1459         flags=tvb_get_guint8(tvb, offset);
1460         if (flags & OSPF_V3_AS_EXTERNAL_FLAG_E)
1461             flags_string[0] = 'E';
1462         else
1463             flags_string[0] = '.';
1464         if (flags & OSPF_V3_AS_EXTERNAL_FLAG_F)
1465             flags_string[1] = 'F';
1466         else
1467             flags_string[1] = '.';
1468         if (flags & OSPF_V3_AS_EXTERNAL_FLAG_T)
1469             flags_string[2] = 'T';
1470         else
1471             flags_string[2] = '.';
1472
1473         flags_string[3]=0;
1474
1475         proto_tree_add_text(ospf_lsa_tree, tvb, offset, 1, "Flags: 0x%02x (%s)",
1476                             flags, flags_string);
1477         
1478         /* 24 bits metric */
1479         metric=tvb_get_ntoh24(tvb, offset+1);
1480         proto_tree_add_text(ospf_lsa_tree, tvb, offset+1, 3,
1481                                 "Metric: %u", metric);
1482
1483         /* prefix length */
1484         prefix_length=tvb_get_guint8(tvb, offset+4);
1485         proto_tree_add_text(ospf_lsa_tree, tvb, offset+4, 1, "PrefixLength: %u",prefix_length);
1486
1487         /* prefix options */
1488         dissect_ospf_v3_prefix_options(tvb, offset+5, ospf_lsa_tree);
1489
1490         /* referenced LS type */
1491         referenced_ls_type=tvb_get_ntohs(tvb, offset+6);
1492         proto_tree_add_text(ospf_lsa_tree, tvb, offset+6, 2,"Referenced LS type 0x%04x (%s)",
1493                             referenced_ls_type, val_to_str(referenced_ls_type, v3_ls_type_vals, "Unknown"));
1494
1495         offset+=8;
1496
1497         /* address_prefix */
1498         dissect_ospf_v3_address_prefix(tvb, offset, prefix_length, ospf_lsa_tree);
1499        
1500         offset+=(prefix_length+31)/32*4;
1501
1502         /* Forwarding Address (optional - only if F-flag is on) */
1503         if ( (offset < end_offset) && (flags & OSPF_V3_AS_EXTERNAL_FLAG_F) ) {
1504             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 16,"Forwarding Address: %s",
1505               ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset, 16)));
1506
1507             offset+=16;
1508         }
1509
1510         /* External Route Tag (optional - only if T-flag is on) */
1511         if ( (offset < end_offset) && (flags & OSPF_V3_AS_EXTERNAL_FLAG_T) ) {
1512             external_route_tag=tvb_get_ntohl(tvb, offset);
1513             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4,"External Route Tag: 0x%04x",
1514                                 external_route_tag);
1515
1516             offset+=4;
1517         }
1518
1519         /* Referenced Link State ID (optional - only if Referenced LS type is non-zero */
1520         if ( (offset < end_offset) && (referenced_ls_type != 0) ) {
1521             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "Referenced Link State ID: %s", 
1522                             ip_to_str(tvb_get_ptr(tvb, offset, 4)));
1523             offset+=4;
1524         }
1525
1526         break;
1527
1528     case OSPF_V3_LSTYPE_LINK:
1529
1530         /* router priority */
1531         router_priority=tvb_get_guint8(tvb, offset);
1532         proto_tree_add_text(ospf_lsa_tree, tvb, offset, 1, "Router Priority: %u", router_priority);
1533
1534         /* options field in an link-lsa */
1535         dissect_ospf_options(tvb, offset + 1, ospf_lsa_tree, OSPF_VERSION_3);
1536
1537         /* Link-local Interface Address */
1538         proto_tree_add_text(ospf_lsa_tree, tvb, offset + 4, 16, "Link-local Interface Address: %s",
1539            ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset + 4, 16)));
1540
1541         /* Number prefixes */
1542         number_prefixes=tvb_get_ntohl(tvb, offset + 20);
1543         proto_tree_add_text(ospf_lsa_tree, tvb, offset+20, 4, "# prefixes: %d",number_prefixes);
1544
1545         offset+=24;
1546
1547         while (number_prefixes > 0) {
1548
1549             /* prefix length */
1550             prefix_length=tvb_get_guint8(tvb, offset);
1551             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 1, "PrefixLength: %u",prefix_length);
1552
1553             /* prefix options */
1554             dissect_ospf_v3_prefix_options(tvb, offset+1, ospf_lsa_tree);
1555
1556             /* 16 bits reserved */
1557             reserved16=tvb_get_ntohs(tvb, offset+2);
1558             proto_tree_add_text(ospf_lsa_tree, tvb, offset+2, 2,
1559                (reserved16 == 0 ? "Reserved: %u" : "Reserved: %u (incorrect, should be 0)"),reserved16);
1560
1561             offset+=4;
1562
1563             /* address_prefix */
1564             dissect_ospf_v3_address_prefix(tvb, offset, prefix_length, ospf_lsa_tree);
1565        
1566             offset+=(prefix_length+31)/32*4;
1567
1568             number_prefixes--;
1569
1570         }             
1571         break;
1572
1573     case OSPF_V3_LSTYPE_INTRA_AREA_PREFIX:
1574
1575         /* # prefixes */
1576         number_prefixes=tvb_get_ntohs(tvb, offset);
1577         proto_tree_add_text(ospf_lsa_tree, tvb, offset, 2,"# prefixes: %u",number_prefixes);
1578
1579         /* referenced LS type */
1580         referenced_ls_type=tvb_get_ntohs(tvb, offset+2);
1581         proto_tree_add_text(ospf_lsa_tree, tvb, offset+2, 2,"Referenced LS type 0x%04x (%s)",
1582                             referenced_ls_type, val_to_str(referenced_ls_type, v3_ls_type_vals, "Unknown"));
1583
1584         /* Referenced Link State ID */
1585         proto_tree_add_text(ospf_lsa_tree, tvb, offset + 4, 4, "Referenced Link State ID: %s", 
1586                             ip_to_str(tvb_get_ptr(tvb, offset + 4, 4)));
1587
1588         /* Referenced Advertising Router */
1589         proto_tree_add_text(ospf_lsa_tree, tvb, offset + 8, 4, "Referenced Advertising Router: %s", 
1590                             ip_to_str(tvb_get_ptr(tvb, offset + 8, 4)));
1591
1592         offset+=12;
1593
1594         while (number_prefixes > 0) {
1595
1596             /* prefix length */
1597             prefix_length=tvb_get_guint8(tvb, offset);
1598             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 1, "PrefixLength: %u",prefix_length);
1599
1600             /* prefix options */
1601             dissect_ospf_v3_prefix_options(tvb, offset+1, ospf_lsa_tree);
1602
1603             /* 16 bits metric */
1604             metric=tvb_get_ntohs(tvb, offset+2);
1605             proto_tree_add_text(ospf_lsa_tree, tvb, offset+2, 2,
1606                                 "Metric: %u", metric);
1607
1608             offset+=4;
1609
1610             /* address_prefix */
1611             dissect_ospf_v3_address_prefix(tvb, offset, prefix_length, ospf_lsa_tree);
1612        
1613             offset+=(prefix_length+31)/32*4;
1614
1615             number_prefixes--;
1616         }
1617         break;
1618
1619     default:
1620         /* unknown LSA type */
1621         proto_tree_add_text(ospf_lsa_tree, tvb, offset, ls_length,
1622                             "Unknown LSA Type 0x%04x",ls_type);
1623         offset += ls_length;
1624         break;
1625     }
1626     /* return the offset of the next LSA */
1627     return offset;
1628 }
1629
1630
1631 static void
1632 dissect_ospf_options(tvbuff_t *tvb, int offset, proto_tree *tree, guint8 version)
1633 {
1634     guint8 options_ospfv2;
1635     guint32 options_ospfv3;
1636     char options_string[20] = "";
1637
1638     /* ATTENTION !!! no check for length of options string  - with OSPFv3 maximum length is 14 characters */
1639
1640     switch ( version ) {
1641
1642         case OSPF_VERSION_2:
1643
1644             options_ospfv2 = tvb_get_guint8(tvb, offset);
1645
1646             if (options_ospfv2 & OSPF_V2_OPTIONS_E)
1647                 strcat(options_string, "E");
1648
1649             if (options_ospfv2 & OSPF_V2_OPTIONS_MC) {
1650                 if (options_string[0] != '\0')
1651                     strcat(options_string, "/");
1652                 strcat(options_string, "MC");
1653             }
1654
1655             if (options_ospfv2 & OSPF_V2_OPTIONS_NP) {
1656                 if (options_string[0] != '\0')
1657                     strcat(options_string, "/");
1658                 strcat(options_string, "NP");
1659             }
1660
1661             if (options_ospfv2 & OSPF_V2_OPTIONS_EA) {
1662                 if (options_string[0] != '\0')
1663                     strcat(options_string, "/");
1664                 strcat(options_string, "EA");
1665             }
1666
1667             if (options_ospfv2 & OSPF_V2_OPTIONS_DC) {
1668                 if (options_string[0] != '\0')
1669                     strcat(options_string, "/");
1670                 strcat(options_string, "DC");
1671             }
1672
1673             if (options_ospfv2 & OSPF_V2_OPTIONS_O) {
1674                 if (options_string[0] != '\0')
1675                     strcat(options_string, "/");
1676                 strcat(options_string, "O");
1677             }
1678
1679             if (options_ospfv2 & OSPF_V2_OPTIONS_DN) {
1680                 if (options_string[0] != '\0')
1681                     strcat(options_string, "/");
1682                 strcat(options_string, "DN");  
1683             }
1684
1685             proto_tree_add_text(tree, tvb, offset, 1, "Options: 0x%x (%s)",
1686                         options_ospfv2, options_string);
1687             break;
1688
1689
1690         case OSPF_VERSION_3:
1691
1692             options_ospfv3 = tvb_get_ntoh24(tvb, offset);
1693
1694             if (options_ospfv3 & OSPF_V3_OPTIONS_V6)
1695                 strcat(options_string, "V6");
1696
1697             if (options_ospfv3 & OSPF_V3_OPTIONS_E)
1698                 if (options_string[0] != '\0')
1699                     strcat(options_string, "/");
1700                 strcat(options_string, "E");
1701
1702             if (options_ospfv3 & OSPF_V3_OPTIONS_MC) {
1703                 if (options_string[0] != '\0')
1704                     strcat(options_string, "/");
1705                 strcat(options_string, "MC");
1706             }
1707
1708             if (options_ospfv3 & OSPF_V3_OPTIONS_N) {
1709                 if (options_string[0] != '\0')
1710                     strcat(options_string, "/");
1711                 strcat(options_string, "N");
1712             }
1713
1714             if (options_ospfv3 & OSPF_V3_OPTIONS_R) {
1715                 if (options_string[0] != '\0')
1716                     strcat(options_string, "/");
1717                 strcat(options_string, "R");
1718             }
1719
1720             if (options_ospfv3 & OSPF_V3_OPTIONS_DC) {
1721                 if (options_string[0] != '\0')
1722                     strcat(options_string, "/");
1723                 strcat(options_string, "DC");
1724             }
1725
1726             proto_tree_add_text(tree, tvb, offset, 3, "Options: 0x%x (%s)",
1727                         options_ospfv3, options_string);
1728             break;
1729
1730         default:
1731             break;
1732     }
1733
1734 }
1735
1736
1737 static void dissect_ospf_v3_prefix_options(tvbuff_t *tvb, int offset, proto_tree *tree)
1738 {
1739
1740     guint8 prefix_options;
1741     char prefix_options_string[11];
1742     guint8 position;
1743
1744     position=0;
1745     
1746     prefix_options=tvb_get_guint8(tvb, offset);
1747
1748     strcpy(prefix_options_string,"");
1749
1750     if (prefix_options & OSPF_V3_PREFIX_OPTION_P) {
1751         strcat(prefix_options_string, "P");
1752         position++;
1753     }
1754
1755     if (prefix_options & OSPF_V3_PREFIX_OPTION_MC) {
1756         if ( (position > 0) && (prefix_options_string[position-1] != '/') ) {
1757             strcat(prefix_options_string, "/");
1758             position++;
1759         }
1760         strcat(prefix_options_string, "MC");
1761         position+=2;
1762     }
1763
1764     if (prefix_options & OSPF_V3_PREFIX_OPTION_LA) {
1765         if ( (position > 0) && (prefix_options_string[position-1] != '/') ) {
1766             strcat(prefix_options_string, "/");
1767             position++;
1768         }
1769         strcat(prefix_options_string, "LA");
1770         position+=2;
1771     }
1772
1773     if (prefix_options & OSPF_V3_PREFIX_OPTION_NU) {
1774         if ( (position > 0) && (prefix_options_string[position-1] != '/') ) {
1775             strcat(prefix_options_string, "/");
1776             position++;
1777         }
1778         strcat(prefix_options_string, "NU");
1779     }
1780
1781     prefix_options_string[10]=0;
1782
1783     proto_tree_add_text(tree, tvb, offset, 1, "PrefixOptions: 0x%02x (%s)",prefix_options, prefix_options_string);
1784
1785 }
1786
1787
1788 static void dissect_ospf_v3_address_prefix(tvbuff_t *tvb, int offset, int prefix_length, proto_tree *tree)
1789 {
1790
1791     guint8 value;
1792     guint8 position;
1793     guint8 bufpos;
1794     gchar  buffer[32+7];
1795     gchar  bytebuf[3];
1796     guint8 bytes_to_process;
1797     int start_offset;
1798
1799     start_offset=offset;
1800     position=0;
1801     bufpos=0;
1802     bytes_to_process=((prefix_length+31)/32)*4;
1803
1804     while (bytes_to_process > 0 ) {
1805
1806         value=tvb_get_guint8(tvb, offset);
1807
1808         if ( (position > 0) && ( (position%2) == 0 ) )
1809             buffer[bufpos++]=':';
1810
1811         sprintf(bytebuf,"%02x",value);
1812         buffer[bufpos++]=bytebuf[0];        
1813         buffer[bufpos++]=bytebuf[1];        
1814         
1815         position++;
1816         offset++;
1817         bytes_to_process--;
1818     }
1819
1820     buffer[bufpos]=0;  
1821     proto_tree_add_text(tree, tvb, start_offset, ((prefix_length+31)/32)*4, "Address Prefix: %s",buffer);
1822
1823 }
1824
1825
1826 void
1827 proto_register_ospf(void)
1828 {
1829 /*        static hf_register_info hf[] = {
1830                 { &variable,
1831                 { "Name",           "ospf.abbreviation", TYPE, VALS_POINTER }},
1832         };*/
1833     static gint *ett[] = {
1834         &ett_ospf,
1835         &ett_ospf_hdr,
1836         &ett_ospf_hello,
1837         &ett_ospf_desc,
1838         &ett_ospf_lsr,
1839         &ett_ospf_lsa,
1840         &ett_ospf_lsa_upd,
1841         &ett_ospf_lsa_mpls,
1842         &ett_ospf_lsa_mpls_router,
1843         &ett_ospf_lsa_mpls_link,
1844         &ett_ospf_lsa_mpls_link_stlv
1845     };
1846
1847     proto_ospf = proto_register_protocol("Open Shortest Path First",
1848                                          "OSPF", "ospf");
1849  /*       proto_register_field_array(proto_ospf, hf, array_length(hf));*/
1850     proto_register_subtree_array(ett, array_length(ett));
1851 }
1852
1853 void
1854 proto_reg_handoff_ospf(void)
1855 {
1856     dissector_handle_t ospf_handle;
1857
1858     ospf_handle = create_dissector_handle(dissect_ospf, proto_ospf);
1859     dissector_add("ip.proto", IP_PROTO_OSPF, ospf_handle);
1860     data_handle = find_dissector("data");
1861 }