checkAPIs.pl: support for new-style dissectors in check_hf_entries
[metze/wireshark/wip.git] / epan / dissectors / packet-igrp.c
1 /* packet-igrp.c
2  * Routines for IGRP dissection
3  * Copyright 2000, Paul Ionescu <paul@acorp.ro>
4  *
5  * See
6  *
7  *   http://www.cisco.com/en/US/tech/tk365/technologies_white_paper09186a00800c8ae1.shtml
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * Copied from packet-syslog.c
14  *
15  * SPDX-License-Identifier: GPL-2.0-or-later
16  */
17
18 #include "config.h"
19
20 #include <epan/packet.h>
21 #include <epan/expert.h>
22 #include <epan/to_str.h>
23 #include <epan/ipproto.h>
24
25 void proto_register_igrp(void);
26 void proto_reg_handoff_igrp(void);
27
28 #define IGRP_HEADER_LENGTH 12
29 #define IGRP_ENTRY_LENGTH 14
30
31 static gint proto_igrp = -1;
32 static gint hf_igrp_update = -1;
33 static gint hf_igrp_as = -1;
34 /* Generated from convert_proto_tree_add_text.pl */
35 static int hf_igrp_load = -1;
36 static int hf_igrp_bandwidth = -1;
37 static int hf_igrp_command = -1;
38 static int hf_igrp_reliability = -1;
39 static int hf_igrp_network = -1;
40 static int hf_igrp_version = -1;
41 static int hf_igrp_interior_routes = -1;
42 static int hf_igrp_mtu = -1;
43 static int hf_igrp_hop_count = -1;
44 static int hf_igrp_exterior_routes = -1;
45 static int hf_igrp_delay = -1;
46 static int hf_igrp_checksum = -1;
47 static int hf_igrp_system_routes = -1;
48 static gint ett_igrp = -1;
49 static gint ett_igrp_vektor = -1;
50 static gint ett_igrp_net = -1;
51
52 static expert_field ei_igrp_version = EI_INIT;
53
54 static void dissect_vektor_igrp (tvbuff_t *tvb, proto_tree *igrp_vektor_tree, guint8 network);
55
56 static int dissect_igrp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
57 {
58   guint8 ver_and_opcode,version,opcode,network;
59   gint offset=IGRP_HEADER_LENGTH;
60   guint16 ninterior,nsystem,nexterior;
61   const guint8 *ipsrc;
62   proto_item *ti;
63   proto_tree *igrp_tree, *igrp_vektor_tree;
64   tvbuff_t   *next_tvb;
65
66   col_set_str(pinfo->cinfo, COL_PROTOCOL, "IGRP");
67   col_clear(pinfo->cinfo, COL_INFO);
68
69   ver_and_opcode = tvb_get_guint8(tvb,0);
70
71   switch (ver_and_opcode) {
72   case 0x11:
73     col_set_str(pinfo->cinfo, COL_INFO, "Response" );
74     break;
75   case 0x12:
76     col_set_str(pinfo->cinfo, COL_INFO, "Request" );
77     break;
78   default:
79     col_set_str(pinfo->cinfo, COL_INFO, "Unknown version or opcode");
80   }
81
82
83   if (tree) {
84     ti = proto_tree_add_protocol_format(tree, proto_igrp, tvb, 0, -1,
85                                         "Cisco IGRP");
86
87     igrp_tree = proto_item_add_subtree(ti, ett_igrp);
88
89     version = (ver_and_opcode&0xf0)>>4 ; /* version is the fist half of the byte */
90     opcode = ver_and_opcode&0x0f ;       /* opcode is the last half of the byte */
91
92     ti = proto_tree_add_item(igrp_tree, hf_igrp_version, tvb, 0, 1, ENC_BIG_ENDIAN);
93     if (version != 1)
94         expert_add_info(pinfo, ti, &ei_igrp_version);
95     ti = proto_tree_add_item(igrp_tree, hf_igrp_command, tvb, 0, 1, ENC_BIG_ENDIAN);
96     if (opcode==1)
97         proto_item_append_text(ti, " (Response)");
98     else
99         proto_item_append_text(ti, " (Request)");
100     proto_tree_add_item(igrp_tree, hf_igrp_update, tvb, 1,1, ENC_BIG_ENDIAN);
101     proto_tree_add_item(igrp_tree, hf_igrp_as, tvb, 2,2, ENC_BIG_ENDIAN);
102
103     ninterior = tvb_get_ntohs(tvb,4);
104     nsystem = tvb_get_ntohs(tvb,6);
105     nexterior = tvb_get_ntohs(tvb,8);
106
107     /* this is a ugly hack to find the first byte of the IP source address */
108     if (pinfo->net_src.type == AT_IPv4) {
109       ipsrc = (const guint8 *)pinfo->net_src.data;
110       network = ipsrc[0];
111     } else
112       network = 0; /* XXX - shouldn't happen */
113
114     ti = proto_tree_add_item(igrp_tree, hf_igrp_interior_routes, tvb, 4, 2, ENC_BIG_ENDIAN);
115     for( ; ninterior>0 ; ninterior-- ) {
116       igrp_vektor_tree =  proto_item_add_subtree(ti,ett_igrp_vektor);
117       next_tvb = tvb_new_subset_length_caplen(tvb, offset, IGRP_ENTRY_LENGTH, -1);
118       dissect_vektor_igrp (next_tvb,igrp_vektor_tree,network);
119       offset+=IGRP_ENTRY_LENGTH;
120     }
121
122     ti = proto_tree_add_item(igrp_tree, hf_igrp_system_routes, tvb, 6, 2, ENC_BIG_ENDIAN);
123     for( ; nsystem>0 ; nsystem-- ) {
124       igrp_vektor_tree =  proto_item_add_subtree(ti,ett_igrp_vektor);
125       next_tvb = tvb_new_subset_length_caplen(tvb, offset, IGRP_ENTRY_LENGTH, -1);
126       dissect_vektor_igrp (next_tvb,igrp_vektor_tree,0);
127       offset+=IGRP_ENTRY_LENGTH;
128     }
129
130     ti = proto_tree_add_item(igrp_tree, hf_igrp_exterior_routes, tvb, 8, 2, ENC_BIG_ENDIAN);
131     for( ; nexterior>0 ; nexterior-- ) {
132       igrp_vektor_tree =  proto_item_add_subtree(ti,ett_igrp_vektor);
133       next_tvb = tvb_new_subset_length_caplen(tvb, offset, IGRP_ENTRY_LENGTH, -1);
134       dissect_vektor_igrp (next_tvb,igrp_vektor_tree,0);
135       offset+=IGRP_ENTRY_LENGTH;
136     }
137
138     proto_tree_add_checksum(igrp_tree, tvb, 10, hf_igrp_checksum, -1, NULL, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
139   }
140   return tvb_captured_length(tvb);
141 }
142
143 static void dissect_vektor_igrp (tvbuff_t *tvb, proto_tree *igrp_vektor_tree, guint8 network)
144 {
145   union {
146     guint8 addr_bytes[4];
147     guint32 addr_word;
148   } addr;
149   address ip_addr;
150
151   if (network != 0) {
152     /*
153      * Interior route; network is the high-order byte, and the three
154      * bytes in the vector are the lower 3 bytes.
155      */
156     addr.addr_bytes[0]=network;
157     addr.addr_bytes[1]=tvb_get_guint8(tvb,0);
158     addr.addr_bytes[2]=tvb_get_guint8(tvb,1);
159     addr.addr_bytes[3]=tvb_get_guint8(tvb,2);
160   } else {
161     /*
162      * System or exterior route; the three bytes in the vector are
163      * the three high-order bytes, and the low-order byte is 0.
164      */
165     addr.addr_bytes[0]=tvb_get_guint8(tvb,0);
166     addr.addr_bytes[1]=tvb_get_guint8(tvb,1);
167     addr.addr_bytes[2]=tvb_get_guint8(tvb,2);
168     addr.addr_bytes[3]=0;
169   }
170
171   set_address(&ip_addr, AT_IPv4, 4, &addr);
172   igrp_vektor_tree = proto_tree_add_subtree_format(igrp_vektor_tree, tvb, 0 ,14,
173                                                    ett_igrp_net, NULL, "Entry for network %s", address_to_str(wmem_packet_scope(), &ip_addr));
174   proto_tree_add_ipv4(igrp_vektor_tree, hf_igrp_network, tvb, 0, 3, addr.addr_word);
175   proto_tree_add_item(igrp_vektor_tree, hf_igrp_delay, tvb, 3, 3, ENC_BIG_ENDIAN);
176   proto_tree_add_item(igrp_vektor_tree, hf_igrp_bandwidth, tvb, 6, 3, ENC_BIG_ENDIAN);
177   proto_tree_add_item(igrp_vektor_tree, hf_igrp_mtu, tvb, 9, 2, ENC_BIG_ENDIAN);
178   proto_tree_add_item(igrp_vektor_tree, hf_igrp_reliability, tvb, 11, 1, ENC_BIG_ENDIAN);
179   proto_tree_add_item(igrp_vektor_tree, hf_igrp_load, tvb, 12, 1, ENC_BIG_ENDIAN);
180   proto_tree_add_item(igrp_vektor_tree, hf_igrp_hop_count, tvb, 13, 1, ENC_BIG_ENDIAN);
181 }
182
183
184 /* Register the protocol with Wireshark */
185 void proto_register_igrp(void)
186 {
187
188   /* Setup list of header fields */
189   static hf_register_info hf[] = {
190
191     { &hf_igrp_update,
192       { "Update Release",           "igrp.update",
193       FT_UINT8, BASE_DEC, NULL, 0x0 ,
194       "Update Release number", HFILL }
195     },
196     { &hf_igrp_as,
197       { "Autonomous System",           "igrp.as",
198       FT_UINT16, BASE_DEC, NULL, 0x0 ,
199       "Autonomous System number", HFILL }
200     },
201
202     /* Generated from convert_proto_tree_add_text.pl */
203     { &hf_igrp_version, { "IGRP Version", "igrp.version", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL }},
204     { &hf_igrp_command, { "Command", "igrp.command", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }},
205     { &hf_igrp_interior_routes, { "Interior routes", "igrp.interior_routes", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
206     { &hf_igrp_system_routes, { "System routes", "igrp.system_routes", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
207     { &hf_igrp_exterior_routes, { "Exterior routes", "igrp.exterior_routes", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
208     { &hf_igrp_checksum, { "Checksum", "igrp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
209     { &hf_igrp_network, { "Network", "igrp.network", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
210     { &hf_igrp_delay, { "Delay", "igrp.delay", FT_UINT24, BASE_DEC, NULL, 0x0, NULL, HFILL }},
211     { &hf_igrp_bandwidth, { "Bandwidth", "igrp.bandwidth", FT_UINT24, BASE_DEC, NULL, 0x0, NULL, HFILL }},
212     { &hf_igrp_mtu, { "MTU", "igrp.mtu", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_byte_bytes, 0x0, NULL, HFILL }},
213     { &hf_igrp_reliability, { "Reliability", "igrp.reliability", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
214     { &hf_igrp_load, { "Load", "igrp.load", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
215     { &hf_igrp_hop_count, { "Hop count", "igrp.hop_count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
216   };
217
218   /* Setup protocol subtree array */
219   static gint *ett[] = {
220     &ett_igrp,
221     &ett_igrp_vektor,
222     &ett_igrp_net
223   };
224
225   static ei_register_info ei[] = {
226     { &ei_igrp_version, { "igrp.version.invalid", PI_PROTOCOL, PI_WARN, "Unknown Version, The dissection may be inaccurate", EXPFILL }},
227   };
228
229   expert_module_t* expert_igrp;
230
231   /* Register the protocol name and description */
232   proto_igrp = proto_register_protocol("Cisco Interior Gateway Routing Protocol",
233                                        "IGRP", "igrp");
234
235   /* Required function calls to register the header fields and subtrees used */
236   proto_register_field_array(proto_igrp, hf, array_length(hf));
237   proto_register_subtree_array(ett, array_length(ett));
238   expert_igrp = expert_register_protocol(proto_igrp);
239   expert_register_field_array(expert_igrp, ei, array_length(ei));
240 }
241
242 void
243 proto_reg_handoff_igrp(void)
244 {
245   dissector_handle_t igrp_handle;
246
247   igrp_handle = create_dissector_handle(dissect_igrp, proto_igrp);
248   dissector_add_uint("ip.proto", IP_PROTO_IGRP, igrp_handle);
249 }
250
251 /*    IGRP Packet structure:
252
253 HEADER structure + k * VECTOR structure
254 where: k = (Number of Interior routes) + (Number of System routes) + (Number of Exterior routes)
255
256 HEADER structure is 12 bytes as follows :
257
258 4  bits         Version (only version 1 is defined)
259 4  bits         Opcode (1=Replay, 2=Request)
260 8  bits         Update Release
261 16 bits         Autonomous system number
262 16 bits         Number of Interior routes
263 16 bits         Number of System routes
264 16 bits         Number of Exterior routes
265 16 bits         Checksum
266 -------
267 12 bytes in header
268
269 VECTOR structure is 14 bytes as follows :
270 24 bits         Network
271 24 bits         Delay
272 24 bits         Bandwidth
273 16 bits         MTU
274 8  bits         Reliability
275 8  bits         Load
276 8  bits         Hop count
277 -------
278 14 bytes in 1 vector
279
280 It is interesting how is coded an ip network address in 3 bytes because IGRP is a classful routing protocol:
281 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
282 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
283
284 If the Delay is 0xFFFFFF then the network is unreachable
285
286 */
287
288 /*
289  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
290  *
291  * Local Variables:
292  * c-basic-offset: 2
293  * tab-width: 8
294  * indent-tabs-mode: nil
295  * End:
296  *
297  * ex: set shiftwidth=2 tabstop=8 expandtab:
298  * :indentSize=2:tabSize=8:noTabs=true:
299  */