A new type of DCERPC over SMB transport.
[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.30 2002/01/24 09:20:49 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, -1, fmat, ap);
99         va_end(ap);
100 }
101
102 /*
103  * Name: dissect_isis()
104  * 
105  * Description:
106  *      Main entry area for isis de-mangling.  This will build the
107  *      main isis tree data and call the sub-protocols as needed.
108  *
109  * Input:
110  *      tvbuff_t * : tvbuffer for packet data
111  *      packet_info * : info for current packet
112  *      proto_tree * : tree of display data.  May be NULL.
113  *
114  * Output:
115  *      void, but we will add to the proto_tree if it is not NULL.
116  */
117 static void
118 dissect_isis(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
119 {
120         proto_item *ti;
121         proto_tree *isis_tree = NULL;
122         int offset = 0;
123         guint8 isis_version;
124         guint8 isis_header_length;
125         guint8 isis_type_reserved;
126         guint8 isis_type;
127         guint8 isis_system_id_len;
128
129         if (check_col(pinfo->cinfo, COL_PROTOCOL))
130                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ISIS");
131         if (check_col(pinfo->cinfo, COL_INFO))
132                 col_clear(pinfo->cinfo, COL_INFO);
133
134         isis_version = tvb_get_guint8(tvb, 2);
135         if (isis_version != ISIS_REQUIRED_VERSION){
136                 if (check_col(pinfo->cinfo, COL_INFO)) {
137                         col_add_fstr(pinfo->cinfo, COL_INFO,
138                                 "Unknown ISIS version (%u vs %u)",
139                                 isis_version, ISIS_REQUIRED_VERSION );
140                 }
141                 isis_dissect_unknown(tvb, pinfo, tree, 0,
142                         "Unknown ISIS version (%d vs %d)",
143                         isis_version, ISIS_REQUIRED_VERSION);
144                 return;
145         }
146         
147         isis_header_length = tvb_get_guint8(tvb, 1);
148         if (tree) {
149                 ti = proto_tree_add_item(tree, proto_isis, tvb, 0, -1, FALSE);
150                 isis_tree = proto_item_add_subtree(ti, ett_isis);
151         }
152
153         if (tree) {
154                 proto_tree_add_item(isis_tree, hf_isis_irpd, tvb, offset, 1,
155                         FALSE );
156         }
157         offset += 1;
158
159         if (tree) {
160                 proto_tree_add_uint(isis_tree, hf_isis_header_length, tvb,
161                         offset, 1, isis_header_length );
162         }
163         offset += 1;
164
165         if (tree) {
166                 proto_tree_add_uint(isis_tree, hf_isis_version, tvb,
167                         offset, 1, isis_version );
168         }
169         offset += 1;
170
171         isis_system_id_len = tvb_get_guint8(tvb, 3);
172         if (tree) {
173                 proto_tree_add_uint(isis_tree, hf_isis_system_id_length, tvb,
174                         offset, 1, isis_system_id_len );
175         }
176         offset += 1;
177
178         isis_type_reserved = tvb_get_guint8(tvb, 4);
179         isis_type = isis_type_reserved & ISIS_TYPE_MASK;
180         if (check_col(pinfo->cinfo, COL_INFO)) {
181                 col_add_str(pinfo->cinfo, COL_INFO,
182                         val_to_str ( isis_type, isis_vals, "Unknown (0x%x)" ) );
183         }
184         if (tree) {
185                 proto_tree_add_uint_format(isis_tree, hf_isis_type, tvb,
186                         offset, 1, isis_type,
187                         "PDU Type           : %s (R:%s%s%s)",
188                         val_to_str(isis_type, isis_vals, "Unknown (0x%x)"),
189                         (isis_type_reserved & ISIS_R8_MASK) ? "1" : "0",
190                         (isis_type_reserved & ISIS_R7_MASK) ? "1" : "0",
191                         (isis_type_reserved & ISIS_R6_MASK) ? "1" : "0");
192         }
193         offset += 1;
194
195         if (tree) {
196                 proto_tree_add_item(isis_tree, hf_isis_version2, tvb, 5, 1,
197                         FALSE );
198         }
199         offset += 1;
200
201         if (tree) {
202                 proto_tree_add_item(isis_tree, hf_isis_reserved, tvb, 6, 1,
203                         FALSE );
204         }
205         offset += 1;
206
207         if (tree) {
208                 proto_tree_add_item(isis_tree, hf_isis_max_area_adr, tvb, 7, 1,
209                         FALSE );
210         }
211         offset += 1;
212
213         /*
214          * Interpret the system ID length.
215          */
216         if (isis_system_id_len == 0)
217                 isis_system_id_len = 6; /* zero means 6-octet ID field length */
218         else if (isis_system_id_len == 255) {
219                 isis_system_id_len = 0; /* 255 means null ID field */
220                 /* XXX - what about the LAN ID? */
221         }
222         /* XXX - otherwise, must be in the range 1 through 8 */
223
224         switch (isis_type) {
225         case ISIS_TYPE_L1_HELLO:
226         case ISIS_TYPE_L2_HELLO:
227         case ISIS_TYPE_PTP_HELLO:
228                 isis_dissect_isis_hello(tvb, pinfo, isis_tree, offset,
229                         isis_type, isis_header_length, isis_system_id_len);
230                 break;
231         case ISIS_TYPE_L1_LSP:
232         case ISIS_TYPE_L2_LSP:
233                 isis_dissect_isis_lsp(tvb, pinfo, isis_tree, offset,
234                         isis_type, isis_header_length, isis_system_id_len);
235                 break;
236         case ISIS_TYPE_L1_CSNP:
237         case ISIS_TYPE_L2_CSNP:
238                 isis_dissect_isis_csnp(tvb, pinfo, isis_tree, offset,
239                         isis_type, isis_header_length, isis_system_id_len);
240                 break;
241         case ISIS_TYPE_L1_PSNP:
242         case ISIS_TYPE_L2_PSNP:
243                 isis_dissect_isis_psnp(tvb, pinfo, isis_tree, offset,
244                         isis_type, isis_header_length, isis_system_id_len);
245                 break;
246         default:
247                 isis_dissect_unknown(tvb, pinfo, tree, offset,
248                         "Unknown ISIS packet type");
249         }
250 } /* dissect_isis */
251
252
253 /*
254  * Name: proto_register_isis()
255  *
256  * Description:
257  *      main register for isis protocol set.  We register some display
258  *      formats and the protocol module variables.
259  *
260  *      NOTE: this procedure to autolinked by the makefile process that
261  *      builds register.c
262  *
263  * Input: 
264  *      void
265  *
266  * Output:
267  *      void
268  */
269 void 
270 proto_register_isis(void) {
271   static hf_register_info hf[] = {
272     { &hf_isis_irpd,
273       { "Intra Domain Routing Protocol Discriminator",  "isis.irpd",    
274         FT_UINT8, BASE_HEX, VALS(nlpid_vals), 0x0, "", HFILL }},
275
276     { &hf_isis_header_length,
277       { "PDU Header Length  ", "isis.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
278
279     { &hf_isis_version,
280       { "Version (==1)      ", "isis.version", FT_UINT8, 
281          BASE_DEC, NULL, 0x0, "", HFILL }},
282
283     { &hf_isis_system_id_length,
284       { "System ID Length   ", "isis.sysid_len",        
285         FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
286
287     { &hf_isis_type, 
288       { "PDU Type           ", "isis.type", FT_UINT8, BASE_DEC, 
289         VALS(isis_vals), 0xff, "", HFILL }},
290
291     { &hf_isis_version2, 
292       { "Version2 (==1)     ", "isis.version2", FT_UINT8, BASE_DEC, NULL, 
293         0x0, "", HFILL }},
294
295     { &hf_isis_reserved,
296       { "Reserved (==0)     ", "isis.reserved", FT_UINT8, BASE_DEC, NULL, 
297         0x0, "", HFILL }},
298
299     { &hf_isis_max_area_adr,
300       { "Max.AREAs: (0==3)  ", "isis.max_area_adr", FT_UINT8, BASE_DEC, NULL, 
301       0x0, "", HFILL }},
302
303     };
304     /*
305      * Note, we pull in the unknown CLV handler here, since it
306      * is used by all ISIS packet types.
307      */
308     static gint *ett[] = {
309       &ett_isis,
310     };
311
312     proto_isis = proto_register_protocol(PROTO_STRING_ISIS, "ISIS", "isis");
313     proto_register_field_array(proto_isis, hf, array_length(hf));
314     proto_register_subtree_array(ett, array_length(ett));
315
316     /*
317      * Call registration routines for other source files in the ISIS
318      * dissector.
319      */
320     isis_register_hello(proto_isis);
321     isis_register_lsp(proto_isis);
322     isis_register_csnp(proto_isis);
323     isis_register_psnp(proto_isis);
324 }
325
326 void
327 proto_reg_handoff_isis(void)
328 {
329     dissector_handle_t isis_handle;
330
331     isis_handle = create_dissector_handle(dissect_isis, proto_isis);
332     dissector_add("osinl", NLPID_ISO10589_ISIS, isis_handle);
333 }