Changes from Craig Metz to:
[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.28 2000/09/13 07:47:09 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-ospf.h"
52 #include "packet-ip.h"
53 #include "ieee-float.h"
54
55 static int proto_ospf = -1;
56
57 static gint ett_ospf = -1;
58 static gint ett_ospf_hdr = -1;
59 static gint ett_ospf_hello = -1;
60 static gint ett_ospf_desc = -1;
61 static gint ett_ospf_lsr = -1;
62 static gint ett_ospf_lsa = -1;
63 static gint ett_ospf_lsa_upd = -1;
64
65 /* Trees for opaque LSAs */
66 static gint ett_ospf_lsa_mpls = -1;
67 static gint ett_ospf_lsa_mpls_router = -1;
68 static gint ett_ospf_lsa_mpls_link = -1;
69 static gint ett_ospf_lsa_mpls_link_stlv = -1;
70
71 static void dissect_ospf_hello(const u_char*, int, frame_data*, proto_tree*);
72 static void dissect_ospf_db_desc(const u_char*, int, frame_data*, proto_tree*); 
73 static void dissect_ospf_ls_req(const u_char*, int, frame_data*, proto_tree*); 
74 static void dissect_ospf_ls_upd(const u_char*, int, frame_data*, proto_tree*); 
75 static void dissect_ospf_ls_ack(const u_char*, int, frame_data*, proto_tree*); 
76
77 /* dissect_ospf_lsa returns the length of the LSA 
78  * if disassemble_body is set to FALSE (e.g. in LSA ACK 
79  * packets), the LSA-header length is returned (20)
80  */
81 static int dissect_ospf_lsa(const u_char*, int, frame_data*, proto_tree*, int disassemble_body); 
82
83 static void 
84 dissect_ospf(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
85     e_ospfhdr ospfh;
86     e_ospf_crypto *crypto;
87     int i, saved_len, ospflen;
88
89     proto_tree *ospf_tree = NULL;
90         proto_item *ti; 
91     proto_tree *ospf_header_tree;
92     char auth_data[(2 * 16) + 1]="";
93     char *packet_type;
94     static value_string pt_vals[] = { {OSPF_HELLO,   "Hello Packet"   },
95                                       {OSPF_DB_DESC, "DB Descr."      },
96                                       {OSPF_LS_REQ,  "LS Request"     },
97                                       {OSPF_LS_UPD,  "LS Update"      },
98                                       {OSPF_LS_ACK,  "LS Acknowledge" },
99                                       {0,             NULL            } };
100
101     OLD_CHECK_DISPLAY_AS_DATA(proto_ospf, pd, offset, fd, tree);
102
103     memcpy(&ospfh, &pd[offset], sizeof(e_ospfhdr));
104
105     packet_type = match_strval(ospfh.packet_type, pt_vals);
106     if (check_col(fd, COL_PROTOCOL))
107         col_add_str(fd, COL_PROTOCOL, "OSPF");
108     if (check_col(fd, COL_INFO)) {
109         if (packet_type != NULL)
110             col_add_str(fd, COL_INFO, packet_type); 
111         else
112             col_add_fstr(fd, COL_INFO, "Unknown (%d)", ospfh.packet_type); 
113     }  
114
115     if (tree) {
116         ti = proto_tree_add_item(tree, proto_ospf, NullTVB, offset, ntohs(ospfh.length), FALSE);
117         ospf_tree = proto_item_add_subtree(ti, ett_ospf);
118
119         ti = proto_tree_add_text(ospf_tree, NullTVB, offset, OSPF_HEADER_LENGTH, "OSPF Header"); 
120         ospf_header_tree = proto_item_add_subtree(ti, ett_ospf_hdr);
121
122         proto_tree_add_text(ospf_header_tree, NullTVB, offset, 1, "OSPF Version: %d", ospfh.version);  
123         proto_tree_add_text(ospf_header_tree, NullTVB, offset + 1 , 1, "OSPF Packet Type: %d (%s)", 
124                                                            ospfh.packet_type,
125                                                            (packet_type != NULL ?
126                                                              packet_type :
127                                                              "Unknown"));
128         proto_tree_add_text(ospf_header_tree, NullTVB, offset + 2 , 2, "Packet Length: %d", 
129                                                            ntohs(ospfh.length));
130         proto_tree_add_text(ospf_header_tree, NullTVB, offset + 4 , 4, "Source OSPF Router ID: %s", 
131
132                                                            ip_to_str((guint8 *) &(ospfh.routerid)));
133         if (!(ospfh.area)) {
134            proto_tree_add_text(ospf_header_tree, NullTVB, offset + 8 , 4, "Area ID: Backbone");
135         } else {
136            proto_tree_add_text(ospf_header_tree, NullTVB, offset + 8 , 4, "Area ID: %s", ip_to_str((guint8 *) &(ospfh.area)));
137         }
138         proto_tree_add_text(ospf_header_tree, NullTVB, offset + 12 , 2, "Packet Checksum: 0x%x",
139               ntohs(ospfh.checksum));
140         switch( ntohs(ospfh.auth_type) ) {
141             case OSPF_AUTH_NONE:
142                  proto_tree_add_text(ospf_header_tree, NullTVB, offset + 14 , 2, "Auth Type: none");
143                  proto_tree_add_text(ospf_header_tree, NullTVB, offset + 16 , 8, "Auth Data (none)");
144                  break;
145             case OSPF_AUTH_SIMPLE:
146                  proto_tree_add_text(ospf_header_tree, NullTVB, offset + 14 , 2, "Auth Type: simple");
147                  strncpy(auth_data, (char *) &ospfh.auth_data, 8);
148                  proto_tree_add_text(ospf_header_tree, NullTVB, offset + 16 , 8, "Auth Data: %s", auth_data);
149                  break;
150             case OSPF_AUTH_CRYPT:
151                  crypto = (e_ospf_crypto *)ospfh.auth_data;
152                  proto_tree_add_text(ospf_header_tree, NullTVB, offset + 14 , 2, "Auth Type: crypt");
153                  proto_tree_add_text(ospf_header_tree, NullTVB, offset + 18 , 1, "Auth Key ID: %d",
154                                      crypto->key_id);
155                  proto_tree_add_text(ospf_header_tree, NullTVB, offset + 19 , 1, "Auth Data Length: %d",
156                                      crypto->length);
157                  proto_tree_add_text(ospf_header_tree, NullTVB, offset + 20 , 4, "Auth Crypto Sequence Number: 0x%lx",
158                                  (unsigned long)ntohl(crypto->sequence_num));
159   
160                  ospflen = ntohs(ospfh.length);
161                  for (i = 0; i < crypto->length && i < (sizeof(auth_data)/2); i++)
162                      sprintf(&auth_data[i*2],"%02x",pd[offset + ospflen + i]);
163                  proto_tree_add_text(ospf_header_tree, NullTVB, offset + ospflen , 16, "Auth Data: %s", auth_data);
164                  break;
165             default:
166                  proto_tree_add_text(ospf_header_tree, NullTVB, offset + 14 , 2, "Auth Type (unknown)");
167                  proto_tree_add_text(ospf_header_tree, NullTVB, offset + 16 , 8, "Auth Data (unknown)");
168         }
169
170     }
171
172     /* Temporarily adjust the captured length to match the size of the OSPF
173      * packet (since the dissect routines use it to work out where the end of
174      * the ospf packet is).
175      */
176     saved_len = pi.captured_len;
177     if (BYTES_ARE_IN_FRAME(offset, ntohs(ospfh.length))) {
178       pi.captured_len = offset + ntohs(ospfh.length);
179     }
180
181     /*  Skip over header */
182     offset += OSPF_HEADER_LENGTH;
183
184     switch(ospfh.packet_type){
185         case OSPF_HELLO:
186             dissect_ospf_hello(pd, offset, fd, ospf_tree); 
187             break;
188         case OSPF_DB_DESC:
189             dissect_ospf_db_desc(pd, offset, fd, ospf_tree);   
190             break;
191         case OSPF_LS_REQ:
192             dissect_ospf_ls_req(pd, offset, fd, ospf_tree);   
193             break;
194         case OSPF_LS_UPD:
195             dissect_ospf_ls_upd(pd, offset, fd, ospf_tree);
196             break;
197         case OSPF_LS_ACK:
198             dissect_ospf_ls_ack(pd, offset, fd, ospf_tree);
199             break;
200         default:
201             pi.captured_len = saved_len;
202             old_dissect_data(pd, offset, fd, tree); 
203     }
204     pi.captured_len = saved_len;
205 }
206
207 static void
208 dissect_ospf_hello(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
209     e_ospf_hello ospfhello;
210     guint32 *ospfneighbor;
211     char options[20]="";
212     int options_offset;
213
214     proto_tree *ospf_hello_tree;
215         proto_item *ti; 
216
217     memcpy(&ospfhello, &pd[offset], sizeof(e_ospf_hello));
218
219     if (tree) {
220         ti = proto_tree_add_text(tree, NullTVB, offset, END_OF_FRAME, "OSPF Hello Packet"); 
221         ospf_hello_tree = proto_item_add_subtree(ti, ett_ospf_hello);
222
223
224         proto_tree_add_text(ospf_hello_tree, NullTVB, offset , 4, "Network Mask: %s",  ip_to_str((guint8 *) &ospfhello.network_mask));
225         proto_tree_add_text(ospf_hello_tree, NullTVB, offset + 4, 2, "Hello Interval: %d seconds",  ntohs(ospfhello.hellointervall));
226
227         /* ATTENTION !!! no check for length of options string */
228         options_offset=0;
229         if(( ospfhello.options & OSPF_OPTIONS_E ) == OSPF_OPTIONS_E){
230             strcpy( (char *)(options + options_offset), "E");
231             options_offset+=1;
232         }
233         if(( ospfhello.options & OSPF_OPTIONS_MC ) == OSPF_OPTIONS_MC){
234             strcpy((char *) (options + options_offset), "/MC");
235             options_offset+=3;
236         }
237         if(( ospfhello.options & OSPF_OPTIONS_NP ) == OSPF_OPTIONS_NP){
238             strcpy((char *) (options + options_offset), "/NP");
239             options_offset+=3;
240         }
241         if(( ospfhello.options & OSPF_OPTIONS_EA ) == OSPF_OPTIONS_EA){
242             strcpy((char *) (options + options_offset) , "/EA");
243             options_offset+=3;
244         }
245         if(( ospfhello.options & OSPF_OPTIONS_DC ) == OSPF_OPTIONS_DC){
246             strcpy((char *) (options + options_offset) , "/DC");
247             options_offset+=3;
248         }
249
250         proto_tree_add_text(ospf_hello_tree, NullTVB, offset + 6, 1, "Options: %d (%s)",  ospfhello.options, options);
251         proto_tree_add_text(ospf_hello_tree, NullTVB, offset + 7, 1, "Router Priority: %d",  ospfhello.priority);
252         proto_tree_add_text(ospf_hello_tree, NullTVB, offset + 8, 4, "Router Dead Interval: %ld seconds",  (long)ntohl(ospfhello.dead_interval));
253         proto_tree_add_text(ospf_hello_tree, NullTVB, offset + 12, 4, "Designated Router: %s",  ip_to_str((guint8 *) &ospfhello.drouter));
254         proto_tree_add_text(ospf_hello_tree, NullTVB, offset + 16, 4, "Backup Designated Router: %s",  ip_to_str((guint8 *) &ospfhello.bdrouter));
255
256
257         offset+=20;
258         while(((int)(pi.captured_len - offset)) >= 4){
259             ospfneighbor=(guint32 *) &pd[offset];
260             proto_tree_add_text(ospf_hello_tree, NullTVB, offset, 4, "Active Neighbor: %s",  ip_to_str((guint8 *) ospfneighbor));
261             offset+=4;
262         }
263     }
264 }
265
266 static void
267 dissect_ospf_db_desc(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
268     e_ospf_dbd ospf_dbd;
269     char options[20]="";
270     int options_offset;
271     char flags[20]="";
272     int flags_offset;
273
274     proto_tree *ospf_db_desc_tree=NULL;
275         proto_item *ti; 
276
277     memcpy(&ospf_dbd, &pd[offset], sizeof(e_ospf_dbd));
278
279     if (tree) {
280         ti = proto_tree_add_text(tree, NullTVB, offset, END_OF_FRAME, "OSPF DB Description"); 
281         ospf_db_desc_tree = proto_item_add_subtree(ti, ett_ospf_desc);
282
283         proto_tree_add_text(ospf_db_desc_tree, NullTVB, offset, 2, "Interface MTU: %d", ntohs(ospf_dbd.interface_mtu) );
284
285
286         options_offset=0;
287         if(( ospf_dbd.options & OSPF_OPTIONS_E ) == OSPF_OPTIONS_E){
288             strcpy( (char *)(options + options_offset), "_E_");
289             options_offset+=1;
290         }
291         if(( ospf_dbd.options & OSPF_OPTIONS_MC ) == OSPF_OPTIONS_MC){
292             strcpy((char *) (options + options_offset), "_MC_");
293             options_offset+=3;
294         }
295         if(( ospf_dbd.options & OSPF_OPTIONS_NP ) == OSPF_OPTIONS_NP){
296             strcpy((char *) (options + options_offset), "_NP_");
297             options_offset+=3;
298         }
299         if(( ospf_dbd.options & OSPF_OPTIONS_EA ) == OSPF_OPTIONS_EA){
300             strcpy((char *) (options + options_offset) , "_EA_");
301             options_offset+=3;
302         }
303         if(( ospf_dbd.options & OSPF_OPTIONS_DC ) == OSPF_OPTIONS_DC){
304             strcpy((char *) (options + options_offset) , "_DC_");
305             options_offset+=3;
306         }
307
308         proto_tree_add_text(ospf_db_desc_tree, NullTVB, offset + 2 , 1, "Options: %d (%s)", ospf_dbd.options, options );
309
310
311         flags_offset=0;
312         if(( ospf_dbd.flags & OSPF_DBD_FLAG_MS ) == OSPF_DBD_FLAG_MS){
313             strcpy( (char *)(flags + flags_offset), "_MS_");
314             flags_offset+=4;
315         }
316         if(( ospf_dbd.flags & OSPF_DBD_FLAG_M ) == OSPF_DBD_FLAG_M){
317             strcpy((char *) (flags + flags_offset), "_M_");
318             flags_offset+=3;
319         }
320         if(( ospf_dbd.flags & OSPF_DBD_FLAG_I ) == OSPF_DBD_FLAG_I){
321             strcpy((char *) (flags + flags_offset), "_I_");
322             flags_offset+=3;
323         }
324
325         proto_tree_add_text(ospf_db_desc_tree, NullTVB, offset + 3 , 1, "Flags: %d (%s)", ospf_dbd.flags, flags );
326         proto_tree_add_text(ospf_db_desc_tree, NullTVB, offset + 4 , 4, "DD Sequence: %ld", (long)ntohl(ospf_dbd.dd_sequence) );
327     }
328     /* LS Headers will be processed here */
329     /* skip to the end of DB-Desc header */
330     offset+=8;
331     while( ((int) (pi.captured_len - offset)) >= OSPF_LSA_HEADER_LENGTH ) {
332        dissect_ospf_lsa(pd, offset, fd, tree, FALSE);
333        offset+=OSPF_LSA_HEADER_LENGTH;
334     }
335 }
336
337 static void
338 dissect_ospf_ls_req(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
339     e_ospf_ls_req ospf_lsr;
340
341     proto_tree *ospf_lsr_tree;
342         proto_item *ti; 
343
344
345     /* zero or more LS requests may be within a LS Request */
346     /* we place every request for a LSA in a single subtree */
347     if (tree) {
348         while( ((int) (pi.captured_len - offset)) >= OSPF_LS_REQ_LENGTH ){
349              memcpy(&ospf_lsr, &pd[offset], sizeof(e_ospf_ls_req));
350              ti = proto_tree_add_text(tree, NullTVB, offset, OSPF_LS_REQ_LENGTH, "Link State Request"); 
351              ospf_lsr_tree = proto_item_add_subtree(ti, ett_ospf_lsr);
352
353              switch( ntohl( ospf_lsr.ls_type ) ){
354                  case OSPF_LSTYPE_ROUTER:
355                      proto_tree_add_text(ospf_lsr_tree, NullTVB, offset, 4, "LS Type: Router-LSA (%ld)", 
356                                        (long)ntohl( ospf_lsr.ls_type ) );
357                      break;
358                  case OSPF_LSTYPE_NETWORK:
359                      proto_tree_add_text(ospf_lsr_tree, NullTVB, offset, 4, "LS Type: Network-LSA (%ld)", 
360                                        (long)ntohl( ospf_lsr.ls_type ) );
361                      break;
362                  case OSPF_LSTYPE_SUMMERY:
363                      proto_tree_add_text(ospf_lsr_tree, NullTVB, offset, 4, "LS Type: Summary-LSA (IP network) (%ld)", 
364                                        (long)ntohl( ospf_lsr.ls_type ) );
365                      break;
366                  case OSPF_LSTYPE_ASBR:
367                      proto_tree_add_text(ospf_lsr_tree, NullTVB, offset, 4, "LS Type: Summary-LSA (ASBR) (%ld)", 
368                                        (long)ntohl( ospf_lsr.ls_type ) );
369                      break;
370                  case OSPF_LSTYPE_ASEXT:
371                      proto_tree_add_text(ospf_lsr_tree, NullTVB, offset, 4, "LS Type: AS-External-LSA (ASBR) (%ld)", 
372                                        (long)ntohl( ospf_lsr.ls_type ) );
373                      break;
374                  default:
375                      proto_tree_add_text(ospf_lsr_tree, NullTVB, offset, 4, "LS Type: %ld (unknown)", 
376                                        (long)ntohl( ospf_lsr.ls_type ) );
377              }
378
379              proto_tree_add_text(ospf_lsr_tree, NullTVB, offset + 4, 4, "Link State ID : %s", 
380                                          ip_to_str((guint8 *) &(ospf_lsr.ls_id)));
381              proto_tree_add_text(ospf_lsr_tree, NullTVB, offset + 8, 4, "Advertising Router : %s", 
382                                          ip_to_str((guint8 *) &(ospf_lsr.adv_router)));
383
384              offset+=12;
385         }
386     }
387 }
388
389 static void
390 dissect_ospf_ls_upd(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
391     e_ospf_lsa_upd_hdr upd_hdr;
392     guint32 lsa_counter; 
393
394     proto_tree *ospf_lsa_upd_tree=NULL;
395         proto_item *ti; 
396
397     memcpy(&upd_hdr, &pd[offset], sizeof(e_ospf_lsa_upd_hdr));
398
399     if (tree) {
400         ti = proto_tree_add_text(tree, NullTVB, offset, END_OF_FRAME, "LS Update Packet"); 
401         ospf_lsa_upd_tree = proto_item_add_subtree(ti, ett_ospf_lsa_upd);
402
403         proto_tree_add_text(ospf_lsa_upd_tree, NullTVB, offset, 4, "Nr oF LSAs: %ld", (long)ntohl(upd_hdr.lsa_nr) );
404     }
405     /* skip to the beginning of the first LSA */
406     offset+=4; /* the LS Upd PAcket contains only a 32 bit #LSAs field */
407     
408     lsa_counter = 0;
409     while(lsa_counter < ntohl(upd_hdr.lsa_nr)){
410         offset+=dissect_ospf_lsa(pd, offset, fd, ospf_lsa_upd_tree, TRUE);
411         lsa_counter += 1;
412     }
413 }
414
415 static void
416 dissect_ospf_ls_ack(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
417
418     /* the body of a LS Ack packet simply contains zero or more LSA Headers */
419     while( ((int)(pi.captured_len - offset)) >= OSPF_LSA_HEADER_LENGTH ) {
420        dissect_ospf_lsa(pd, offset, fd, tree, FALSE);
421        offset+=OSPF_LSA_HEADER_LENGTH;
422     }
423
424 }
425
426 /*
427  * Returns if an LSA is opaque, i.e. requires special treatment 
428  */
429 int is_opaque(int lsa_type)
430 {
431     return (lsa_type >= 9 && lsa_type <= 11);
432 }
433
434 /* MPLS/TE TLV types */
435 #define MPLS_TLV_ROUTER    1
436 #define MPLS_TLV_LINK      2
437
438 /* MPLS/TE Link STLV types */
439 enum {
440     MPLS_LINK_TYPE       = 1,
441     MPLS_LINK_ID,
442     MPLS_LINK_LOCAL_IF,
443     MPLS_LINK_REMOTE_IF,
444     MPLS_LINK_TE_METRIC,
445     MPLS_LINK_MAX_BW,
446     MPLS_LINK_MAX_RES_BW,
447     MPLS_LINK_UNRES_BW,
448     MPLS_LINK_COLOR,
449 };
450
451 static value_string mpls_link_stlv_str[] = {
452     {MPLS_LINK_TYPE, "Link Type"},
453     {MPLS_LINK_ID, "Link ID"},
454     {MPLS_LINK_LOCAL_IF, "Local Interface IP Address"},
455     {MPLS_LINK_REMOTE_IF, "Remote Interface IP Address"},
456     {MPLS_LINK_TE_METRIC, "Traffic Engineering Metric"},
457     {MPLS_LINK_MAX_BW, "Maximum Bandwidth"},
458     {MPLS_LINK_MAX_RES_BW, "Maximum Reservable Bandwidth"},
459     {MPLS_LINK_UNRES_BW, "Unreserved Bandwidth"},
460     {MPLS_LINK_COLOR, "Resource Class/Color"},
461 };
462
463 /* 
464  * Dissect MPLS/TE opaque LSA 
465  */
466
467 void dissect_ospf_lsa_mpls(const u_char *pd, 
468                           int offset, 
469                           frame_data *fd, 
470                           proto_tree *tree,
471                           e_ospf_lsa_hdr *lsa_hdr) {
472     proto_item *ti; 
473     proto_tree *mpls_tree;
474     proto_tree *tlv_tree;
475     proto_tree *stlv_tree;
476
477     int length;
478     int tlv_type;
479     int tlv_length;
480
481     int link_len;
482     int stlv_type, stlv_len;
483     char *stlv_name;
484     int i;
485
486     ti = proto_tree_add_text(tree, NullTVB, offset, ntohs(lsa_hdr->length) - 20,
487                              "MPLS Traffic Engineering LSA");
488     mpls_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls);
489
490     for (length = 0; length < ntohs(lsa_hdr->length) - 20; length += 4) {
491         tlv_type = pntohs(pd+offset+length);
492         tlv_length = pntohs(pd+offset+length + 2);
493
494         switch(tlv_type) {
495         case MPLS_TLV_ROUTER:
496             ti = proto_tree_add_text(mpls_tree, NullTVB, offset+length, tlv_length+4, 
497                                      "Router Address: %s", 
498                                      ip_to_str((pd+offset+length+4)));
499             tlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_router);
500             proto_tree_add_text(tlv_tree, NullTVB, offset+length, 2, "TLV Type: 1 - Router Address");
501             proto_tree_add_text(tlv_tree, NullTVB, offset+length+2, 2, "TLV Length: %d", tlv_length);
502             proto_tree_add_text(tlv_tree, NullTVB, offset+length+4, 4, "Router Address: %s", 
503                                 ip_to_str((pd+offset+length+4)));
504             break;
505         case MPLS_TLV_LINK:
506             ti = proto_tree_add_text(mpls_tree, NullTVB, offset+length, tlv_length+4, 
507                                      "Link Information");
508             tlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link);
509             proto_tree_add_text(tlv_tree, NullTVB, offset+length, 2, "TLV Type: 2 - Link Information");
510             proto_tree_add_text(tlv_tree, NullTVB, offset+length+2, 2, "TLV Length: %d", tlv_length);
511
512             /* Walk down the sub-TLVs for link information */
513             for (link_len = length + 4; link_len < length + 4 + tlv_length; link_len += 4) {
514                 stlv_type = pntohs(pd+offset+link_len);
515                 stlv_len = pntohs(pd+offset+link_len + 2);
516                 stlv_name = val_to_str(stlv_type, mpls_link_stlv_str, "Unknown sub-TLV");
517                 switch(stlv_type) {
518
519                 case MPLS_LINK_TYPE:
520                     ti = proto_tree_add_text(tlv_tree, NullTVB, offset+link_len, stlv_len+4, 
521                                              "%s: %d", stlv_name,
522                                              *((guint8 *)pd + offset + link_len + 4));
523                     stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
524                     proto_tree_add_text(stlv_tree, NullTVB, offset+link_len, 2, 
525                                         "TLV Type: %d: %s", stlv_type, stlv_name);
526                     proto_tree_add_text(stlv_tree, NullTVB, offset+link_len+2, 2, "TLV Length: %d", stlv_len);
527                     proto_tree_add_text(stlv_tree, NullTVB, offset+link_len+4, 1, "%s: %d", stlv_name,
528                                         *((guint8 *)pd + offset + link_len + 4));
529                     break;
530                     
531                 case MPLS_LINK_ID:
532                     ti = proto_tree_add_text(tlv_tree, NullTVB, offset+link_len, stlv_len+4, 
533                                              "%s: %s (%x)", stlv_name, 
534                                              ip_to_str(pd + offset + link_len + 4),
535                                              pntohl(pd + offset + link_len + 4));
536                     stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
537                     proto_tree_add_text(stlv_tree, NullTVB, offset+link_len, 2, 
538                                         "TLV Type: %d: %s", stlv_type, stlv_name);
539                     proto_tree_add_text(stlv_tree, NullTVB, offset+link_len+2, 2, "TLV Length: %d", stlv_len);
540                     proto_tree_add_text(stlv_tree, NullTVB, offset+link_len+4, 4, "%s: %s (%x)", stlv_name, 
541                                         ip_to_str(pd + offset + link_len + 4),
542                                         pntohl(pd + offset + link_len + 4));
543                     break;
544                     
545                 case MPLS_LINK_LOCAL_IF:
546                 case MPLS_LINK_REMOTE_IF:
547                     ti = proto_tree_add_text(tlv_tree, NullTVB, offset+link_len, stlv_len+4, 
548                                              "%s: %s", stlv_name, 
549                                              ip_to_str(pd+offset+link_len+4));
550                     stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
551                     proto_tree_add_text(stlv_tree, NullTVB, offset+link_len, 2, 
552                                         "TLV Type: %d: %s", stlv_type, stlv_name);
553                     proto_tree_add_text(stlv_tree, NullTVB, offset+link_len+2, 2, "TLV Length: %d", stlv_len);
554                     proto_tree_add_text(stlv_tree, NullTVB, offset+link_len+4, 4, "%s: %s", stlv_name, 
555                                         ip_to_str(pd+offset+link_len+4));
556
557                     break;
558
559                 case MPLS_LINK_TE_METRIC:
560                 case MPLS_LINK_COLOR:
561                     ti = proto_tree_add_text(tlv_tree, NullTVB, offset+link_len, stlv_len+4, 
562                                              "%s: %d", stlv_name, 
563                                              pntohl(pd + offset + link_len + 4));
564                     stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
565                     proto_tree_add_text(stlv_tree, NullTVB, offset+link_len, 2, 
566                                         "TLV Type: %d: %s", stlv_type, stlv_name);
567                     proto_tree_add_text(stlv_tree, NullTVB, offset+link_len+2, 2, "TLV Length: %d", stlv_len);
568                     proto_tree_add_text(stlv_tree, NullTVB, offset+link_len+4, 4, "%s: %d", stlv_name, 
569                                         pntohl(pd + offset + link_len + 4));
570                     break;
571                     
572                 case MPLS_LINK_MAX_BW:
573                 case MPLS_LINK_MAX_RES_BW:
574                     ti = proto_tree_add_text(tlv_tree, NullTVB, offset+link_len, stlv_len+4, 
575                                              "%s: %ld", stlv_name, 
576                                              pieee_to_long(pd + offset + link_len + 4));
577                     stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
578                     proto_tree_add_text(stlv_tree, NullTVB, offset+link_len, 2, 
579                                         "TLV Type: %d: %s", stlv_type, stlv_name);
580                     proto_tree_add_text(stlv_tree, NullTVB, offset+link_len+2, 2, "TLV Length: %d", stlv_len);
581                     proto_tree_add_text(stlv_tree, NullTVB, offset+link_len+4, 4, "%s: %ld", stlv_name, 
582                                         pieee_to_long(pd + offset + link_len + 4));
583                     break;
584                     
585                 case MPLS_LINK_UNRES_BW:
586                     ti = proto_tree_add_text(tlv_tree, NullTVB, offset+link_len, stlv_len+4, 
587                                              "%s", stlv_name);
588                     stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
589                     proto_tree_add_text(stlv_tree, NullTVB, offset+link_len, 2, 
590                                         "TLV Type: %d: %s", stlv_type, stlv_name);
591                     proto_tree_add_text(stlv_tree, NullTVB, offset+link_len+2, 2, "TLV Length: %d", stlv_len);
592                     for (i=0; i<8; i++) 
593                         proto_tree_add_text(stlv_tree, NullTVB, offset+link_len+4+(i*4), 4, 
594                                             "Pri %d: %ld", i,
595                                             pieee_to_long(pd + offset + link_len + 4 + i*4));
596                     break;
597                     
598                 default:
599                     proto_tree_add_text(tlv_tree, NullTVB, offset+link_len, stlv_len+4, 
600                                         "Unknown Link sub-TLV: %d", stlv_type);
601                 }
602                 link_len += ((stlv_len+3)/4)*4;
603             }
604
605             break;
606
607         default:
608             ti = proto_tree_add_text(mpls_tree, NullTVB, offset+length, tlv_length+4, 
609                                      "Unknown LSA: %d", tlv_type);
610             tlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link);
611             proto_tree_add_text(tlv_tree, NullTVB, offset+length, 2, "TLV Type: %d - Unknown", tlv_type);
612             proto_tree_add_text(tlv_tree, NullTVB, offset+length+2, 2, "TLV Length: %d", tlv_length);
613             proto_tree_add_text(tlv_tree, NullTVB, offset+length+4, tlv_length, "TLV Data");
614             break;
615         }
616
617         length += tlv_length;
618
619     }
620 }
621
622 /*
623  * Dissect opaque LSAs
624  */
625 void dissect_ospf_lsa_opaque(const u_char *pd, 
626                             int offset, 
627                             frame_data *fd, 
628                             proto_tree *tree,
629                             e_ospf_lsa_hdr *lsa_hdr) {
630     guint8 opaque_id = *((guint8 *) &(lsa_hdr->ls_id));
631
632     switch(opaque_id) {
633
634     case OSPF_LSA_MPLS_TE:
635         dissect_ospf_lsa_mpls(pd, offset, fd, tree, lsa_hdr);
636         break;
637
638     default:
639         proto_tree_add_text(tree, NullTVB, offset, END_OF_FRAME, "Unknown LSA Type");
640         break;
641     } /* switch on opaque LSA id */
642 }
643
644 static int
645 dissect_ospf_lsa(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int disassemble_body) {
646     e_ospf_lsa_hdr       lsa_hdr;
647     char                *lsa_type;
648     int                  lsa_end;
649
650     /* data strutures for the router LSA */
651     e_ospf_router_lsa           router_lsa;
652     e_ospf_router_data          router_data;
653     e_ospf_router_metric        tos_data;
654     guint16                     link_counter;
655     guint8                      tos_counter;
656     char                        *link_type;
657     char                        *link_id;
658
659     /* data structures for the network lsa */
660     e_ospf_network_lsa  network_lsa;
661     guint32             *attached_router;
662
663     /* data structures for the summary and ASBR LSAs */
664     e_ospf_summary_lsa  summary_lsa;
665     guint32             metric;
666
667     /* data structures for the AS-External LSA */
668     e_ospf_asexternal_lsa       asext_lsa;
669     guint32                   asext_metric;
670
671     /* data structures for opaque LSA */
672     guint32                     ls_id;
673
674     proto_tree *ospf_lsa_tree;
675         proto_item *ti; 
676
677     memcpy(&lsa_hdr, &pd[offset], sizeof(e_ospf_lsa_hdr));
678
679              
680
681     switch(lsa_hdr.ls_type) {
682         case OSPF_LSTYPE_ROUTER:
683             lsa_type="Router LSA";
684             break;
685         case OSPF_LSTYPE_NETWORK:
686             lsa_type="Network LSA";
687             break;
688         case OSPF_LSTYPE_SUMMERY:
689             lsa_type="Summary LSA";
690             break;
691         case OSPF_LSTYPE_ASBR:
692             lsa_type="ASBR LSA";
693             break;
694         case OSPF_LSTYPE_ASEXT:
695             lsa_type="AS-external-LSA";
696             break;
697         case OSPF_LSTYPE_ASEXT7:
698             lsa_type="AS-external-LSA Type 7/NSSA";
699             break;
700         case OSPF_LSTYPE_OP_LINKLOCAL:
701             lsa_type="Opaque LSA, Link-local scope";
702             break;
703         case OSPF_LSTYPE_OP_AREALOCAL:
704             lsa_type="Opaque LSA, Area-local scope";
705             break;
706         case OSPF_LSTYPE_OP_ASWIDE:
707             lsa_type="Opaque LSA, AS-wide scope";
708             break;
709         default:
710             lsa_type="unknown";
711     }
712
713     if (tree) {
714         if(disassemble_body){
715              ti = proto_tree_add_text(tree, NullTVB, offset, ntohs(lsa_hdr.length), 
716                                                       "%s (Type: %d)", lsa_type, lsa_hdr.ls_type); 
717         } else {
718              ti = proto_tree_add_text(tree, NullTVB, offset, OSPF_LSA_HEADER_LENGTH, "LSA Header"); 
719         }
720         ospf_lsa_tree = proto_item_add_subtree(ti, ett_ospf_lsa);
721
722         
723         proto_tree_add_text(ospf_lsa_tree, NullTVB, offset, 2, "LS Age: %d seconds", ntohs(lsa_hdr.ls_age));
724         proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 2, 1, "Options: %d ", lsa_hdr.options);
725         proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 3, 1, "LSA Type: %d (%s)", lsa_hdr.ls_type, lsa_type);
726
727         if (is_opaque(lsa_hdr.ls_type)) {
728             ls_id = ntohl(lsa_hdr.ls_id);
729             proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 4, 1, "Link State ID Opaque Type: %u ", 
730                                 (ls_id >> 24) & 0xff);
731             proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 5, 3, "Link State ID Opaque ID: %u ", 
732                                 ls_id & 0xffffff);
733         } else
734             proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 4, 4, "Link State ID: %s ", 
735                                 ip_to_str((guint8 *) &(lsa_hdr.ls_id)));
736
737         proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 8, 4, "Advertising Router: %s ", 
738                                                      ip_to_str((guint8 *) &(lsa_hdr.adv_router)));
739         proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 12, 4, "LS Sequence Number: 0x%04lx ", 
740                                                      (unsigned long)ntohl(lsa_hdr.ls_seq));
741         proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 16, 2, "LS Checksum: %04x ", ntohs(lsa_hdr.ls_checksum));
742
743         proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 18, 2, "Length: %d ", ntohs(lsa_hdr.length));
744
745         if(!disassemble_body){
746            return OSPF_LSA_HEADER_LENGTH;
747         }
748
749         lsa_end = offset + ntohs(lsa_hdr.length);
750         /* the LSA body starts after 20 bytes of LSA Header */
751         offset+=20;
752
753         switch(lsa_hdr.ls_type){
754             case(OSPF_LSTYPE_ROUTER):
755                 memcpy(&router_lsa, &pd[offset], sizeof(e_ospf_router_lsa));
756
757                 /* again: flags should be secified in detail */
758                 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset, 1, "Flags: 0x%02x ", router_lsa.flags);
759                 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 2, 2, "Nr. of Links: %d ", 
760                                                                    ntohs(router_lsa.nr_links));
761                 offset += 4;
762                 /* router_lsa.nr_links links follow 
763                  * maybe we should put each of the links into its own subtree ???
764                  */
765                 for(link_counter = 1 ; link_counter <= ntohs(router_lsa.nr_links); link_counter++){
766
767                     memcpy(&router_data, &pd[offset], sizeof(e_ospf_router_data));
768                     /* check the Link Type and ID */
769                     switch(router_data.link_type) {
770                         case OSPF_LINK_PTP:
771                             link_type="Point-to-point connection to another router";
772                             link_id="Neighboring router's Router ID";
773                             break;
774                         case OSPF_LINK_TRANSIT:
775                             link_type="Connection to a transit network";
776                             link_id="IP address of Designated Router";
777                             break;
778                         case OSPF_LINK_STUB:
779                             link_type="Connection to a stub network";
780                             link_id="IP network/subnet number";
781                             break;
782                         case OSPF_LINK_VIRTUAL:
783                             link_type="Virtual link";
784                             link_id="Neighboring router's Router ID";
785                             break;
786                         default:
787                             link_type="unknown link type";
788                             link_id="unknown link id";
789                     }
790
791                     proto_tree_add_text(ospf_lsa_tree, NullTVB, offset, 4, "%s: %s", link_id,
792                                                    ip_to_str((guint8 *) &(router_data.link_id)));
793
794                     /* link_data should be specified in detail (e.g. network mask) (depends on link type)*/
795                     proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 4, 4, "Link Data: %s", 
796                                                    ip_to_str((guint8 *) &(router_data.link_data)));
797
798                     proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 8, 1, "Link Type: %d - %s", 
799                                                               router_data.link_type, link_type);
800                     proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 9, 1, "Nr. of TOS metrics: %d", router_data.nr_tos);
801                     proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 10, 2, "TOS 0 metric: %d", ntohs( router_data.tos0_metric ));
802
803                     offset += 12;
804
805                     /* router_data.nr_tos metrics may follow each link 
806                      * ATTENTION: TOS metrics are not tested (I don't have TOS based routing)
807                      * please send me a mail if it is/isn't working
808                      */
809
810                     for(tos_counter = 1 ; link_counter <= ntohs(router_data.nr_tos); tos_counter++){
811                         memcpy(&tos_data, &pd[offset], sizeof(e_ospf_router_metric));
812                         proto_tree_add_text(ospf_lsa_tree, NullTVB, offset, 1, "TOS: %d, Metric: %d", 
813                                                 tos_data.tos, ntohs(tos_data.metric));
814                         offset += 4;
815                     }
816                 }
817                 break;
818             case(OSPF_LSTYPE_NETWORK):
819                 memcpy(&network_lsa, &pd[offset], sizeof(e_ospf_network_lsa));
820                 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset, 4, "Netmask: %s", 
821                                                  ip_to_str((guint8 *) &(network_lsa.network_mask)));
822                 offset += 4;
823
824                 while( (lsa_end - offset) >= 4){
825                     attached_router = (guint32 *) &pd[offset];
826                     proto_tree_add_text(ospf_lsa_tree, NullTVB, offset, 4, "Attached Router: %s", 
827                                                  ip_to_str((guint8 *) attached_router));
828                     offset += 4;
829                 }
830                 break;
831             case(OSPF_LSTYPE_SUMMERY):
832                 /* Type 3 and 4 LSAs have the same format */
833             case(OSPF_LSTYPE_ASBR):
834                 memcpy(&summary_lsa, &pd[offset], sizeof(e_ospf_summary_lsa));
835                 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset, 4, "Netmask: %s", 
836                                                  ip_to_str((guint8 *) &(summary_lsa.network_mask)));
837                 /* this routine returns only the TOS 0 metric (even if there are more TOS metrics) */
838                 memcpy(&metric, &pd[offset+4], 4);
839                 metric = ntohl(metric) & 0x00ffffff ;
840                 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 5, 3, "Metric: %d", metric);
841                                                  
842                 /* returns only the TOS 0 metric (even if there are more TOS metrics) */
843                 break;
844             case(OSPF_LSTYPE_ASEXT):
845             case(OSPF_LSTYPE_ASEXT7):
846                 memcpy(&summary_lsa, &pd[offset], sizeof(e_ospf_summary_lsa));
847                 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset, 4, "Netmask: %s", 
848                                                   ip_to_str((guint8 *) &(summary_lsa.network_mask)));
849
850                 /* asext_lsa = (e_ospf_asexternal_lsa *) &pd[offset + 4]; */
851                 memcpy(&asext_lsa, &pd[offset + 4], sizeof(asext_lsa));
852                 if( (asext_lsa.options & 128) == 128 ) { /* check wether or not E bit is set */
853                    proto_tree_add_text(ospf_lsa_tree, NullTVB, offset, 1, 
854                             "External Type: Type 2 (metric is larger than any other link state path)");
855                 } else {
856                    proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 4, 1, 
857                             "External Type: Type 1 (metric is specified in the same units as interface cost)");
858                 }
859                 /* the metric field of a AS-external LAS is specified in 3 bytes -> not well aligned */
860                 /* this routine returns only the TOS 0 metric (even if there are more TOS metrics) */
861                 memcpy(&asext_metric, &pd[offset+4], 4); 
862                 
863                 /* erase the leading 8 bits (the dont belong to the metric */
864                 asext_metric = ntohl(asext_metric) & 0x00ffffff ;
865
866                 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 5,  3,"Metric: %d", asext_metric);
867                 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 8,  4,"Forwarding Address: %s", 
868                                                  ip_to_str((guint8 *) &(asext_lsa.gateway)));
869                 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 12, 4,"External Route Tag: %ld", (long)ntohl(asext_lsa.external_tag)); 
870                     
871                 break;
872
873         case OSPF_LSTYPE_OP_LINKLOCAL:
874         case OSPF_LSTYPE_OP_AREALOCAL:
875         case OSPF_LSTYPE_OP_ASWIDE:
876             dissect_ospf_lsa_opaque(pd, offset, fd, ospf_lsa_tree, &lsa_hdr);
877             break;
878
879         default:
880                /* unknown LSA type */
881                 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset, END_OF_FRAME, "Unknown LSA Type");
882         }
883     }
884     /* return the length of this LSA */
885     return ntohs(lsa_hdr.length);
886 }
887
888 void
889 proto_register_ospf(void)
890 {
891 /*        static hf_register_info hf[] = {
892                 { &variable,
893                 { "Name",           "ospf.abbreviation", TYPE, VALS_POINTER }},
894         };*/
895         static gint *ett[] = {
896                 &ett_ospf,
897                 &ett_ospf_hdr,
898                 &ett_ospf_hello,
899                 &ett_ospf_desc,
900                 &ett_ospf_lsr,
901                 &ett_ospf_lsa,
902                 &ett_ospf_lsa_upd,
903                 &ett_ospf_lsa_mpls,
904                 &ett_ospf_lsa_mpls_router,
905                 &ett_ospf_lsa_mpls_link,
906                 &ett_ospf_lsa_mpls_link_stlv
907         };
908
909         proto_ospf = proto_register_protocol("Open Shortest Path First", "ospf");
910  /*       proto_register_field_array(proto_ospf, hf, array_length(hf));*/
911         proto_register_subtree_array(ett, array_length(ett));
912 }
913
914 void
915 proto_reg_handoff_ospf(void)
916 {
917         old_dissector_add("ip.proto", IP_PROTO_OSPF, dissect_ospf);
918 }