From Ronnie Sahlberg: add support for finding the response that matches
[obnox/wireshark/wip.git] / packet-isis.c
1 /* packet-isis.c
2  * Routines for ISO/OSI network and transport protocol packet disassembly, core
3  * bits.
4  *
5  * $Id: packet-isis.c,v 1.29 2002/01/21 07:36:36 guy Exp $
6  * Stuart Stanley <stuarts@mxmail.net>
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1998 Gerald Combs
11  * 
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34
35 #include <stdio.h>
36 #include <string.h>
37 #include <glib.h>
38 #include <epan/packet.h>
39 #include "nlpid.h"
40 #include "packet-osi.h"
41 #include "packet-isis.h"
42 #include "packet-isis-lsp.h"
43 #include "packet-isis-hello.h"
44 #include "packet-isis-snp.h"
45
46
47 /* isis base header */
48 static int proto_isis               = -1;
49
50 static int hf_isis_irpd             = -1;
51 static int hf_isis_header_length    = -1;
52 static int hf_isis_version          = -1;
53 static int hf_isis_system_id_length = -1;
54 static int hf_isis_type             = -1;
55 static int hf_isis_version2         = -1;
56 static int hf_isis_reserved         = -1;
57 static int hf_isis_max_area_adr     = -1;
58
59 static gint ett_isis                = -1;
60
61 static const value_string isis_vals[] = {
62   { ISIS_TYPE_L1_HELLO,  "L1 HELLO"},
63   { ISIS_TYPE_L2_HELLO,  "L2 HELLO"},
64   { ISIS_TYPE_PTP_HELLO, "P2P HELLO"},
65   { ISIS_TYPE_L1_LSP,    "L1 LSP"},
66   { ISIS_TYPE_L2_LSP,    "L2 LSP"},
67   { ISIS_TYPE_L1_CSNP,   "L1 CSNP"},
68   { ISIS_TYPE_L2_CSNP,   "L2 CSNP"},
69   { ISIS_TYPE_L1_PSNP,   "L1 PSNP"},
70   { ISIS_TYPE_L2_PSNP,   "L2 PSNP"},
71   { 0,                   NULL}      };
72
73 /*
74  * Name: dissect_isis_unknown()
75  *
76  * Description:
77  *      There was some error in the protocol and we are in unknown space
78  *      here.  Add a tree item to cover the error and go on.  Note
79  *      that we make sure we don't go off the end of the bleedin packet here!
80  *
81  * Input
82  *      tvbuff_t * : tvbuffer for packet data
83  *      packet_info * : info for current packet
84  *      proto_tree * : tree of display data.  May be NULL.
85  *      int : current offset into packet data
86  *      char * : format text
87  *
88  * Output:
89  *      void (may modify proto tree)
90  */
91 void
92 isis_dissect_unknown(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, 
93         int offset, char *fmat, ...)
94 {
95         va_list ap;
96
97         va_start(ap, fmat);
98         proto_tree_add_text_valist(tree, tvb, offset, 
99                 tvb_length_remaining(tvb, offset), fmat, ap);
100         va_end(ap);
101 }
102
103 /*
104  * Name: dissect_isis()
105  * 
106  * Description:
107  *      Main entry area for isis de-mangling.  This will build the
108  *      main isis tree data and call the sub-protocols as needed.
109  *
110  * Input:
111  *      tvbuff_t * : tvbuffer for packet data
112  *      packet_info * : info for current packet
113  *      proto_tree * : tree of display data.  May be NULL.
114  *
115  * Output:
116  *      void, but we will add to the proto_tree if it is not NULL.
117  */
118 static void
119 dissect_isis(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
120 {
121         proto_item *ti;
122         proto_tree *isis_tree = NULL;
123         int offset = 0;
124         guint8 isis_version;
125         guint8 isis_header_length;
126         guint8 isis_type_reserved;
127         guint8 isis_type;
128         guint8 isis_system_id_len;
129
130         if (check_col(pinfo->cinfo, COL_PROTOCOL))
131                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ISIS");
132         if (check_col(pinfo->cinfo, COL_INFO))
133                 col_clear(pinfo->cinfo, COL_INFO);
134
135         isis_version = tvb_get_guint8(tvb, 2);
136         if (isis_version != ISIS_REQUIRED_VERSION){
137                 if (check_col(pinfo->cinfo, COL_INFO)) {
138                         col_add_fstr(pinfo->cinfo, COL_INFO,
139                                 "Unknown ISIS version (%u vs %u)",
140                                 isis_version, ISIS_REQUIRED_VERSION );
141                 }
142                 isis_dissect_unknown(tvb, pinfo, tree, 0,
143                         "Unknown ISIS version (%d vs %d)",
144                         isis_version, ISIS_REQUIRED_VERSION);
145                 return;
146         }
147         
148         isis_header_length = tvb_get_guint8(tvb, 1);
149         if (tree) {
150                 ti = proto_tree_add_item(tree, proto_isis, tvb, 0, 
151                         tvb_length(tvb), FALSE );
152                 isis_tree = proto_item_add_subtree(ti, ett_isis);
153         }
154
155         if (tree) {
156                 proto_tree_add_item(isis_tree, hf_isis_irpd, tvb, offset, 1,
157                         FALSE );
158         }
159         offset += 1;
160
161         if (tree) {
162                 proto_tree_add_uint(isis_tree, hf_isis_header_length, tvb,
163                         offset, 1, isis_header_length );
164         }
165         offset += 1;
166
167         if (tree) {
168                 proto_tree_add_uint(isis_tree, hf_isis_version, tvb,
169                         offset, 1, isis_version );
170         }
171         offset += 1;
172
173         isis_system_id_len = tvb_get_guint8(tvb, 3);
174         if (tree) {
175                 proto_tree_add_uint(isis_tree, hf_isis_system_id_length, tvb,
176                         offset, 1, isis_system_id_len );
177         }
178         offset += 1;
179
180         isis_type_reserved = tvb_get_guint8(tvb, 4);
181         isis_type = isis_type_reserved & ISIS_TYPE_MASK;
182         if (check_col(pinfo->cinfo, COL_INFO)) {
183                 col_add_str(pinfo->cinfo, COL_INFO,
184                         val_to_str ( isis_type, isis_vals, "Unknown (0x%x)" ) );
185         }
186         if (tree) {
187                 proto_tree_add_uint_format(isis_tree, hf_isis_type, tvb,
188                         offset, 1, isis_type,
189                         "PDU Type           : %s (R:%s%s%s)",
190                         val_to_str(isis_type, isis_vals, "Unknown (0x%x)"),
191                         (isis_type_reserved & ISIS_R8_MASK) ? "1" : "0",
192                         (isis_type_reserved & ISIS_R7_MASK) ? "1" : "0",
193                         (isis_type_reserved & ISIS_R6_MASK) ? "1" : "0");
194         }
195         offset += 1;
196
197         if (tree) {
198                 proto_tree_add_item(isis_tree, hf_isis_version2, tvb, 5, 1,
199                         FALSE );
200         }
201         offset += 1;
202
203         if (tree) {
204                 proto_tree_add_item(isis_tree, hf_isis_reserved, tvb, 6, 1,
205                         FALSE );
206         }
207         offset += 1;
208
209         if (tree) {
210                 proto_tree_add_item(isis_tree, hf_isis_max_area_adr, tvb, 7, 1,
211                         FALSE );
212         }
213         offset += 1;
214
215         /*
216          * Interpret the system ID length.
217          */
218         if (isis_system_id_len == 0)
219                 isis_system_id_len = 6; /* zero means 6-octet ID field length */
220         else if (isis_system_id_len == 255) {
221                 isis_system_id_len = 0; /* 255 means null ID field */
222                 /* XXX - what about the LAN ID? */
223         }
224         /* XXX - otherwise, must be in the range 1 through 8 */
225
226         switch (isis_type) {
227         case ISIS_TYPE_L1_HELLO:
228         case ISIS_TYPE_L2_HELLO:
229         case ISIS_TYPE_PTP_HELLO:
230                 isis_dissect_isis_hello(tvb, pinfo, isis_tree, offset,
231                         isis_type, isis_header_length, isis_system_id_len);
232                 break;
233         case ISIS_TYPE_L1_LSP:
234         case ISIS_TYPE_L2_LSP:
235                 isis_dissect_isis_lsp(tvb, pinfo, isis_tree, offset,
236                         isis_type, isis_header_length, isis_system_id_len);
237                 break;
238         case ISIS_TYPE_L1_CSNP:
239         case ISIS_TYPE_L2_CSNP:
240                 isis_dissect_isis_csnp(tvb, pinfo, isis_tree, offset,
241                         isis_type, isis_header_length, isis_system_id_len);
242                 break;
243         case ISIS_TYPE_L1_PSNP:
244         case ISIS_TYPE_L2_PSNP:
245                 isis_dissect_isis_psnp(tvb, pinfo, isis_tree, offset,
246                         isis_type, isis_header_length, isis_system_id_len);
247                 break;
248         default:
249                 isis_dissect_unknown(tvb, pinfo, tree, offset,
250                         "Unknown ISIS packet type");
251         }
252 } /* dissect_isis */
253
254
255 /*
256  * Name: proto_register_isis()
257  *
258  * Description:
259  *      main register for isis protocol set.  We register some display
260  *      formats and the protocol module variables.
261  *
262  *      NOTE: this procedure to autolinked by the makefile process that
263  *      builds register.c
264  *
265  * Input: 
266  *      void
267  *
268  * Output:
269  *      void
270  */
271 void 
272 proto_register_isis(void) {
273   static hf_register_info hf[] = {
274     { &hf_isis_irpd,
275       { "Intra Domain Routing Protocol Discriminator",  "isis.irpd",    
276         FT_UINT8, BASE_HEX, VALS(nlpid_vals), 0x0, "", HFILL }},
277
278     { &hf_isis_header_length,
279       { "PDU Header Length  ", "isis.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
280
281     { &hf_isis_version,
282       { "Version (==1)      ", "isis.version", FT_UINT8, 
283          BASE_DEC, NULL, 0x0, "", HFILL }},
284
285     { &hf_isis_system_id_length,
286       { "System ID Length   ", "isis.sysid_len",        
287         FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
288
289     { &hf_isis_type, 
290       { "PDU Type           ", "isis.type", FT_UINT8, BASE_DEC, 
291         VALS(isis_vals), 0xff, "", HFILL }},
292
293     { &hf_isis_version2, 
294       { "Version2 (==1)     ", "isis.version2", FT_UINT8, BASE_DEC, NULL, 
295         0x0, "", HFILL }},
296
297     { &hf_isis_reserved,
298       { "Reserved (==0)     ", "isis.reserved", FT_UINT8, BASE_DEC, NULL, 
299         0x0, "", HFILL }},
300
301     { &hf_isis_max_area_adr,
302       { "Max.AREAs: (0==3)  ", "isis.max_area_adr", FT_UINT8, BASE_DEC, NULL, 
303       0x0, "", HFILL }},
304
305     };
306     /*
307      * Note, we pull in the unknown CLV handler here, since it
308      * is used by all ISIS packet types.
309      */
310     static gint *ett[] = {
311       &ett_isis,
312     };
313
314     proto_isis = proto_register_protocol(PROTO_STRING_ISIS, "ISIS", "isis");
315     proto_register_field_array(proto_isis, hf, array_length(hf));
316     proto_register_subtree_array(ett, array_length(ett));
317
318     /*
319      * Call registration routines for other source files in the ISIS
320      * dissector.
321      */
322     isis_register_hello(proto_isis);
323     isis_register_lsp(proto_isis);
324     isis_register_csnp(proto_isis);
325     isis_register_psnp(proto_isis);
326 }
327
328 void
329 proto_reg_handoff_isis(void)
330 {
331     dissector_handle_t isis_handle;
332
333     isis_handle = create_dissector_handle(dissect_isis, proto_isis);
334     dissector_add("osinl", NLPID_ISO10589_ISIS, isis_handle);
335 }