7bf8dc5daa0aa6f50e4a2c1a80972e921705e10f
[obnox/wireshark/wip.git] / packet-igrp.c
1 /* packet-igrp.c
2  * Routines for IGRP dissection
3  * Copyright 2000, Paul Ionescu <paul@acorp.ro>
4  * 
5  * $Id: packet-igrp.c,v 1.10 2001/12/10 00:25:28 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copied from packet-syslog.c
12  * 
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  * 
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <ctype.h>
35
36 #include <string.h>
37 #include <glib.h>
38 #include "packet.h"
39 #include "ipproto.h"
40
41 #define IGRP_HEADER_LENGTH 12
42 #define IGRP_ENTRY_LENGTH 14
43
44 static gint proto_igrp = -1;
45 static gint hf_igrp_update = -1;
46 static gint hf_igrp_as = -1;
47
48 static gint ett_igrp = -1;
49 static gint ett_igrp_vektor = -1;
50 static gint ett_igrp_net = -1;
51
52 static void dissect_vektor_igrp (tvbuff_t *tvb, proto_tree *igrp_vektor_tree, guint8 network);
53
54 static void dissect_igrp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
55 {
56   guint8 ver_and_opcode,version,opcode,update,network;
57   gint offset=IGRP_HEADER_LENGTH;
58   guint16 as,net1,net2,net3;
59   proto_item *ti;
60   proto_tree *igrp_tree, *igrp_vektor_tree;
61   tvbuff_t   *next_tvb; 
62   
63   if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
64     col_set_str(pinfo->cinfo, COL_PROTOCOL, "IGRP");
65   if (check_col(pinfo->cinfo, COL_INFO))
66     col_clear(pinfo->cinfo, COL_INFO);
67     
68   ver_and_opcode = tvb_get_guint8(tvb,0);
69   update         = tvb_get_guint8(tvb,1);
70   as             = tvb_get_ntohs(tvb,2);
71   
72   
73   if (check_col(pinfo->cinfo, COL_INFO)) {
74     switch (ver_and_opcode) {
75     case 0x11:
76         col_add_fstr(pinfo->cinfo, COL_INFO, "Response" );
77         break;
78     case 0x12:
79         col_add_fstr(pinfo->cinfo, COL_INFO, "Request" );
80         break;
81     default:            
82         col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown version or opcode"); 
83     }
84   }
85
86
87
88   
89   if (tree) {
90       ti = proto_tree_add_protocol_format(tree, proto_igrp, tvb, 0,
91         tvb_length(tvb), "Cisco IGRP ");
92         
93       igrp_tree = proto_item_add_subtree(ti, ett_igrp);
94       
95       version = (ver_and_opcode&0xf0)>>4 ; /* version is the fist half of the byte */
96       opcode = ver_and_opcode&0x0f ;       /* opcode is the last half of the byte */
97       
98       proto_tree_add_text(igrp_tree,  tvb, 0,1,"IGRP Version  : %d %s",version,(version==1?" ":" -  Unknown Version, The dissection may be innacurate"));
99       proto_tree_add_text(igrp_tree,  tvb, 0,1,"Command       : %d %s",opcode,(opcode==1?"(Response)":"(Request)"));
100       proto_tree_add_uint(igrp_tree, hf_igrp_update, tvb, 1,1, update);
101       proto_tree_add_uint(igrp_tree, hf_igrp_as, tvb, 2,2,as);
102
103       net1 = tvb_get_ntohs(tvb,4);
104       net2 = tvb_get_ntohs(tvb,6);
105       net3 = tvb_get_ntohs(tvb,8);
106
107       /* this is a ugly hack to find the first byte of the IP source address */
108       network = pinfo->net_src.data[0];
109       
110       ti = proto_tree_add_text(igrp_tree,  tvb, 4,2,"Interior routes : %d",net1);
111         for( ; net1>0 ; net1-- )
112         {
113                 igrp_vektor_tree =  proto_item_add_subtree(ti,ett_igrp_vektor);
114                 next_tvb = tvb_new_subset(tvb, offset, IGRP_ENTRY_LENGTH, -1);
115                 dissect_vektor_igrp (next_tvb,igrp_vektor_tree,network);
116                 offset+=IGRP_ENTRY_LENGTH;
117         }
118
119       ti = proto_tree_add_text(igrp_tree,  tvb, 6,2,"System routes   : %d",net2);
120         for( ; net2>0 ; net2-- )
121         {
122                 igrp_vektor_tree =  proto_item_add_subtree(ti,ett_igrp_vektor);
123                 next_tvb = tvb_new_subset(tvb, offset, IGRP_ENTRY_LENGTH, -1);
124                 dissect_vektor_igrp (next_tvb,igrp_vektor_tree,0);
125                 offset+=IGRP_ENTRY_LENGTH;
126         }
127
128       ti = proto_tree_add_text(igrp_tree,  tvb, 8,2,"Exterior routes : %d",net3);
129         for( ; net3>0 ; net3-- )
130         {
131                 igrp_vektor_tree =  proto_item_add_subtree(ti,ett_igrp_vektor);
132                 next_tvb = tvb_new_subset(tvb, offset, IGRP_ENTRY_LENGTH, -1);
133                 dissect_vektor_igrp (next_tvb,igrp_vektor_tree,0);
134                 offset+=IGRP_ENTRY_LENGTH;
135         }
136
137       proto_tree_add_text(igrp_tree, tvb, 10,2,"Checksum = 0x%4x",tvb_get_ntohs(tvb,10));
138
139   }
140   return;
141 }
142
143 static void dissect_vektor_igrp (tvbuff_t *tvb, proto_tree *igrp_vektor_tree, guint8 network)
144 {
145         proto_item *ti;
146         guint8 *ptr_addr,addr[5];
147
148         addr[0]=network;
149         addr[1]=tvb_get_guint8(tvb,0);
150         addr[2]=tvb_get_guint8(tvb,1);
151         addr[3]=tvb_get_guint8(tvb,2);
152         addr[4]=0;
153
154         ptr_addr=addr;
155         if (network==0) ptr_addr=&addr[1];
156
157         ti = proto_tree_add_text (igrp_vektor_tree, tvb, 0 ,14,
158           "Entry for network %s", ip_to_str(ptr_addr)) ; 
159         igrp_vektor_tree =  proto_item_add_subtree(ti,ett_igrp_net);
160         proto_tree_add_text (igrp_vektor_tree, tvb, 0 ,3,"Network     = %s",ip_to_str(ptr_addr)) ; 
161         proto_tree_add_text (igrp_vektor_tree, tvb, 3 ,3,"Delay       = %d",tvb_get_ntoh24(tvb,3)) ; 
162         proto_tree_add_text (igrp_vektor_tree, tvb, 6 ,3,"Bandwidth   = %d",tvb_get_ntoh24(tvb,6)) ; 
163         proto_tree_add_text (igrp_vektor_tree, tvb, 9 ,2,"MTU         = %d  bytes",tvb_get_ntohs(tvb,9)) ; 
164         proto_tree_add_text (igrp_vektor_tree, tvb, 11,1,"Reliability = %d",tvb_get_guint8(tvb,11)) ; 
165         proto_tree_add_text (igrp_vektor_tree, tvb, 12,1,"Load        = %d",tvb_get_guint8(tvb,12)) ; 
166         proto_tree_add_text (igrp_vektor_tree, tvb, 13,1,"Hop count   = %d  hops",tvb_get_guint8(tvb,13)) ; 
167 }       
168
169  
170 /* Register the protocol with Ethereal */
171 void proto_register_igrp(void)
172 {                 
173
174   /* Setup list of header fields */
175   static hf_register_info hf[] = {
176
177     { &hf_igrp_update,
178       { "Update Release",           "igrp.update",
179       FT_UINT8, BASE_DEC, NULL, 0x0 ,
180       "Update Release number", HFILL }
181     },
182     { &hf_igrp_as,
183       { "Autonomous System",           "igrp.as",
184       FT_UINT16, BASE_DEC, NULL, 0x0 ,
185       "Autonomous System number", HFILL }
186     }
187   };
188
189   /* Setup protocol subtree array */
190   static gint *ett[] = {
191     &ett_igrp,
192     &ett_igrp_vektor,
193     &ett_igrp_net
194   };
195
196   /* Register the protocol name and description */
197   proto_igrp = proto_register_protocol("Cisco Interior Gateway Routing Protocol",
198                                        "IGRP", "igrp");
199
200   /* Required function calls to register the header fields and subtrees used */
201   proto_register_field_array(proto_igrp, hf, array_length(hf));
202   proto_register_subtree_array(ett, array_length(ett));
203 };
204
205 void
206 proto_reg_handoff_igrp(void)
207 {
208   dissector_handle_t igrp_handle;
209
210   igrp_handle = create_dissector_handle(dissect_igrp, proto_igrp);
211   dissector_add("ip.proto", IP_PROTO_IGRP, igrp_handle);
212 }
213
214 /*      IGRP Packet structure:
215
216 HEADER structure + k * VECTOR structure
217 where: k = (Number of Interior routes) + (Number of System routes) + (Number of Exterior routes)
218
219 HEADER structure is 12 bytes as follows :
220
221 4  bits         Version (only version 1 is defined)
222 4  bits         Opcode (1=Replay, 2=Request)
223 8  bits         Update Release 
224 16 bits         Autonomous system number
225 16 bits         Number of Interior routes
226 16 bits         Number of System routes
227 16 bits         Number of Exterior routes
228 16 bits         Checksum
229 -------
230 12 bytes in header
231
232 VECTOR structure is 14 bytes as follows :
233 24 bits         Network
234 24 bits         Delay
235 24 bits         Bandwidth
236 16 bits         MTU
237 8  bits         Reliability
238 8  bits         Load
239 8  bits         Hop count
240 -------
241 14 bytes in 1 vector
242
243 It is interesting how is coded an ip network address in 3 bytes because IGRP is a classful routing protocol:
244 If it is a interior route then this 3 bytes are the final bytes, and the first one is taken from the source ip address of the ip packet
245 If it is a system route or a exterior route then this 3 bytes are the first three and the last byte is not important
246
247 If the Delay is 0xFFFFFF then the network is unreachable
248
249 */