Fetch fields from the ISIS header one at a time, rather than snarfing
[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.24 2001/07/02 01:46:22 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  */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
35 #endif
36
37 #include <stdio.h>
38 #include <string.h>
39 #include <glib.h>
40 #include "packet.h"
41 #include "nlpid.h"
42 #include "packet-osi.h"
43 #include "packet-isis.h"
44 #include "packet-isis-lsp.h"
45 #include "packet-isis-hello.h"
46 #include "packet-isis-snp.h"
47
48
49 /* isis base header */
50 static int proto_isis               = -1;
51
52 static int hf_isis_irpd             = -1;
53 static int hf_isis_header_length    = -1;
54 static int hf_isis_version          = -1;
55 static int hf_isis_system_id_length = -1;
56 static int hf_isis_type             = -1;
57 static int hf_isis_version2         = -1;
58 static int hf_isis_reserved         = -1;
59 static int hf_isis_max_area_adr     = -1;
60
61 static gint ett_isis                = -1;
62
63 static const value_string isis_vals[] = {
64   { ISIS_TYPE_L1_HELLO,  "L1 HELLO"},
65   { ISIS_TYPE_L2_HELLO,  "L2 HELLO"},
66   { ISIS_TYPE_PTP_HELLO, "P2P HELLO"},
67   { ISIS_TYPE_L1_LSP,    "L1 LSP"},
68   { ISIS_TYPE_L2_LSP,    "L2 LSP"},
69   { ISIS_TYPE_L1_CSNP,   "L1 CSNP"},
70   { ISIS_TYPE_L2_CSNP,   "L2 CSNP"},
71   { ISIS_TYPE_L1_PSNP,   "L1 PSNP"},
72   { ISIS_TYPE_L2_PSNP,   "L2 PSNP"},
73   { 0,                   NULL}      };
74
75 /*
76  * Name: dissect_isis_unknown()
77  *
78  * Description:
79  *      There was some error in the protocol and we are in unknown space
80  *      here.  Add a tree item to cover the error and go on.  Note
81  *      that we make sure we don't go off the end of the bleedin packet here!
82  *
83  * Input
84  *      tvbuff_t * : tvbuffer for packet data
85  *      packet_info * : info for current packet
86  *      proto_tree * : tree of display data.  May be NULL.
87  *      int : current offset into packet data
88  *      char * : format text
89  *
90  * Output:
91  *      void (may modify proto tree)
92  */
93 void
94 isis_dissect_unknown(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, 
95         int offset, char *fmat, ...)
96 {
97         va_list ap;
98
99         va_start(ap, fmat);
100         proto_tree_add_text_valist(tree, tvb, offset, 
101                 tvb_length_remaining(tvb, offset), fmat, ap);
102         va_end(ap);
103 }
104
105 /*
106  * Name: dissect_isis()
107  * 
108  * Description:
109  *      Main entry area for isis de-mangling.  This will build the
110  *      main isis tree data and call the sub-protocols as needed.
111  *
112  * Input:
113  *      tvbuff_t * : tvbuffer for packet data
114  *      packet_info * : info for current packet
115  *      proto_tree * : tree of display data.  May be NULL.
116  *
117  * Output:
118  *      void, but we will add to the proto_tree if it is not NULL.
119  */
120 static void
121 dissect_isis(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
122 {
123         isis_hdr_t ihdr;
124         proto_item *ti;
125         proto_tree *isis_tree = NULL;
126         int offset = 0;
127         guint8 isis_version;
128         guint8 isis_header_length;
129         guint8 isis_type_reserved;
130         guint8 isis_type;
131         guint8 isis_system_id_len;
132
133         if (check_col(pinfo->fd, COL_PROTOCOL))
134                 col_set_str(pinfo->fd, COL_PROTOCOL, "ISIS");
135         if (check_col(pinfo->fd, COL_INFO))
136                 col_clear(pinfo->fd, COL_INFO);
137
138         isis_version = tvb_get_guint8(tvb, 2);
139         if (isis_version != ISIS_REQUIRED_VERSION){
140                 if (check_col(pinfo->fd, COL_INFO)) {
141                         col_add_fstr(pinfo->fd, COL_INFO,
142                                 "Unknown ISIS version (%u vs %u)",
143                                 isis_version, ISIS_REQUIRED_VERSION );
144                 }
145                 isis_dissect_unknown(tvb, pinfo, tree, 0,
146                         "Unknown ISIS version (%d vs %d)",
147                         isis_version, ISIS_REQUIRED_VERSION);
148                 return;
149         }
150         
151         isis_header_length = tvb_get_guint8(tvb, 1);
152         if (tree) {
153                 ti = proto_tree_add_item(tree, proto_isis, tvb, 0, 
154                         tvb_length(tvb), FALSE );
155                 isis_tree = proto_item_add_subtree(ti, ett_isis);
156         }
157
158         if (tree) {
159                 proto_tree_add_item(isis_tree, hf_isis_irpd, tvb, offset, 1,
160                         FALSE );
161         }
162         offset += 1;
163
164         if (tree) {
165                 proto_tree_add_uint(isis_tree, hf_isis_header_length, tvb,
166                         offset, 1, isis_header_length );
167         }
168         offset += 1;
169
170         if (tree) {
171                 proto_tree_add_uint(isis_tree, hf_isis_version, tvb,
172                         offset, 1, isis_version );
173         }
174         offset += 1;
175
176         isis_system_id_len = tvb_get_guint8(tvb, 3);
177         if (tree) {
178                 proto_tree_add_uint(isis_tree, hf_isis_system_id_length, tvb,
179                         offset, 1, isis_system_id_len );
180         }
181         offset += 1;
182
183         isis_type_reserved = tvb_get_guint8(tvb, 4);
184         isis_type = isis_type_reserved & ISIS_TYPE_MASK;
185         if (check_col(pinfo->fd, COL_INFO)) {
186                 col_add_str(pinfo->fd, COL_INFO,
187                         val_to_str ( isis_type, isis_vals, "Unknown (0x%x)" ) );
188         }
189         if (tree) {
190                 proto_tree_add_uint_format(isis_tree, hf_isis_type, tvb,
191                         offset, 1, isis_type,
192                         "PDU Type           : %s (R:%s%s%s)",
193                         val_to_str(isis_type, isis_vals, "Unknown (0x%x)"),
194                         (isis_type_reserved & ISIS_R8_MASK) ? "1" : "0",
195                         (isis_type_reserved & ISIS_R7_MASK) ? "1" : "0",
196                         (isis_type_reserved & ISIS_R6_MASK) ? "1" : "0");
197         }
198         offset += 1;
199
200         if (tree) {
201                 proto_tree_add_item(isis_tree, hf_isis_version2, tvb, 5, 1,
202                         FALSE );
203         }
204         offset += 1;
205
206         if (tree) {
207                 proto_tree_add_item(isis_tree, hf_isis_reserved, tvb, 6, 1,
208                         FALSE );
209         }
210         offset += 1;
211
212         if (tree) {
213                 proto_tree_add_item(isis_tree, hf_isis_max_area_adr, tvb, 7, 1,
214                         FALSE );
215         }
216         offset += 1;
217
218         /*
219          * Interpret the system ID length.
220          */
221         if (isis_system_id_len == 0)
222                 isis_system_id_len = 6; /* zero means 6-octet ID field length */
223         else if (isis_system_id_len == 255) {
224                 isis_system_id_len = 0; /* 255 means null ID field */
225                 /* XXX - what about the LAN ID? */
226         }
227         /* XXX - otherwise, must be in the range 1 through 8 */
228
229         switch (isis_type) {
230         case ISIS_TYPE_L1_HELLO:
231         case ISIS_TYPE_L2_HELLO:
232         case ISIS_TYPE_PTP_HELLO:
233                 isis_dissect_isis_hello(tvb, pinfo, isis_tree, offset,
234                         isis_type, isis_header_length, isis_system_id_len);
235                 break;
236         case ISIS_TYPE_L1_LSP:
237         case ISIS_TYPE_L2_LSP:
238                 isis_dissect_isis_lsp(tvb, pinfo, isis_tree, offset,
239                         isis_type, isis_header_length, isis_system_id_len);
240                 break;
241         case ISIS_TYPE_L1_CSNP:
242         case ISIS_TYPE_L2_CSNP:
243                 isis_dissect_isis_csnp(tvb, pinfo, isis_tree, offset,
244                         isis_type, isis_header_length, isis_system_id_len);
245                 break;
246         case ISIS_TYPE_L1_PSNP:
247         case ISIS_TYPE_L2_PSNP:
248                 isis_dissect_isis_psnp(tvb, pinfo, isis_tree, offset,
249                         isis_type, isis_header_length, isis_system_id_len);
250                 break;
251         default:
252                 isis_dissect_unknown(tvb, pinfo, tree, offset,
253                         "Unknown ISIS packet type");
254         }
255 } /* dissect_isis */
256
257
258 /*
259  * Name: proto_register_isis()
260  *
261  * Description:
262  *      main register for isis protocol set.  We register some display
263  *      formats and the protocol module variables.
264  *
265  *      NOTE: this procedure to autolinked by the makefile process that
266  *      builds register.c
267  *
268  * Input: 
269  *      void
270  *
271  * Output:
272  *      void
273  */
274 void 
275 proto_register_isis(void) {
276   static hf_register_info hf[] = {
277     { &hf_isis_irpd,
278       { "Intra Domain Routing Protocol Discriminator",  "isis.irpd",    
279         FT_UINT8, BASE_HEX, VALS(nlpid_vals), 0x0, "", HFILL }},
280
281     { &hf_isis_header_length,
282       { "PDU Header Length  ", "isis.len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
283
284     { &hf_isis_version,
285       { "Version (==1)      ", "isis.version", FT_UINT8, 
286          BASE_DEC, NULL, 0x0, "", HFILL }},
287
288     { &hf_isis_system_id_length,
289       { "System ID Length   ", "isis.sysid_len",        
290         FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
291
292     { &hf_isis_type, 
293       { "PDU Type           ", "isis.type", FT_UINT8, BASE_DEC, 
294         VALS(isis_vals), 0xff, "", HFILL }},
295
296     { &hf_isis_version2, 
297       { "Version2 (==1)     ", "isis.version2", FT_UINT8, BASE_DEC, NULL, 
298         0x0, "", HFILL }},
299
300     { &hf_isis_reserved,
301       { "Reserved (==0)     ", "isis.reserved", FT_UINT8, BASE_DEC, NULL, 
302         0x0, "", HFILL }},
303
304     { &hf_isis_max_area_adr,
305       { "Max.AREAs: (0==3)  ", "isis.max_area_adr", FT_UINT8, BASE_DEC, NULL, 
306       0x0, "", HFILL }},
307
308     };
309     /*
310      * Note, we pull in the unknown CLV handler here, since it
311      * is used by all ISIS packet types.
312      */
313     static gint *ett[] = {
314       &ett_isis,
315     };
316
317     proto_isis = proto_register_protocol(PROTO_STRING_ISIS, "ISIS", "isis");
318     proto_register_field_array(proto_isis, hf, array_length(hf));
319     proto_register_subtree_array(ett, array_length(ett));
320 }
321
322 void
323 proto_reg_handoff_isis(void)
324 {
325     dissector_add("osinl", NLPID_ISO10589_ISIS, dissect_isis, proto_isis);
326 }