Add a new "prefs_register_protocol()" routine, which is like
[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.33 2001/01/03 06:55:30 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  *
12  * TOS - support is not fully implemented
13  * 
14  * Ethereal - Network traffic analyzer
15  * By Gerald Combs <gerald@zing.org>
16  * Copyright 1998 Gerald Combs
17  * 
18  * 
19  * This program is free software; you can redistribute it and/or
20  * modify it under the terms of the GNU General Public License
21  * as published by the Free Software Foundation; either version 2
22  * of the License, or (at your option) any later version.
23  * 
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  * GNU General Public License for more details.
28  * 
29  * You should have received a copy of the GNU General Public License
30  * along with this program; if not, write to the Free Software
31  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
32  */
33  
34 #ifdef HAVE_CONFIG_H
35 # include "config.h"
36 #endif
37
38 #ifdef HAVE_SYS_TYPES_H
39 # include <sys/types.h>
40 #endif
41
42 #ifdef HAVE_NETINET_IN_H
43 # include <netinet/in.h>
44 #endif
45
46 #include <stdio.h>
47 #include <string.h>
48
49 #include <glib.h>
50 #include "packet.h"
51 #include "packet-ip.h"
52 #include "in_cksum.h"
53 #include "ieee-float.h"
54
55 #define OSPF_HEADER_LENGTH      24
56
57 #define OSPF_HELLO      1
58 #define OSPF_DB_DESC    2
59 #define OSPF_LS_REQ     3
60 #define OSPF_LS_UPD     4
61 #define OSPF_LS_ACK     5
62
63 static const value_string pt_vals[] = {
64         {OSPF_HELLO,   "Hello Packet"   },
65         {OSPF_DB_DESC, "DB Descr."      },
66         {OSPF_LS_REQ,  "LS Request"     },
67         {OSPF_LS_UPD,  "LS Update"      },
68         {OSPF_LS_ACK,  "LS Acknowledge" },
69         {0,             NULL            }
70 };
71
72 #define OSPF_AUTH_NONE          0
73 #define OSPF_AUTH_SIMPLE        1
74 #define OSPF_AUTH_CRYPT         2
75
76 static const value_string auth_vals[] = {
77         {OSPF_AUTH_NONE,   "Null"            },
78         {OSPF_AUTH_SIMPLE, "Simple password" },
79         {OSPF_AUTH_CRYPT,  "Cryptographic"   },
80         {0,                NULL              }
81 };
82
83 #define OSPF_OPTIONS_E          0x02
84 #define OSPF_OPTIONS_MC         0x04
85 #define OSPF_OPTIONS_NP         0x08
86 #define OSPF_OPTIONS_EA         0x10
87 #define OSPF_OPTIONS_DC         0x20
88
89 #define OSPF_DBD_FLAG_MS        1
90 #define OSPF_DBD_FLAG_M         2
91 #define OSPF_DBD_FLAG_I         4
92
93 #define OSPF_LS_REQ_LENGTH      12
94
95 #define OSPF_LSTYPE_ROUTER      1
96 #define OSPF_LSTYPE_NETWORK     2
97 #define OSPF_LSTYPE_SUMMERY     3
98 #define OSPF_LSTYPE_ASBR        4
99 #define OSPF_LSTYPE_ASEXT       5
100 #define OSPF_LSTYPE_ASEXT7      7
101
102 /* Opaque LSA types */
103 #define OSPF_LSTYPE_OP_LINKLOCAL 9
104 #define OSPF_LSTYPE_OP_AREALOCAL 10
105 #define OSPF_LSTYPE_OP_ASWIDE    11
106
107 #define OSPF_LINK_PTP           1
108 #define OSPF_LINK_TRANSIT       2
109 #define OSPF_LINK_STUB          3
110 #define OSPF_LINK_VIRTUAL       4
111
112 #define OSPF_LSA_HEADER_LENGTH  20
113
114 /* Known opaque LSAs */
115 #define OSPF_LSA_MPLS_TE        1
116
117 static const value_string ls_type_vals[] = {
118         {OSPF_LSTYPE_ROUTER,  "Router-LSA"               },
119         {OSPF_LSTYPE_NETWORK, "Network-LSA"              },
120         {OSPF_LSTYPE_SUMMERY, "Summary-LSA (IP network)" },
121         {OSPF_LSTYPE_ASBR,    "Summary-LSA (ASBR)"       },
122         {OSPF_LSTYPE_ASEXT,   "AS-External-LSA (ASBR)"   },
123         {0,                    NULL                      }
124 };
125
126 static int proto_ospf = -1;
127
128 static gint ett_ospf = -1;
129 static gint ett_ospf_hdr = -1;
130 static gint ett_ospf_hello = -1;
131 static gint ett_ospf_desc = -1;
132 static gint ett_ospf_lsr = -1;
133 static gint ett_ospf_lsa = -1;
134 static gint ett_ospf_lsa_upd = -1;
135
136 /* Trees for opaque LSAs */
137 static gint ett_ospf_lsa_mpls = -1;
138 static gint ett_ospf_lsa_mpls_router = -1;
139 static gint ett_ospf_lsa_mpls_link = -1;
140 static gint ett_ospf_lsa_mpls_link_stlv = -1;
141
142 static void dissect_ospf_hello(tvbuff_t*, int, proto_tree*);
143 static void dissect_ospf_db_desc(tvbuff_t*, int, proto_tree*); 
144 static void dissect_ospf_ls_req(tvbuff_t*, int, proto_tree*); 
145 static void dissect_ospf_ls_upd(tvbuff_t*, int, proto_tree*); 
146 static void dissect_ospf_ls_ack(tvbuff_t*, int, proto_tree*); 
147
148 /* dissect_ospf_lsa returns the offset of the next LSA
149  * if disassemble_body is set to FALSE (e.g. in LSA ACK 
150  * packets), the offset is set to the offset of the next
151  * LSA header
152  */
153 static int dissect_ospf_lsa(tvbuff_t*, int, proto_tree*, gboolean disassemble_body); 
154
155 static void dissect_ospf_options(tvbuff_t *, int, proto_tree *);
156
157 static void 
158 dissect_ospf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
159 {
160     proto_tree *ospf_tree = NULL;
161     proto_item *ti; 
162     proto_tree *ospf_header_tree;
163     guint8  version;
164     guint8  packet_type;
165     guint16 ospflen;
166     vec_t cksum_vec[2];
167     int cksum_vec_len;
168     guint16 cksum, computed_cksum;
169     guint length, reported_length;
170     guint16 auth_type;
171     char auth_data[8];
172     int crypto_len;
173  
174     CHECK_DISPLAY_AS_DATA(proto_ospf, tvb, pinfo, tree);
175
176     pinfo->current_proto = "OSPF";
177
178     version = tvb_get_guint8(tvb, 0);
179     packet_type = tvb_get_guint8(tvb, 1);
180     if (check_col(pinfo->fd, COL_PROTOCOL))
181         col_set_str(pinfo->fd, COL_PROTOCOL, "OSPF");
182     if (check_col(pinfo->fd, COL_INFO)) {
183         col_add_str(pinfo->fd, COL_INFO,
184                     val_to_str(packet_type, pt_vals, "Unknown (%u)"));
185     }  
186
187     if (tree) {
188         ospflen = tvb_get_ntohs(tvb, 2);
189
190         ti = proto_tree_add_item(tree, proto_ospf, tvb, 0, ospflen, FALSE);
191         ospf_tree = proto_item_add_subtree(ti, ett_ospf);
192
193         ti = proto_tree_add_text(ospf_tree, tvb, 0, OSPF_HEADER_LENGTH,
194                                  "OSPF Header"); 
195         ospf_header_tree = proto_item_add_subtree(ti, ett_ospf_hdr);
196
197         proto_tree_add_text(ospf_header_tree, tvb, 0, 1, "OSPF Version: %u",
198                             version);  
199         proto_tree_add_text(ospf_header_tree, tvb, 1, 1, "OSPF Packet Type: %u (%s)",
200                             packet_type,
201                             val_to_str(packet_type, pt_vals, "Unknown"));
202         proto_tree_add_text(ospf_header_tree, tvb, 2, 2, "Packet Length: %u",
203                             ospflen);
204         proto_tree_add_text(ospf_header_tree, tvb, 4, 4, "Source OSPF Router ID: %s",
205                             ip_to_str(tvb_get_ptr(tvb, 4, 4)));
206         if (tvb_get_ntohl(tvb, 8) == 0) {
207            proto_tree_add_text(ospf_header_tree, tvb, 8, 4, "Area ID: Backbone");
208         } else {
209            proto_tree_add_text(ospf_header_tree, tvb, 8, 4, "Area ID: %s",
210                                ip_to_str(tvb_get_ptr(tvb, 8, 4)));
211         }
212         cksum = tvb_get_ntohs(tvb, 12);
213         length = tvb_length(tvb);
214         /* XXX - include only the length from the OSPF header? */
215         reported_length = tvb_reported_length(tvb);
216         if (!pi.fragmented && length >= reported_length
217                 && length >= OSPF_HEADER_LENGTH) {
218             /* The packet isn't part of a fragmented datagram and isn't
219                truncated, so we can checksum it. */
220
221             /* Header, not including the authentication data (the OSPF
222                checksum excludes the 64-bit authentication field). */
223             cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, 16);
224             cksum_vec[0].len = 16;
225             if (length > OSPF_HEADER_LENGTH) {
226                 /* Rest of the packet, again not including the
227                    authentication data. */
228                 reported_length -= OSPF_HEADER_LENGTH;
229                 cksum_vec[1].ptr = tvb_get_ptr(tvb, OSPF_HEADER_LENGTH, reported_length);
230                 cksum_vec[1].len = reported_length;
231                 cksum_vec_len = 2;
232             } else {
233                 /* There's nothing but a header. */
234                 cksum_vec_len = 1;
235             }
236             computed_cksum = in_cksum(cksum_vec, cksum_vec_len);
237             if (computed_cksum == 0) {
238                 proto_tree_add_text(ospf_header_tree, tvb, 12, 2,
239                         "Packet Checksum: 0x%04x (correct)", cksum);
240             } else {
241                 proto_tree_add_text(ospf_header_tree, tvb, 12, 2,
242                         "Packet Checksum: 0x%04x (incorrect, should be 0x%04x)",
243                         cksum, in_cksum_shouldbe(cksum, computed_cksum));
244             }
245         } else {
246             proto_tree_add_text(ospf_header_tree, tvb, 12, 2,
247                 "Packet Checksum: 0x%04x", cksum);
248         }
249         auth_type = tvb_get_ntohs(tvb, 14);
250         proto_tree_add_text(ospf_header_tree, tvb, 14, 2, "Auth Type: %s",
251                             val_to_str(auth_type, auth_vals, "Unknown (%u)"));
252         switch (auth_type) {
253
254         case OSPF_AUTH_NONE:
255             proto_tree_add_text(ospf_header_tree, tvb, 16, 8, "Auth Data (none)");
256             break;
257
258         case OSPF_AUTH_SIMPLE:
259             tvb_get_nstringz0(tvb, 16, 8, auth_data);
260             proto_tree_add_text(ospf_header_tree, tvb, 16, 8, "Auth Data: %s", auth_data);
261             break;
262
263         case OSPF_AUTH_CRYPT:
264             proto_tree_add_text(ospf_header_tree, tvb, 18, 1, "Auth Key ID: %u",
265                                 tvb_get_guint8(tvb, 18));
266             crypto_len = tvb_get_guint8(tvb, 19);
267             proto_tree_add_text(ospf_header_tree, tvb, 19, 1, "Auth Data Length: %u",
268                                 crypto_len);
269             proto_tree_add_text(ospf_header_tree, tvb, 20, 4, "Auth Crypto Sequence Number: 0x%x",
270                                 tvb_get_ntohl(tvb, 20));
271   
272             /* Show the message digest that was appended to the end of the
273                OSPF message - but only if it's present (we don't want
274                to get an exception before we've tried dissecting OSPF
275                message). */
276             if (tvb_bytes_exist(tvb, ospflen, crypto_len)) {
277                 proto_tree_add_text(ospf_header_tree, tvb, ospflen, crypto_len,
278                                     "Auth Data: %s",
279                                     tvb_bytes_to_str(tvb, ospflen, crypto_len));
280             }
281             break;
282
283         default:
284             proto_tree_add_text(ospf_header_tree, tvb, 16, 8, "Auth Data (unknown)");
285             break;
286         }
287
288         /* Adjust the length of the tvbuff to match the size of the OSPF
289          * packet (since the dissect routines use it to work out where the
290          * end of the OSPF packet is).
291          */
292         tvb_set_reported_length(tvb, ospflen);
293
294         switch (packet_type){
295
296         case OSPF_HELLO:
297             dissect_ospf_hello(tvb, OSPF_HEADER_LENGTH, ospf_tree);
298             break;
299
300         case OSPF_DB_DESC:
301             dissect_ospf_db_desc(tvb, OSPF_HEADER_LENGTH, ospf_tree);
302             break;
303
304         case OSPF_LS_REQ:
305             dissect_ospf_ls_req(tvb, OSPF_HEADER_LENGTH, ospf_tree);
306             break;
307
308         case OSPF_LS_UPD:
309             dissect_ospf_ls_upd(tvb, OSPF_HEADER_LENGTH, ospf_tree);
310             break;
311
312         case OSPF_LS_ACK:
313             dissect_ospf_ls_ack(tvb, OSPF_HEADER_LENGTH, ospf_tree);
314             break;
315
316         default:
317             dissect_data(tvb, OSPF_HEADER_LENGTH, pinfo, tree);
318             break;
319         }
320     }
321 }
322
323 static void
324 dissect_ospf_hello(tvbuff_t *tvb, int offset, proto_tree *tree)
325 {
326     proto_tree *ospf_hello_tree;
327     proto_item *ti; 
328
329     ti = proto_tree_add_text(tree, tvb, offset,
330                              tvb_length_remaining(tvb, offset),
331                              "OSPF Hello Packet");
332     ospf_hello_tree = proto_item_add_subtree(ti, ett_ospf_hello);
333
334     proto_tree_add_text(ospf_hello_tree, tvb, offset, 4, "Network Mask: %s",
335                         ip_to_str(tvb_get_ptr(tvb, offset, 4)));
336     proto_tree_add_text(ospf_hello_tree, tvb, offset + 4, 2,
337                         "Hello Interval: %u seconds",
338                         tvb_get_ntohs(tvb, offset + 4));
339
340     dissect_ospf_options(tvb, offset + 6, ospf_hello_tree);
341     proto_tree_add_text(ospf_hello_tree, tvb, offset + 7, 1, "Router Priority: %u",
342                         tvb_get_guint8(tvb, offset + 7));
343     proto_tree_add_text(ospf_hello_tree, tvb, offset + 8, 4, "Router Dead Interval: %u seconds",
344                         tvb_get_ntohl(tvb, offset + 8));
345     proto_tree_add_text(ospf_hello_tree, tvb, offset + 12, 4, "Designated Router: %s",
346                         ip_to_str(tvb_get_ptr(tvb, offset + 12, 4)));
347     proto_tree_add_text(ospf_hello_tree, tvb, offset + 16, 4, "Backup Designated Router: %s",
348                         ip_to_str(tvb_get_ptr(tvb, offset + 16, 4)));
349
350     offset += 20;
351     while (tvb_reported_length_remaining(tvb, offset) != 0) {
352         proto_tree_add_text(ospf_hello_tree, tvb, offset, 4,
353                             "Active Neighbor: %s",
354                             ip_to_str(tvb_get_ptr(tvb, offset, 4)));
355         offset += 4;
356     }
357 }
358
359 static void
360 dissect_ospf_db_desc(tvbuff_t *tvb, int offset, proto_tree *tree)
361 {
362     proto_tree *ospf_db_desc_tree=NULL;
363     proto_item *ti; 
364     guint8 flags;
365     char flags_string[20] = "";
366
367     if (tree) {
368         ti = proto_tree_add_text(tree, tvb, offset,
369                                  tvb_length_remaining(tvb, offset),
370                                  "OSPF DB Description"); 
371         ospf_db_desc_tree = proto_item_add_subtree(ti, ett_ospf_desc);
372
373         proto_tree_add_text(ospf_db_desc_tree, tvb, offset, 2, "Interface MTU: %u",
374                             tvb_get_ntohs(tvb, offset));
375
376         dissect_ospf_options(tvb, offset + 2, ospf_db_desc_tree);
377
378         flags = tvb_get_guint8(tvb, offset + 3);
379         if (flags & OSPF_DBD_FLAG_MS)
380             strcat(flags_string, "MS");
381         if (flags & OSPF_DBD_FLAG_M) {
382             if (flags_string[0] != '\0')
383                 strcat(flags_string, "/");
384             strcat(flags_string, "M");
385         }
386         if (flags & OSPF_DBD_FLAG_I) {
387             if (flags_string[0] != '\0')
388                 strcat(flags_string, "/");
389             strcat(flags_string, "I");
390         }
391         proto_tree_add_text(ospf_db_desc_tree, tvb, offset + 3, 1, "Flags: 0x%x (%s)",
392                             flags, flags_string);
393         proto_tree_add_text(ospf_db_desc_tree, tvb, offset + 4, 4, "DD Sequence: %u",
394                             tvb_get_ntohl(tvb, offset + 4));
395     }
396
397     /* LS Headers will be processed here */
398     /* skip to the end of DB-Desc header */
399     offset += 8;
400     while (tvb_reported_length_remaining(tvb, offset) != 0)
401         offset = dissect_ospf_lsa(tvb, offset, tree, FALSE);
402 }
403
404 static void
405 dissect_ospf_ls_req(tvbuff_t *tvb, int offset, proto_tree *tree)
406 {
407     proto_tree *ospf_lsr_tree;
408     proto_item *ti;
409     guint32 ls_type;
410
411     /* zero or more LS requests may be within a LS Request */
412     /* we place every request for a LSA in a single subtree */
413     while (tvb_reported_length_remaining(tvb, offset) != 0) {
414         ti = proto_tree_add_text(tree, tvb, offset, OSPF_LS_REQ_LENGTH,
415                                  "Link State Request"); 
416         ospf_lsr_tree = proto_item_add_subtree(ti, ett_ospf_lsr);
417
418         ls_type = tvb_get_ntohl(tvb, offset);
419         proto_tree_add_text(ospf_lsr_tree, tvb, offset, 4, "LS Type: %s (%u)",
420                             val_to_str(ls_type, ls_type_vals, "Unknown"),
421                             ls_type);
422
423         proto_tree_add_text(ospf_lsr_tree, tvb, offset + 4, 4, "Link State ID: %s", 
424                             ip_to_str(tvb_get_ptr(tvb, offset + 4, 4)));
425         proto_tree_add_text(ospf_lsr_tree, tvb, offset + 8, 4, "Advertising Router: %s", 
426                             ip_to_str(tvb_get_ptr(tvb, offset + 8, 4)));
427
428         offset += 12;
429     }
430 }
431
432 static void
433 dissect_ospf_ls_upd(tvbuff_t *tvb, int offset, proto_tree *tree)
434 {
435     proto_tree *ospf_lsa_upd_tree=NULL;
436     proto_item *ti;
437     guint32 lsa_nr;
438     guint32 lsa_counter; 
439
440     ti = proto_tree_add_text(tree, tvb, offset,
441                              tvb_length_remaining(tvb, offset),
442                              "LS Update Packet");
443     ospf_lsa_upd_tree = proto_item_add_subtree(ti, ett_ospf_lsa_upd);
444
445     lsa_nr = tvb_get_ntohl(tvb, offset);
446     proto_tree_add_text(ospf_lsa_upd_tree, tvb, offset, 4, "Number of LSAs: %u",
447                         lsa_nr);
448     /* skip to the beginning of the first LSA */
449     offset += 4; /* the LS Upd Packet contains only a 32 bit #LSAs field */
450     
451     lsa_counter = 0;
452     while (lsa_counter < lsa_nr) {
453         offset = dissect_ospf_lsa(tvb, offset, ospf_lsa_upd_tree, TRUE);
454         lsa_counter += 1;
455     }
456 }
457
458 static void
459 dissect_ospf_ls_ack(tvbuff_t *tvb, int offset, proto_tree *tree)
460 {
461     /* the body of a LS Ack packet simply contains zero or more LSA Headers */
462     while (tvb_reported_length_remaining(tvb, offset) != 0)
463         offset = dissect_ospf_lsa(tvb, offset, tree, FALSE);
464 }
465
466 /*
467  * Returns if an LSA is opaque, i.e. requires special treatment 
468  */
469 static int
470 is_opaque(int lsa_type)
471 {
472     return (lsa_type >= OSPF_LSTYPE_OP_LINKLOCAL &&
473         lsa_type <= OSPF_LSTYPE_OP_ASWIDE);
474 }
475
476 /* MPLS/TE TLV types */
477 #define MPLS_TLV_ROUTER    1
478 #define MPLS_TLV_LINK      2
479
480 /* MPLS/TE Link STLV types */
481 enum {
482     MPLS_LINK_TYPE       = 1,
483     MPLS_LINK_ID,
484     MPLS_LINK_LOCAL_IF,
485     MPLS_LINK_REMOTE_IF,
486     MPLS_LINK_TE_METRIC,
487     MPLS_LINK_MAX_BW,
488     MPLS_LINK_MAX_RES_BW,
489     MPLS_LINK_UNRES_BW,
490     MPLS_LINK_COLOR,
491 };
492
493 static const value_string mpls_link_stlv_str[] = {
494     {MPLS_LINK_TYPE, "Link Type"},
495     {MPLS_LINK_ID, "Link ID"},
496     {MPLS_LINK_LOCAL_IF, "Local Interface IP Address"},
497     {MPLS_LINK_REMOTE_IF, "Remote Interface IP Address"},
498     {MPLS_LINK_TE_METRIC, "Traffic Engineering Metric"},
499     {MPLS_LINK_MAX_BW, "Maximum Bandwidth"},
500     {MPLS_LINK_MAX_RES_BW, "Maximum Reservable Bandwidth"},
501     {MPLS_LINK_UNRES_BW, "Unreserved Bandwidth"},
502     {MPLS_LINK_COLOR, "Resource Class/Color"},
503 };
504
505 /* 
506  * Dissect MPLS/TE opaque LSA 
507  */
508 static void
509 dissect_ospf_lsa_mpls(tvbuff_t *tvb, int offset, proto_tree *tree,
510                       guint32 length)
511 {
512     proto_item *ti; 
513     proto_tree *mpls_tree;
514     proto_tree *tlv_tree;
515     proto_tree *stlv_tree;
516
517     int tlv_type;
518     int tlv_length;
519     int tlv_end_offset;
520
521     int stlv_type, stlv_len, stlv_offset;
522     char *stlv_name;
523     int i;
524
525     ti = proto_tree_add_text(tree, tvb, offset, length,
526                              "MPLS Traffic Engineering LSA");
527     mpls_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls);
528
529     while (length != 0) {
530         tlv_type = tvb_get_ntohs(tvb, offset);
531         tlv_length = tvb_get_ntohs(tvb, offset + 2);
532         tlv_end_offset = offset + tlv_length + 4;
533
534         switch (tlv_type) {
535
536         case MPLS_TLV_ROUTER:
537             ti = proto_tree_add_text(mpls_tree, tvb, offset, tlv_length+4,
538                                      "Router Address: %s", 
539                                      ip_to_str(tvb_get_ptr(tvb, offset+4, 4)));
540             tlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_router);
541             proto_tree_add_text(tlv_tree, tvb, offset, 2, "TLV Type: 1 - Router Address");
542             proto_tree_add_text(tlv_tree, tvb, offset+2, 2, "TLV Length: %u",
543                                 tlv_length);
544             proto_tree_add_text(tlv_tree, tvb, offset+4, 4, "Router Address: %s",
545                                 ip_to_str(tvb_get_ptr(tvb, offset+4, 4)));
546             break;
547
548         case MPLS_TLV_LINK:
549             ti = proto_tree_add_text(mpls_tree, tvb, offset, tlv_length+4,
550                                      "Link Information");
551             tlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link);
552             proto_tree_add_text(tlv_tree, tvb, offset, 2, "TLV Type: 2 - Link Information");
553             proto_tree_add_text(tlv_tree, tvb, offset+2, 2, "TLV Length: %u",
554                                 tlv_length);
555             stlv_offset = offset + 4;
556
557             /* Walk down the sub-TLVs for link information */
558             while (stlv_offset < tlv_end_offset) {
559                 stlv_type = tvb_get_ntohs(tvb, stlv_offset);
560                 stlv_len = tvb_get_ntohs(tvb, stlv_offset + 2);
561                 stlv_name = val_to_str(stlv_type, mpls_link_stlv_str, "Unknown sub-TLV");
562                 switch (stlv_type) {
563
564                 case MPLS_LINK_TYPE:
565                     ti = proto_tree_add_text(tlv_tree, tvb, stlv_offset, stlv_len+4,
566                                              "%s: %u", stlv_name,
567                                              tvb_get_guint8(tvb, stlv_offset + 4));
568                     stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
569                     proto_tree_add_text(stlv_tree, tvb, stlv_offset, 2,
570                                         "TLV Type: %u: %s", stlv_type, stlv_name);
571                     proto_tree_add_text(stlv_tree, tvb, stlv_offset+2, 2, "TLV Length: %u",
572                                         stlv_len);
573                     proto_tree_add_text(stlv_tree, tvb, stlv_offset+4, 1, "%s: %u", stlv_name,
574                                         tvb_get_guint8(tvb, stlv_offset + 4));
575                     break;
576
577                 case MPLS_LINK_ID:
578                     ti = proto_tree_add_text(tlv_tree, tvb, stlv_offset, stlv_len+4,
579                                              "%s: %s (%x)", stlv_name,
580                                              ip_to_str(tvb_get_ptr(tvb, stlv_offset + 4, 4)),
581                                              tvb_get_ntohl(tvb, stlv_offset + 4));
582                     stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
583                     proto_tree_add_text(stlv_tree, tvb, stlv_offset, 2,
584                                         "TLV Type: %u: %s", stlv_type, stlv_name);
585                     proto_tree_add_text(stlv_tree, tvb, stlv_offset+2, 2, "TLV Length: %u",
586                                         stlv_len);
587                     proto_tree_add_text(stlv_tree, tvb, stlv_offset+4, 4, "%s: %s (%x)", stlv_name,
588                                         ip_to_str(tvb_get_ptr(tvb, stlv_offset + 4, 4)),
589                                         tvb_get_ntohl(tvb, stlv_offset + 4));
590                     break;
591
592                 case MPLS_LINK_LOCAL_IF:
593                 case MPLS_LINK_REMOTE_IF:
594                     ti = proto_tree_add_text(tlv_tree, tvb, stlv_offset, stlv_len+4,
595                                              "%s: %s", stlv_name,
596                                              ip_to_str(tvb_get_ptr(tvb, stlv_offset+4, 4)));
597                     stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
598                     proto_tree_add_text(stlv_tree, tvb, stlv_offset, 2,
599                                         "TLV Type: %u: %s", stlv_type, stlv_name);
600                     proto_tree_add_text(stlv_tree, tvb, stlv_offset+2, 2, "TLV Length: %u",
601                                         stlv_len);
602                     proto_tree_add_text(stlv_tree, tvb, stlv_offset+4, 4, "%s: %s", stlv_name,
603                                         ip_to_str(tvb_get_ptr(tvb, stlv_offset+4, 4)));
604                     break;
605
606                 case MPLS_LINK_TE_METRIC:
607                 case MPLS_LINK_COLOR:
608                     ti = proto_tree_add_text(tlv_tree, tvb, stlv_offset, stlv_len+4,
609                                              "%s: %u", stlv_name,
610                                              tvb_get_ntohl(tvb, stlv_offset + 4));
611                     stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
612                     proto_tree_add_text(stlv_tree, tvb, stlv_offset, 2,
613                                         "TLV Type: %u: %s", stlv_type, stlv_name);
614                     proto_tree_add_text(stlv_tree, tvb, stlv_offset+2, 2, "TLV Length: %u",
615                                         stlv_len);
616                     proto_tree_add_text(stlv_tree, tvb, stlv_offset+4, 4, "%s: %u", stlv_name,
617                                         tvb_get_ntohl(tvb, stlv_offset + 4));
618                     break;
619
620                 case MPLS_LINK_MAX_BW:
621                 case MPLS_LINK_MAX_RES_BW:
622                     ti = proto_tree_add_text(tlv_tree, tvb, stlv_offset, stlv_len+4,
623                                              "%s: %ld", stlv_name,
624                                              pieee_to_long(tvb_get_ptr(tvb, stlv_offset + 4, 4)));
625                     stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
626                     proto_tree_add_text(stlv_tree, tvb, stlv_offset, 2,
627                                         "TLV Type: %u: %s", stlv_type, stlv_name);
628                     proto_tree_add_text(stlv_tree, tvb, stlv_offset+2, 2, "TLV Length: %u",
629                                         stlv_len);
630                     proto_tree_add_text(stlv_tree, tvb, stlv_offset+4, 4, "%s: %ld", stlv_name,
631                                         pieee_to_long(tvb_get_ptr(tvb, stlv_offset + 4, 4)));
632                     break;
633
634                 case MPLS_LINK_UNRES_BW:
635                     ti = proto_tree_add_text(tlv_tree, tvb, stlv_offset, stlv_len+4,
636                                              "%s", stlv_name);
637                     stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
638                     proto_tree_add_text(stlv_tree, tvb, stlv_offset, 2,
639                                         "TLV Type: %u: %s", stlv_type, stlv_name);
640                     proto_tree_add_text(stlv_tree, tvb, stlv_offset+2, 2, "TLV Length: %u",
641                                         stlv_len);
642                     for (i = 0; i < 8; i++) {
643                         proto_tree_add_text(stlv_tree, tvb, stlv_offset+4+(i*4), 4,
644                                             "Pri %d: %ld", i,
645                                             pieee_to_long(tvb_get_ptr(tvb, stlv_offset + 4 + i*4, 4)));
646                     }
647                     break;
648
649                 default:
650                     proto_tree_add_text(tlv_tree, tvb, stlv_offset, stlv_len+4,
651                                         "Unknown Link sub-TLV: %u", stlv_type);
652                     break;
653                 }
654                 stlv_offset += ((stlv_len+4+3)/4)*4;
655             }
656             break;
657
658         default:
659             ti = proto_tree_add_text(mpls_tree, tvb, offset, tlv_length+4, 
660                                      "Unknown LSA: %u", tlv_type);
661             tlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link);
662             proto_tree_add_text(tlv_tree, tvb, offset, 2, "TLV Type: %u - Unknown",
663                                 tlv_type);
664             proto_tree_add_text(tlv_tree, tvb, offset+2, 2, "TLV Length: %u",
665                                 tlv_length);
666             proto_tree_add_text(tlv_tree, tvb, offset+4, tlv_length, "TLV Data");
667             break;
668         }
669
670         offset += tlv_length + 4;
671         length -= tlv_length + 4;
672     }
673 }
674
675 /*
676  * Dissect opaque LSAs
677  */
678 void
679 dissect_ospf_lsa_opaque(tvbuff_t *tvb, int offset, proto_tree *tree,
680                         guint8 ls_id_type, guint32 length)
681 {
682     switch (ls_id_type) {
683
684     case OSPF_LSA_MPLS_TE:
685         dissect_ospf_lsa_mpls(tvb, offset, tree, length);
686         break;
687
688     default:
689         proto_tree_add_text(tree, tvb, offset, length,
690                             "Unknown LSA Type %u", ls_id_type);
691         break;
692     } /* switch on opaque LSA id */
693 }
694
695 static int
696 dissect_ospf_lsa(tvbuff_t *tvb, int offset, proto_tree *tree,
697                  gboolean disassemble_body)
698 {
699     proto_tree *ospf_lsa_tree;
700     proto_item *ti; 
701
702     guint8               ls_type;
703     guint16              ls_length;
704     int                  end_offset;
705     char                *lsa_type;
706     guint8               nr_links;
707     guint16              nr_tos;
708
709     /* router LSA */
710     guint8               link_type;
711     guint16              link_counter;
712     guint8               tos_counter;
713     char                *link_type_str;
714     char                *link_id;
715
716     /* AS-external LSA */
717     guint8               options;
718
719     /* opaque LSA */
720     guint8               ls_id_type;
721
722     ls_type = tvb_get_guint8(tvb, offset + 3);
723     ls_length = tvb_get_ntohs(tvb, offset + 18);
724     end_offset = offset + ls_length;
725     switch(ls_type) {
726
727     case OSPF_LSTYPE_ROUTER:
728         lsa_type="Router LSA";
729         break;
730
731     case OSPF_LSTYPE_NETWORK:
732         lsa_type="Network LSA";
733         break;
734
735     case OSPF_LSTYPE_SUMMERY:
736         lsa_type="Summary LSA";
737         break;
738
739     case OSPF_LSTYPE_ASBR:
740         lsa_type="ASBR LSA";
741         break;
742
743     case OSPF_LSTYPE_ASEXT:
744         lsa_type="AS-external-LSA";
745         break;
746
747     case OSPF_LSTYPE_ASEXT7:
748         lsa_type="AS-external-LSA Type 7/NSSA";
749         break;
750
751     case OSPF_LSTYPE_OP_LINKLOCAL:
752         lsa_type="Opaque LSA, Link-local scope";
753         break;
754
755     case OSPF_LSTYPE_OP_AREALOCAL:
756         lsa_type="Opaque LSA, Area-local scope";
757         break;
758
759     case OSPF_LSTYPE_OP_ASWIDE:
760         lsa_type="Opaque LSA, AS-wide scope";
761         break;
762
763     default:
764         lsa_type="Unknown";
765         break;
766     }
767
768     if (disassemble_body) {
769         ti = proto_tree_add_text(tree, tvb, offset, ls_length,
770                                  "%s (Type: %u)", lsa_type, ls_type); 
771     } else {
772         ti = proto_tree_add_text(tree, tvb, offset, OSPF_LSA_HEADER_LENGTH,
773                                  "LSA Header"); 
774     }
775     ospf_lsa_tree = proto_item_add_subtree(ti, ett_ospf_lsa);
776
777     proto_tree_add_text(ospf_lsa_tree, tvb, offset, 2, "LS Age: %u seconds",
778                         tvb_get_ntohs(tvb, offset));
779     dissect_ospf_options(tvb, offset + 2, ospf_lsa_tree);
780     proto_tree_add_text(ospf_lsa_tree, tvb, offset + 3, 1, "LSA Type: %u (%s)",
781                         ls_type, lsa_type);
782
783     if (is_opaque(ls_type)) {
784         ls_id_type = tvb_get_guint8(tvb, offset + 4);
785         proto_tree_add_text(ospf_lsa_tree, tvb, offset + 4, 1, "Link State ID Opaque Type: %u",
786                             ls_id_type);
787         proto_tree_add_text(ospf_lsa_tree, tvb, offset + 5, 3, "Link State ID Opaque ID: %u",
788                             tvb_get_ntoh24(tvb, offset + 5));
789     } else {
790         ls_id_type = 0;
791         proto_tree_add_text(ospf_lsa_tree, tvb, offset + 4, 4, "Link State ID: %s",
792                             ip_to_str(tvb_get_ptr(tvb, offset + 4, 4)));
793     }
794
795     proto_tree_add_text(ospf_lsa_tree, tvb, offset + 8, 4, "Advertising Router: %s",
796                         ip_to_str(tvb_get_ptr(tvb, offset + 8, 4)));
797     proto_tree_add_text(ospf_lsa_tree, tvb, offset + 12, 4, "LS Sequence Number: 0x%04x",
798                         tvb_get_ntohl(tvb, offset + 12));
799     proto_tree_add_text(ospf_lsa_tree, tvb, offset + 16, 2, "LS Checksum: %04x",
800                         tvb_get_ntohs(tvb, offset + 16));
801
802     proto_tree_add_text(ospf_lsa_tree, tvb, offset + 18, 2, "Length: %u",
803                         ls_length);
804
805     /* skip past the LSA header to the body */
806     offset += OSPF_LSA_HEADER_LENGTH;
807     ls_length -= OSPF_LSA_HEADER_LENGTH;
808
809     if (!disassemble_body)
810         return offset;
811
812     switch (ls_type){
813
814     case OSPF_LSTYPE_ROUTER:
815         /* again: flags should be secified in detail */
816         proto_tree_add_text(ospf_lsa_tree, tvb, offset, 1, "Flags: 0x%02x",
817                             tvb_get_guint8(tvb, offset));
818         nr_links = tvb_get_ntohs(tvb, offset + 2);
819         proto_tree_add_text(ospf_lsa_tree, tvb, offset + 2, 2, "Number of Links: %u",
820                             nr_links);
821         offset += 4;
822         /* nr_links links follow 
823          * maybe we should put each of the links into its own subtree ???
824          */
825         for (link_counter = 1; link_counter <= nr_links; link_counter++) {
826             /* check the Link Type and ID */
827             link_type = tvb_get_guint8(tvb, offset + 8);
828             switch (link_type) {
829
830             case OSPF_LINK_PTP:
831                 link_type_str="Point-to-point connection to another router";
832                 link_id="Neighboring router's Router ID";
833                 break;
834
835             case OSPF_LINK_TRANSIT:
836                 link_type_str="Connection to a transit network";
837                 link_id="IP address of Designated Router";
838                 break;
839
840             case OSPF_LINK_STUB:
841                 link_type_str="Connection to a stub network";
842                 link_id="IP network/subnet number";
843                 break;
844
845             case OSPF_LINK_VIRTUAL:
846                 link_type_str="Virtual link";
847                 link_id="Neighboring router's Router ID";
848                 break;
849
850             default:
851                 link_type_str="Unknown link type";
852                 link_id="Unknown link ID";
853                 break;
854             }
855
856             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "%s: %s", link_id,
857                                 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
858
859             /* link_data should be specified in detail (e.g. network mask) (depends on link type)*/
860             proto_tree_add_text(ospf_lsa_tree, tvb, offset + 4, 4, "Link Data: %s",
861                                 ip_to_str(tvb_get_ptr(tvb, offset + 4, 4)));
862
863             proto_tree_add_text(ospf_lsa_tree, tvb, offset + 8, 1, "Link Type: %u - %s",
864                                 link_type, link_type_str);
865             nr_tos = tvb_get_guint8(tvb, offset + 9);
866             proto_tree_add_text(ospf_lsa_tree, tvb, offset + 9, 1, "Number of TOS metrics: %u",
867                                 nr_tos);
868             proto_tree_add_text(ospf_lsa_tree, tvb, offset + 10, 2, "TOS 0 metric: %u",
869                                 tvb_get_ntohs(tvb, offset + 10));
870
871             offset += 12;
872
873             /* nr_tos metrics may follow each link 
874              * ATTENTION: TOS metrics are not tested (I don't have TOS
875              * based routing)
876              * please send me a mail if it is/isn't working
877              */
878             for (tos_counter = 1; tos_counter <= nr_tos; tos_counter++) {
879                 proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "TOS: %u, Metric: %u",
880                                     tvb_get_guint8(tvb, offset),
881                                     tvb_get_ntohs(tvb, offset + 2));
882                 offset += 4;
883             }
884         }
885         break;
886
887     case OSPF_LSTYPE_NETWORK:
888         proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "Netmask: %s",
889                                 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
890         offset += 4;
891
892         while (offset < end_offset) {
893             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "Attached Router: %s",
894                                 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
895             offset += 4;
896         }
897         break;
898
899     case OSPF_LSTYPE_SUMMERY:
900     /* Type 3 and 4 LSAs have the same format */
901     case OSPF_LSTYPE_ASBR:
902         proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "Netmask: %s",
903                             ip_to_str(tvb_get_ptr(tvb, offset, 4)));
904         offset += 4;
905
906         proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "Metric: %u",
907                             tvb_get_ntoh24(tvb, offset + 1));
908         offset += 4;
909
910         /* TOS-specific information, if any */
911         while (offset < end_offset) {
912             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "TOS: %u, Metric: %u",
913                                 tvb_get_guint8(tvb, offset),
914                                 tvb_get_ntoh24(tvb, offset + 1));
915             offset += 4;
916         }
917         break;
918
919     case OSPF_LSTYPE_ASEXT:
920     case OSPF_LSTYPE_ASEXT7:
921         proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "Netmask: %s", 
922                             ip_to_str(tvb_get_ptr(tvb, offset, 4)));
923         offset += 4;
924
925         options = tvb_get_guint8(tvb, offset);
926         if (options & 0x80) { /* check wether or not E bit is set */
927             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 1,
928                     "External Type: Type 2 (metric is larger than any other link state path)");
929         } else {
930             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 1,
931                     "External Type: Type 1 (metric is specified in the same units as interface cost)");
932         }
933         /* the metric field of a AS-external LAS is specified in 3 bytes */
934         proto_tree_add_text(ospf_lsa_tree, tvb, offset + 1, 3, "Metric: %u",
935                             tvb_get_ntoh24(tvb, offset + 1));
936         offset += 4;
937
938         proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "Forwarding Address: %s", 
939                             ip_to_str(tvb_get_ptr(tvb, offset, 4)));
940         offset += 4;
941
942         proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "External Route Tag: %u",
943                             tvb_get_ntohl(tvb, offset));
944         offset += 4;
945
946         /* TOS-specific information, if any */
947         while (offset < end_offset) {
948             options = tvb_get_guint8(tvb, offset);
949             if (options & 0x80) { /* check wether or not E bit is set */
950                 proto_tree_add_text(ospf_lsa_tree, tvb, offset, 1,
951                         "External Type: Type 2 (metric is larger than any other link state path)");
952             } else {
953                 proto_tree_add_text(ospf_lsa_tree, tvb, offset, 1,
954                         "External Type: Type 1 (metric is specified in the same units as interface cost)");
955             }
956             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "TOS: %u, Metric: %u",
957                                 options & 0x7F,
958                                 tvb_get_ntoh24(tvb, offset + 1));
959             offset += 4;
960
961             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "Forwarding Address: %s", 
962                                 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
963             offset += 4;
964
965             proto_tree_add_text(ospf_lsa_tree, tvb, offset, 4, "External Route Tag: %u",
966                                 tvb_get_ntohl(tvb, offset));
967             offset += 4;
968         }
969         break;
970
971     case OSPF_LSTYPE_OP_LINKLOCAL:
972     case OSPF_LSTYPE_OP_AREALOCAL:
973     case OSPF_LSTYPE_OP_ASWIDE:
974         dissect_ospf_lsa_opaque(tvb, offset, ospf_lsa_tree, ls_id_type,
975                                 ls_length);
976         offset += ls_length;
977         break;
978
979     default:
980         /* unknown LSA type */
981         proto_tree_add_text(ospf_lsa_tree, tvb, offset, ls_length,
982                             "Unknown LSA Type");
983         offset += ls_length;
984         break;
985     }
986     /* return the offset of the next LSA */
987     return offset;
988 }
989
990 static void
991 dissect_ospf_options(tvbuff_t *tvb, int offset, proto_tree *tree)
992 {
993     guint8 options;
994     char options_string[20] = "";
995
996     /* ATTENTION !!! no check for length of options string */
997     options = tvb_get_guint8(tvb, offset);
998     if (options & OSPF_OPTIONS_E)
999         strcat(options_string, "E");
1000     if (options & OSPF_OPTIONS_MC) {
1001         if (options_string[0] != '\0')
1002             strcat(options_string, "/");
1003         strcat(options_string, "MC");
1004     }
1005     if (options & OSPF_OPTIONS_NP) {
1006         if (options_string[0] != '\0')
1007             strcat(options_string, "/");
1008         strcat(options_string, "NP");
1009     }
1010     if (options & OSPF_OPTIONS_EA) {
1011         if (options_string[0] != '\0')
1012             strcat(options_string, "/");
1013         strcat(options_string, "EA");
1014     }
1015     if (options & OSPF_OPTIONS_DC) {
1016         if (options_string[0] != '\0')
1017             strcat(options_string, "/");
1018         strcat(options_string, "DC");
1019     }
1020
1021     proto_tree_add_text(tree, tvb, offset, 1, "Options: 0x%x (%s)",
1022                         options, options_string);
1023 }
1024
1025 void
1026 proto_register_ospf(void)
1027 {
1028 /*        static hf_register_info hf[] = {
1029                 { &variable,
1030                 { "Name",           "ospf.abbreviation", TYPE, VALS_POINTER }},
1031         };*/
1032     static gint *ett[] = {
1033         &ett_ospf,
1034         &ett_ospf_hdr,
1035         &ett_ospf_hello,
1036         &ett_ospf_desc,
1037         &ett_ospf_lsr,
1038         &ett_ospf_lsa,
1039         &ett_ospf_lsa_upd,
1040         &ett_ospf_lsa_mpls,
1041         &ett_ospf_lsa_mpls_router,
1042         &ett_ospf_lsa_mpls_link,
1043         &ett_ospf_lsa_mpls_link_stlv
1044     };
1045
1046     proto_ospf = proto_register_protocol("Open Shortest Path First",
1047                                          "OSPF", "ospf");
1048  /*       proto_register_field_array(proto_ospf, hf, array_length(hf));*/
1049     proto_register_subtree_array(ett, array_length(ett));
1050 }
1051
1052 void
1053 proto_reg_handoff_ospf(void)
1054 {
1055     dissector_add("ip.proto", IP_PROTO_OSPF, dissect_ospf);
1056 }