2 * Routines for OSPF packet disassembly
3 * (c) Copyright Hannes R. Boehm <hannes@boehm.org>
5 * $Id: packet-ospf.c,v 1.30 2000/12/14 22:23:15 guy Exp $
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.
12 * TOS - support is not fully implemented
14 * Ethereal - Network traffic analyzer
15 * By Gerald Combs <gerald@zing.org>
16 * Copyright 1998 Gerald Combs
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.
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.
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.
38 #ifdef HAVE_SYS_TYPES_H
39 # include <sys/types.h>
42 #ifdef HAVE_NETINET_IN_H
43 # include <netinet/in.h>
51 #include "packet-ospf.h"
52 #include "packet-ip.h"
54 #include "ieee-float.h"
56 static int proto_ospf = -1;
58 static gint ett_ospf = -1;
59 static gint ett_ospf_hdr = -1;
60 static gint ett_ospf_hello = -1;
61 static gint ett_ospf_desc = -1;
62 static gint ett_ospf_lsr = -1;
63 static gint ett_ospf_lsa = -1;
64 static gint ett_ospf_lsa_upd = -1;
66 /* Trees for opaque LSAs */
67 static gint ett_ospf_lsa_mpls = -1;
68 static gint ett_ospf_lsa_mpls_router = -1;
69 static gint ett_ospf_lsa_mpls_link = -1;
70 static gint ett_ospf_lsa_mpls_link_stlv = -1;
72 static void dissect_ospf_hello(const u_char*, int, frame_data*, proto_tree*);
73 static void dissect_ospf_db_desc(const u_char*, int, frame_data*, proto_tree*);
74 static void dissect_ospf_ls_req(const u_char*, int, frame_data*, proto_tree*);
75 static void dissect_ospf_ls_upd(const u_char*, int, frame_data*, proto_tree*);
76 static void dissect_ospf_ls_ack(const u_char*, int, frame_data*, proto_tree*);
78 /* dissect_ospf_lsa returns the length of the LSA
79 * if disassemble_body is set to FALSE (e.g. in LSA ACK
80 * packets), the LSA-header length is returned (20)
82 static int dissect_ospf_lsa(const u_char*, int, frame_data*, proto_tree*, int disassemble_body);
85 dissect_ospf(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
87 e_ospf_crypto *crypto;
88 int i, saved_len, ospflen;
89 guint length, reported_length;
92 guint16 cksum, computed_cksum;
94 proto_tree *ospf_tree = NULL;
96 proto_tree *ospf_header_tree;
97 char auth_data[(2 * 16) + 1]="";
99 static value_string pt_vals[] = { {OSPF_HELLO, "Hello Packet" },
100 {OSPF_DB_DESC, "DB Descr." },
101 {OSPF_LS_REQ, "LS Request" },
102 {OSPF_LS_UPD, "LS Update" },
103 {OSPF_LS_ACK, "LS Acknowledge" },
106 OLD_CHECK_DISPLAY_AS_DATA(proto_ospf, pd, offset, fd, tree);
108 memcpy(&ospfh, &pd[offset], sizeof(e_ospfhdr));
110 packet_type = match_strval(ospfh.packet_type, pt_vals);
111 if (check_col(fd, COL_PROTOCOL))
112 col_set_str(fd, COL_PROTOCOL, "OSPF");
113 if (check_col(fd, COL_INFO)) {
114 if (packet_type != NULL)
115 col_add_str(fd, COL_INFO, packet_type);
117 col_add_fstr(fd, COL_INFO, "Unknown (%d)", ospfh.packet_type);
121 ti = proto_tree_add_item(tree, proto_ospf, NullTVB, offset, ntohs(ospfh.length), FALSE);
122 ospf_tree = proto_item_add_subtree(ti, ett_ospf);
124 ti = proto_tree_add_text(ospf_tree, NullTVB, offset, OSPF_HEADER_LENGTH, "OSPF Header");
125 ospf_header_tree = proto_item_add_subtree(ti, ett_ospf_hdr);
127 proto_tree_add_text(ospf_header_tree, NullTVB, offset, 1, "OSPF Version: %d", ospfh.version);
128 proto_tree_add_text(ospf_header_tree, NullTVB, offset + 1 , 1, "OSPF Packet Type: %d (%s)",
130 (packet_type != NULL ?
133 proto_tree_add_text(ospf_header_tree, NullTVB, offset + 2 , 2, "Packet Length: %d",
134 ntohs(ospfh.length));
135 proto_tree_add_text(ospf_header_tree, NullTVB, offset + 4 , 4, "Source OSPF Router ID: %s",
137 ip_to_str((guint8 *) &(ospfh.routerid)));
139 proto_tree_add_text(ospf_header_tree, NullTVB, offset + 8 , 4, "Area ID: Backbone");
141 proto_tree_add_text(ospf_header_tree, NullTVB, offset + 8 , 4, "Area ID: %s", ip_to_str((guint8 *) &(ospfh.area)));
143 cksum = ntohs(ospfh.checksum);
144 length = pi.captured_len - offset;
145 reported_length = pi.len - offset;
146 if (!pi.fragmented && length >= reported_length
147 && length >= sizeof(e_ospfhdr)) {
148 /* The packet isn't part of a fragmented datagram and isn't
149 truncated, so we can checksum it. */
151 /* Header, not including the authentication data (the OSPF
152 checksum excludes the 64-bit authentication field). */
153 cksum_vec[0].ptr = &pd[offset];
154 cksum_vec[0].len = 16;
155 if (length > sizeof(e_ospfhdr)) {
156 /* Rest of the packet, again not including the
157 authentication data. */
158 cksum_vec[1].ptr = &pd[offset + sizeof(e_ospfhdr)];
159 cksum_vec[1].len = reported_length - sizeof(e_ospfhdr);
162 /* There's nothing but a header. */
165 computed_cksum = in_cksum(cksum_vec, cksum_vec_len);
166 if (computed_cksum == 0) {
167 proto_tree_add_text(ospf_header_tree, NullTVB,
169 "Packet Checksum: 0x%04x (correct)", cksum);
171 proto_tree_add_text(ospf_header_tree, NullTVB,
173 "Packet Checksum: 0x%04x (incorrect, should be 0x%04x)",
174 cksum, in_cksum_shouldbe(cksum, computed_cksum));
177 proto_tree_add_text(ospf_header_tree, NullTVB, offset + 12 , 2,
178 "Packet Checksum: 0x%04x",
181 switch( ntohs(ospfh.auth_type) ) {
183 proto_tree_add_text(ospf_header_tree, NullTVB, offset + 14 , 2, "Auth Type: none");
184 proto_tree_add_text(ospf_header_tree, NullTVB, offset + 16 , 8, "Auth Data (none)");
186 case OSPF_AUTH_SIMPLE:
187 proto_tree_add_text(ospf_header_tree, NullTVB, offset + 14 , 2, "Auth Type: simple");
188 strncpy(auth_data, (char *) &ospfh.auth_data, 8);
189 proto_tree_add_text(ospf_header_tree, NullTVB, offset + 16 , 8, "Auth Data: %s", auth_data);
191 case OSPF_AUTH_CRYPT:
192 crypto = (e_ospf_crypto *)ospfh.auth_data;
193 proto_tree_add_text(ospf_header_tree, NullTVB, offset + 14 , 2, "Auth Type: crypt");
194 proto_tree_add_text(ospf_header_tree, NullTVB, offset + 18 , 1, "Auth Key ID: %d",
196 proto_tree_add_text(ospf_header_tree, NullTVB, offset + 19 , 1, "Auth Data Length: %d",
198 proto_tree_add_text(ospf_header_tree, NullTVB, offset + 20 , 4, "Auth Crypto Sequence Number: 0x%lx",
199 (unsigned long)ntohl(crypto->sequence_num));
201 ospflen = ntohs(ospfh.length);
202 for (i = 0; i < crypto->length && i < (sizeof(auth_data)/2); i++)
203 sprintf(&auth_data[i*2],"%02x",pd[offset + ospflen + i]);
204 proto_tree_add_text(ospf_header_tree, NullTVB, offset + ospflen , 16, "Auth Data: %s", auth_data);
207 proto_tree_add_text(ospf_header_tree, NullTVB, offset + 14 , 2, "Auth Type (unknown)");
208 proto_tree_add_text(ospf_header_tree, NullTVB, offset + 16 , 8, "Auth Data (unknown)");
213 /* Temporarily adjust the captured length to match the size of the OSPF
214 * packet (since the dissect routines use it to work out where the end of
215 * the ospf packet is).
217 saved_len = pi.captured_len;
218 if (BYTES_ARE_IN_FRAME(offset, ntohs(ospfh.length))) {
219 pi.captured_len = offset + ntohs(ospfh.length);
222 /* Skip over header */
223 offset += OSPF_HEADER_LENGTH;
225 switch(ospfh.packet_type){
227 dissect_ospf_hello(pd, offset, fd, ospf_tree);
230 dissect_ospf_db_desc(pd, offset, fd, ospf_tree);
233 dissect_ospf_ls_req(pd, offset, fd, ospf_tree);
236 dissect_ospf_ls_upd(pd, offset, fd, ospf_tree);
239 dissect_ospf_ls_ack(pd, offset, fd, ospf_tree);
242 pi.captured_len = saved_len;
243 old_dissect_data(pd, offset, fd, tree);
245 pi.captured_len = saved_len;
249 dissect_ospf_hello(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
250 e_ospf_hello ospfhello;
251 guint32 *ospfneighbor;
255 proto_tree *ospf_hello_tree;
258 memcpy(&ospfhello, &pd[offset], sizeof(e_ospf_hello));
261 ti = proto_tree_add_text(tree, NullTVB, offset, END_OF_FRAME, "OSPF Hello Packet");
262 ospf_hello_tree = proto_item_add_subtree(ti, ett_ospf_hello);
265 proto_tree_add_text(ospf_hello_tree, NullTVB, offset , 4, "Network Mask: %s", ip_to_str((guint8 *) &ospfhello.network_mask));
266 proto_tree_add_text(ospf_hello_tree, NullTVB, offset + 4, 2, "Hello Interval: %d seconds", ntohs(ospfhello.hellointervall));
268 /* ATTENTION !!! no check for length of options string */
270 if(( ospfhello.options & OSPF_OPTIONS_E ) == OSPF_OPTIONS_E){
271 strcpy( (char *)(options + options_offset), "E");
274 if(( ospfhello.options & OSPF_OPTIONS_MC ) == OSPF_OPTIONS_MC){
275 strcpy((char *) (options + options_offset), "/MC");
278 if(( ospfhello.options & OSPF_OPTIONS_NP ) == OSPF_OPTIONS_NP){
279 strcpy((char *) (options + options_offset), "/NP");
282 if(( ospfhello.options & OSPF_OPTIONS_EA ) == OSPF_OPTIONS_EA){
283 strcpy((char *) (options + options_offset) , "/EA");
286 if(( ospfhello.options & OSPF_OPTIONS_DC ) == OSPF_OPTIONS_DC){
287 strcpy((char *) (options + options_offset) , "/DC");
291 proto_tree_add_text(ospf_hello_tree, NullTVB, offset + 6, 1, "Options: %d (%s)", ospfhello.options, options);
292 proto_tree_add_text(ospf_hello_tree, NullTVB, offset + 7, 1, "Router Priority: %d", ospfhello.priority);
293 proto_tree_add_text(ospf_hello_tree, NullTVB, offset + 8, 4, "Router Dead Interval: %ld seconds", (long)ntohl(ospfhello.dead_interval));
294 proto_tree_add_text(ospf_hello_tree, NullTVB, offset + 12, 4, "Designated Router: %s", ip_to_str((guint8 *) &ospfhello.drouter));
295 proto_tree_add_text(ospf_hello_tree, NullTVB, offset + 16, 4, "Backup Designated Router: %s", ip_to_str((guint8 *) &ospfhello.bdrouter));
299 while(((int)(pi.captured_len - offset)) >= 4){
300 ospfneighbor=(guint32 *) &pd[offset];
301 proto_tree_add_text(ospf_hello_tree, NullTVB, offset, 4, "Active Neighbor: %s", ip_to_str((guint8 *) ospfneighbor));
308 dissect_ospf_db_desc(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
315 proto_tree *ospf_db_desc_tree=NULL;
318 memcpy(&ospf_dbd, &pd[offset], sizeof(e_ospf_dbd));
321 ti = proto_tree_add_text(tree, NullTVB, offset, END_OF_FRAME, "OSPF DB Description");
322 ospf_db_desc_tree = proto_item_add_subtree(ti, ett_ospf_desc);
324 proto_tree_add_text(ospf_db_desc_tree, NullTVB, offset, 2, "Interface MTU: %d", ntohs(ospf_dbd.interface_mtu) );
328 if(( ospf_dbd.options & OSPF_OPTIONS_E ) == OSPF_OPTIONS_E){
329 strcpy( (char *)(options + options_offset), "_E_");
332 if(( ospf_dbd.options & OSPF_OPTIONS_MC ) == OSPF_OPTIONS_MC){
333 strcpy((char *) (options + options_offset), "_MC_");
336 if(( ospf_dbd.options & OSPF_OPTIONS_NP ) == OSPF_OPTIONS_NP){
337 strcpy((char *) (options + options_offset), "_NP_");
340 if(( ospf_dbd.options & OSPF_OPTIONS_EA ) == OSPF_OPTIONS_EA){
341 strcpy((char *) (options + options_offset) , "_EA_");
344 if(( ospf_dbd.options & OSPF_OPTIONS_DC ) == OSPF_OPTIONS_DC){
345 strcpy((char *) (options + options_offset) , "_DC_");
349 proto_tree_add_text(ospf_db_desc_tree, NullTVB, offset + 2 , 1, "Options: %d (%s)", ospf_dbd.options, options );
353 if(( ospf_dbd.flags & OSPF_DBD_FLAG_MS ) == OSPF_DBD_FLAG_MS){
354 strcpy( (char *)(flags + flags_offset), "_MS_");
357 if(( ospf_dbd.flags & OSPF_DBD_FLAG_M ) == OSPF_DBD_FLAG_M){
358 strcpy((char *) (flags + flags_offset), "_M_");
361 if(( ospf_dbd.flags & OSPF_DBD_FLAG_I ) == OSPF_DBD_FLAG_I){
362 strcpy((char *) (flags + flags_offset), "_I_");
366 proto_tree_add_text(ospf_db_desc_tree, NullTVB, offset + 3 , 1, "Flags: %d (%s)", ospf_dbd.flags, flags );
367 proto_tree_add_text(ospf_db_desc_tree, NullTVB, offset + 4 , 4, "DD Sequence: %ld", (long)ntohl(ospf_dbd.dd_sequence) );
369 /* LS Headers will be processed here */
370 /* skip to the end of DB-Desc header */
372 while( ((int) (pi.captured_len - offset)) >= OSPF_LSA_HEADER_LENGTH ) {
373 dissect_ospf_lsa(pd, offset, fd, tree, FALSE);
374 offset+=OSPF_LSA_HEADER_LENGTH;
379 dissect_ospf_ls_req(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
380 e_ospf_ls_req ospf_lsr;
382 proto_tree *ospf_lsr_tree;
386 /* zero or more LS requests may be within a LS Request */
387 /* we place every request for a LSA in a single subtree */
389 while( ((int) (pi.captured_len - offset)) >= OSPF_LS_REQ_LENGTH ){
390 memcpy(&ospf_lsr, &pd[offset], sizeof(e_ospf_ls_req));
391 ti = proto_tree_add_text(tree, NullTVB, offset, OSPF_LS_REQ_LENGTH, "Link State Request");
392 ospf_lsr_tree = proto_item_add_subtree(ti, ett_ospf_lsr);
394 switch( ntohl( ospf_lsr.ls_type ) ){
395 case OSPF_LSTYPE_ROUTER:
396 proto_tree_add_text(ospf_lsr_tree, NullTVB, offset, 4, "LS Type: Router-LSA (%ld)",
397 (long)ntohl( ospf_lsr.ls_type ) );
399 case OSPF_LSTYPE_NETWORK:
400 proto_tree_add_text(ospf_lsr_tree, NullTVB, offset, 4, "LS Type: Network-LSA (%ld)",
401 (long)ntohl( ospf_lsr.ls_type ) );
403 case OSPF_LSTYPE_SUMMERY:
404 proto_tree_add_text(ospf_lsr_tree, NullTVB, offset, 4, "LS Type: Summary-LSA (IP network) (%ld)",
405 (long)ntohl( ospf_lsr.ls_type ) );
407 case OSPF_LSTYPE_ASBR:
408 proto_tree_add_text(ospf_lsr_tree, NullTVB, offset, 4, "LS Type: Summary-LSA (ASBR) (%ld)",
409 (long)ntohl( ospf_lsr.ls_type ) );
411 case OSPF_LSTYPE_ASEXT:
412 proto_tree_add_text(ospf_lsr_tree, NullTVB, offset, 4, "LS Type: AS-External-LSA (ASBR) (%ld)",
413 (long)ntohl( ospf_lsr.ls_type ) );
416 proto_tree_add_text(ospf_lsr_tree, NullTVB, offset, 4, "LS Type: %ld (unknown)",
417 (long)ntohl( ospf_lsr.ls_type ) );
420 proto_tree_add_text(ospf_lsr_tree, NullTVB, offset + 4, 4, "Link State ID : %s",
421 ip_to_str((guint8 *) &(ospf_lsr.ls_id)));
422 proto_tree_add_text(ospf_lsr_tree, NullTVB, offset + 8, 4, "Advertising Router : %s",
423 ip_to_str((guint8 *) &(ospf_lsr.adv_router)));
431 dissect_ospf_ls_upd(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
432 e_ospf_lsa_upd_hdr upd_hdr;
435 proto_tree *ospf_lsa_upd_tree=NULL;
438 memcpy(&upd_hdr, &pd[offset], sizeof(e_ospf_lsa_upd_hdr));
441 ti = proto_tree_add_text(tree, NullTVB, offset, END_OF_FRAME, "LS Update Packet");
442 ospf_lsa_upd_tree = proto_item_add_subtree(ti, ett_ospf_lsa_upd);
444 proto_tree_add_text(ospf_lsa_upd_tree, NullTVB, offset, 4, "Nr oF LSAs: %ld", (long)ntohl(upd_hdr.lsa_nr) );
446 /* skip to the beginning of the first LSA */
447 offset+=4; /* the LS Upd PAcket contains only a 32 bit #LSAs field */
450 while(lsa_counter < ntohl(upd_hdr.lsa_nr)){
451 offset+=dissect_ospf_lsa(pd, offset, fd, ospf_lsa_upd_tree, TRUE);
457 dissect_ospf_ls_ack(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
459 /* the body of a LS Ack packet simply contains zero or more LSA Headers */
460 while( ((int)(pi.captured_len - offset)) >= OSPF_LSA_HEADER_LENGTH ) {
461 dissect_ospf_lsa(pd, offset, fd, tree, FALSE);
462 offset+=OSPF_LSA_HEADER_LENGTH;
468 * Returns if an LSA is opaque, i.e. requires special treatment
470 int is_opaque(int lsa_type)
472 return (lsa_type >= 9 && lsa_type <= 11);
475 /* MPLS/TE TLV types */
476 #define MPLS_TLV_ROUTER 1
477 #define MPLS_TLV_LINK 2
479 /* MPLS/TE Link STLV types */
487 MPLS_LINK_MAX_RES_BW,
492 static value_string mpls_link_stlv_str[] = {
493 {MPLS_LINK_TYPE, "Link Type"},
494 {MPLS_LINK_ID, "Link ID"},
495 {MPLS_LINK_LOCAL_IF, "Local Interface IP Address"},
496 {MPLS_LINK_REMOTE_IF, "Remote Interface IP Address"},
497 {MPLS_LINK_TE_METRIC, "Traffic Engineering Metric"},
498 {MPLS_LINK_MAX_BW, "Maximum Bandwidth"},
499 {MPLS_LINK_MAX_RES_BW, "Maximum Reservable Bandwidth"},
500 {MPLS_LINK_UNRES_BW, "Unreserved Bandwidth"},
501 {MPLS_LINK_COLOR, "Resource Class/Color"},
505 * Dissect MPLS/TE opaque LSA
508 void dissect_ospf_lsa_mpls(const u_char *pd,
512 e_ospf_lsa_hdr *lsa_hdr) {
514 proto_tree *mpls_tree;
515 proto_tree *tlv_tree;
516 proto_tree *stlv_tree;
523 int stlv_type, stlv_len;
527 ti = proto_tree_add_text(tree, NullTVB, offset, ntohs(lsa_hdr->length) - 20,
528 "MPLS Traffic Engineering LSA");
529 mpls_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls);
531 for (length = 0; length < ntohs(lsa_hdr->length) - 20; length += 4) {
532 tlv_type = pntohs(pd+offset+length);
533 tlv_length = pntohs(pd+offset+length + 2);
536 case MPLS_TLV_ROUTER:
537 ti = proto_tree_add_text(mpls_tree, NullTVB, offset+length, tlv_length+4,
538 "Router Address: %s",
539 ip_to_str((pd+offset+length+4)));
540 tlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_router);
541 proto_tree_add_text(tlv_tree, NullTVB, offset+length, 2, "TLV Type: 1 - Router Address");
542 proto_tree_add_text(tlv_tree, NullTVB, offset+length+2, 2, "TLV Length: %d", tlv_length);
543 proto_tree_add_text(tlv_tree, NullTVB, offset+length+4, 4, "Router Address: %s",
544 ip_to_str((pd+offset+length+4)));
547 ti = proto_tree_add_text(mpls_tree, NullTVB, offset+length, tlv_length+4,
549 tlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link);
550 proto_tree_add_text(tlv_tree, NullTVB, offset+length, 2, "TLV Type: 2 - Link Information");
551 proto_tree_add_text(tlv_tree, NullTVB, offset+length+2, 2, "TLV Length: %d", tlv_length);
553 /* Walk down the sub-TLVs for link information */
554 for (link_len = length + 4; link_len < length + 4 + tlv_length; link_len += 4) {
555 stlv_type = pntohs(pd+offset+link_len);
556 stlv_len = pntohs(pd+offset+link_len + 2);
557 stlv_name = val_to_str(stlv_type, mpls_link_stlv_str, "Unknown sub-TLV");
561 ti = proto_tree_add_text(tlv_tree, NullTVB, offset+link_len, stlv_len+4,
563 *((guint8 *)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, 1, "%s: %d", stlv_name,
569 *((guint8 *)pd + offset + link_len + 4));
573 ti = proto_tree_add_text(tlv_tree, NullTVB, offset+link_len, stlv_len+4,
574 "%s: %s (%x)", stlv_name,
575 ip_to_str(pd + offset + link_len + 4),
576 pntohl(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: %s (%x)", stlv_name,
582 ip_to_str(pd + offset + link_len + 4),
583 pntohl(pd + offset + link_len + 4));
586 case MPLS_LINK_LOCAL_IF:
587 case MPLS_LINK_REMOTE_IF:
588 ti = proto_tree_add_text(tlv_tree, NullTVB, offset+link_len, stlv_len+4,
590 ip_to_str(pd+offset+link_len+4));
591 stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
592 proto_tree_add_text(stlv_tree, NullTVB, offset+link_len, 2,
593 "TLV Type: %d: %s", stlv_type, stlv_name);
594 proto_tree_add_text(stlv_tree, NullTVB, offset+link_len+2, 2, "TLV Length: %d", stlv_len);
595 proto_tree_add_text(stlv_tree, NullTVB, offset+link_len+4, 4, "%s: %s", stlv_name,
596 ip_to_str(pd+offset+link_len+4));
600 case MPLS_LINK_TE_METRIC:
601 case MPLS_LINK_COLOR:
602 ti = proto_tree_add_text(tlv_tree, NullTVB, offset+link_len, stlv_len+4,
604 pntohl(pd + offset + link_len + 4));
605 stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
606 proto_tree_add_text(stlv_tree, NullTVB, offset+link_len, 2,
607 "TLV Type: %d: %s", stlv_type, stlv_name);
608 proto_tree_add_text(stlv_tree, NullTVB, offset+link_len+2, 2, "TLV Length: %d", stlv_len);
609 proto_tree_add_text(stlv_tree, NullTVB, offset+link_len+4, 4, "%s: %d", stlv_name,
610 pntohl(pd + offset + link_len + 4));
613 case MPLS_LINK_MAX_BW:
614 case MPLS_LINK_MAX_RES_BW:
615 ti = proto_tree_add_text(tlv_tree, NullTVB, offset+link_len, stlv_len+4,
616 "%s: %ld", stlv_name,
617 pieee_to_long(pd + offset + link_len + 4));
618 stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
619 proto_tree_add_text(stlv_tree, NullTVB, offset+link_len, 2,
620 "TLV Type: %d: %s", stlv_type, stlv_name);
621 proto_tree_add_text(stlv_tree, NullTVB, offset+link_len+2, 2, "TLV Length: %d", stlv_len);
622 proto_tree_add_text(stlv_tree, NullTVB, offset+link_len+4, 4, "%s: %ld", stlv_name,
623 pieee_to_long(pd + offset + link_len + 4));
626 case MPLS_LINK_UNRES_BW:
627 ti = proto_tree_add_text(tlv_tree, NullTVB, offset+link_len, stlv_len+4,
629 stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
630 proto_tree_add_text(stlv_tree, NullTVB, offset+link_len, 2,
631 "TLV Type: %d: %s", stlv_type, stlv_name);
632 proto_tree_add_text(stlv_tree, NullTVB, offset+link_len+2, 2, "TLV Length: %d", stlv_len);
634 proto_tree_add_text(stlv_tree, NullTVB, offset+link_len+4+(i*4), 4,
636 pieee_to_long(pd + offset + link_len + 4 + i*4));
640 proto_tree_add_text(tlv_tree, NullTVB, offset+link_len, stlv_len+4,
641 "Unknown Link sub-TLV: %d", stlv_type);
643 link_len += ((stlv_len+3)/4)*4;
649 ti = proto_tree_add_text(mpls_tree, NullTVB, offset+length, tlv_length+4,
650 "Unknown LSA: %d", tlv_type);
651 tlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link);
652 proto_tree_add_text(tlv_tree, NullTVB, offset+length, 2, "TLV Type: %d - Unknown", tlv_type);
653 proto_tree_add_text(tlv_tree, NullTVB, offset+length+2, 2, "TLV Length: %d", tlv_length);
654 proto_tree_add_text(tlv_tree, NullTVB, offset+length+4, tlv_length, "TLV Data");
658 length += tlv_length;
664 * Dissect opaque LSAs
666 void dissect_ospf_lsa_opaque(const u_char *pd,
670 e_ospf_lsa_hdr *lsa_hdr) {
671 guint8 opaque_id = *((guint8 *) &(lsa_hdr->ls_id));
675 case OSPF_LSA_MPLS_TE:
676 dissect_ospf_lsa_mpls(pd, offset, fd, tree, lsa_hdr);
680 proto_tree_add_text(tree, NullTVB, offset, END_OF_FRAME, "Unknown LSA Type");
682 } /* switch on opaque LSA id */
686 dissect_ospf_lsa(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int disassemble_body) {
687 e_ospf_lsa_hdr lsa_hdr;
691 /* data strutures for the router LSA */
692 e_ospf_router_lsa router_lsa;
693 e_ospf_router_data router_data;
694 e_ospf_router_metric tos_data;
695 guint16 link_counter;
700 /* data structures for the network lsa */
701 e_ospf_network_lsa network_lsa;
702 guint32 *attached_router;
704 /* data structures for the summary and ASBR LSAs */
705 e_ospf_summary_lsa summary_lsa;
708 /* data structures for the AS-External LSA */
709 e_ospf_asexternal_lsa asext_lsa;
710 guint32 asext_metric;
712 /* data structures for opaque LSA */
715 proto_tree *ospf_lsa_tree;
718 memcpy(&lsa_hdr, &pd[offset], sizeof(e_ospf_lsa_hdr));
722 switch(lsa_hdr.ls_type) {
723 case OSPF_LSTYPE_ROUTER:
724 lsa_type="Router LSA";
726 case OSPF_LSTYPE_NETWORK:
727 lsa_type="Network LSA";
729 case OSPF_LSTYPE_SUMMERY:
730 lsa_type="Summary LSA";
732 case OSPF_LSTYPE_ASBR:
735 case OSPF_LSTYPE_ASEXT:
736 lsa_type="AS-external-LSA";
738 case OSPF_LSTYPE_ASEXT7:
739 lsa_type="AS-external-LSA Type 7/NSSA";
741 case OSPF_LSTYPE_OP_LINKLOCAL:
742 lsa_type="Opaque LSA, Link-local scope";
744 case OSPF_LSTYPE_OP_AREALOCAL:
745 lsa_type="Opaque LSA, Area-local scope";
747 case OSPF_LSTYPE_OP_ASWIDE:
748 lsa_type="Opaque LSA, AS-wide scope";
755 if(disassemble_body){
756 ti = proto_tree_add_text(tree, NullTVB, offset, ntohs(lsa_hdr.length),
757 "%s (Type: %d)", lsa_type, lsa_hdr.ls_type);
759 ti = proto_tree_add_text(tree, NullTVB, offset, OSPF_LSA_HEADER_LENGTH, "LSA Header");
761 ospf_lsa_tree = proto_item_add_subtree(ti, ett_ospf_lsa);
764 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset, 2, "LS Age: %d seconds", ntohs(lsa_hdr.ls_age));
765 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 2, 1, "Options: %d ", lsa_hdr.options);
766 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 3, 1, "LSA Type: %d (%s)", lsa_hdr.ls_type, lsa_type);
768 if (is_opaque(lsa_hdr.ls_type)) {
769 ls_id = ntohl(lsa_hdr.ls_id);
770 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 4, 1, "Link State ID Opaque Type: %u ",
771 (ls_id >> 24) & 0xff);
772 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 5, 3, "Link State ID Opaque ID: %u ",
775 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 4, 4, "Link State ID: %s ",
776 ip_to_str((guint8 *) &(lsa_hdr.ls_id)));
778 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 8, 4, "Advertising Router: %s ",
779 ip_to_str((guint8 *) &(lsa_hdr.adv_router)));
780 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 12, 4, "LS Sequence Number: 0x%04lx ",
781 (unsigned long)ntohl(lsa_hdr.ls_seq));
782 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 16, 2, "LS Checksum: %04x ", ntohs(lsa_hdr.ls_checksum));
784 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 18, 2, "Length: %d ", ntohs(lsa_hdr.length));
786 if(!disassemble_body){
787 return OSPF_LSA_HEADER_LENGTH;
790 lsa_end = offset + ntohs(lsa_hdr.length);
791 /* the LSA body starts after 20 bytes of LSA Header */
794 switch(lsa_hdr.ls_type){
795 case(OSPF_LSTYPE_ROUTER):
796 memcpy(&router_lsa, &pd[offset], sizeof(e_ospf_router_lsa));
798 /* again: flags should be secified in detail */
799 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset, 1, "Flags: 0x%02x ", router_lsa.flags);
800 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 2, 2, "Nr. of Links: %d ",
801 ntohs(router_lsa.nr_links));
803 /* router_lsa.nr_links links follow
804 * maybe we should put each of the links into its own subtree ???
806 for(link_counter = 1 ; link_counter <= ntohs(router_lsa.nr_links); link_counter++){
808 memcpy(&router_data, &pd[offset], sizeof(e_ospf_router_data));
809 /* check the Link Type and ID */
810 switch(router_data.link_type) {
812 link_type="Point-to-point connection to another router";
813 link_id="Neighboring router's Router ID";
815 case OSPF_LINK_TRANSIT:
816 link_type="Connection to a transit network";
817 link_id="IP address of Designated Router";
820 link_type="Connection to a stub network";
821 link_id="IP network/subnet number";
823 case OSPF_LINK_VIRTUAL:
824 link_type="Virtual link";
825 link_id="Neighboring router's Router ID";
828 link_type="unknown link type";
829 link_id="unknown link id";
832 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset, 4, "%s: %s", link_id,
833 ip_to_str((guint8 *) &(router_data.link_id)));
835 /* link_data should be specified in detail (e.g. network mask) (depends on link type)*/
836 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 4, 4, "Link Data: %s",
837 ip_to_str((guint8 *) &(router_data.link_data)));
839 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 8, 1, "Link Type: %d - %s",
840 router_data.link_type, link_type);
841 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 9, 1, "Nr. of TOS metrics: %d", router_data.nr_tos);
842 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 10, 2, "TOS 0 metric: %d", ntohs( router_data.tos0_metric ));
846 /* router_data.nr_tos metrics may follow each link
847 * ATTENTION: TOS metrics are not tested (I don't have TOS based routing)
848 * please send me a mail if it is/isn't working
851 for(tos_counter = 1 ; link_counter <= ntohs(router_data.nr_tos); tos_counter++){
852 memcpy(&tos_data, &pd[offset], sizeof(e_ospf_router_metric));
853 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset, 1, "TOS: %d, Metric: %d",
854 tos_data.tos, ntohs(tos_data.metric));
859 case(OSPF_LSTYPE_NETWORK):
860 memcpy(&network_lsa, &pd[offset], sizeof(e_ospf_network_lsa));
861 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset, 4, "Netmask: %s",
862 ip_to_str((guint8 *) &(network_lsa.network_mask)));
865 while( (lsa_end - offset) >= 4){
866 attached_router = (guint32 *) &pd[offset];
867 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset, 4, "Attached Router: %s",
868 ip_to_str((guint8 *) attached_router));
872 case(OSPF_LSTYPE_SUMMERY):
873 /* Type 3 and 4 LSAs have the same format */
874 case(OSPF_LSTYPE_ASBR):
875 memcpy(&summary_lsa, &pd[offset], sizeof(e_ospf_summary_lsa));
876 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset, 4, "Netmask: %s",
877 ip_to_str((guint8 *) &(summary_lsa.network_mask)));
878 /* this routine returns only the TOS 0 metric (even if there are more TOS metrics) */
879 memcpy(&metric, &pd[offset+4], 4);
880 metric = ntohl(metric) & 0x00ffffff ;
881 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 5, 3, "Metric: %d", metric);
883 /* returns only the TOS 0 metric (even if there are more TOS metrics) */
885 case(OSPF_LSTYPE_ASEXT):
886 case(OSPF_LSTYPE_ASEXT7):
887 memcpy(&summary_lsa, &pd[offset], sizeof(e_ospf_summary_lsa));
888 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset, 4, "Netmask: %s",
889 ip_to_str((guint8 *) &(summary_lsa.network_mask)));
891 /* asext_lsa = (e_ospf_asexternal_lsa *) &pd[offset + 4]; */
892 memcpy(&asext_lsa, &pd[offset + 4], sizeof(asext_lsa));
893 if( (asext_lsa.options & 128) == 128 ) { /* check wether or not E bit is set */
894 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset, 1,
895 "External Type: Type 2 (metric is larger than any other link state path)");
897 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 4, 1,
898 "External Type: Type 1 (metric is specified in the same units as interface cost)");
900 /* the metric field of a AS-external LAS is specified in 3 bytes -> not well aligned */
901 /* this routine returns only the TOS 0 metric (even if there are more TOS metrics) */
902 memcpy(&asext_metric, &pd[offset+4], 4);
904 /* erase the leading 8 bits (the dont belong to the metric */
905 asext_metric = ntohl(asext_metric) & 0x00ffffff ;
907 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 5, 3,"Metric: %d", asext_metric);
908 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 8, 4,"Forwarding Address: %s",
909 ip_to_str((guint8 *) &(asext_lsa.gateway)));
910 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset + 12, 4,"External Route Tag: %ld", (long)ntohl(asext_lsa.external_tag));
914 case OSPF_LSTYPE_OP_LINKLOCAL:
915 case OSPF_LSTYPE_OP_AREALOCAL:
916 case OSPF_LSTYPE_OP_ASWIDE:
917 dissect_ospf_lsa_opaque(pd, offset, fd, ospf_lsa_tree, &lsa_hdr);
921 /* unknown LSA type */
922 proto_tree_add_text(ospf_lsa_tree, NullTVB, offset, END_OF_FRAME, "Unknown LSA Type");
925 /* return the length of this LSA */
926 return ntohs(lsa_hdr.length);
930 proto_register_ospf(void)
932 /* static hf_register_info hf[] = {
934 { "Name", "ospf.abbreviation", TYPE, VALS_POINTER }},
936 static gint *ett[] = {
945 &ett_ospf_lsa_mpls_router,
946 &ett_ospf_lsa_mpls_link,
947 &ett_ospf_lsa_mpls_link_stlv
950 proto_ospf = proto_register_protocol("Open Shortest Path First", "ospf");
951 /* proto_register_field_array(proto_ospf, hf, array_length(hf));*/
952 proto_register_subtree_array(ett, array_length(ett));
956 proto_reg_handoff_ospf(void)
958 old_dissector_add("ip.proto", IP_PROTO_OSPF, dissect_ospf);