Break proto_tree_add_item_format() into multiple functions:
[obnox/wireshark/wip.git] / packet-isis.c
1 /* packet-isis-core.c
2  * Routines for ISO/OSI network and transport protocol packet disassembly, core
3  * bits.
4  *
5  * $Id: packet-isis.c,v 1.4 2000/03/12 04:47:41 gram Exp $
6  * Stuart Stanley <stuarts@mxmail.net>
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@zing.org>
10  * Copyright 1998 Gerald Combs
11  *
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  */
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
36 #endif
37
38 #include <stdio.h>
39 #include <string.h>
40 #include <glib.h>
41 #include "packet.h"
42 #include "nlpid.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 /* isis base header */
49 static int proto_isis = -1;
50
51 static int hf_isis_irpd = -1;
52 static int hf_isis_header_length = -1;
53 static int hf_isis_version = -1;
54 static int hf_isis_reserved = -1;
55 static int hf_isis_type = -1;
56 static int hf_isis_version2 = -1;
57 static int hf_isis_eco = -1;
58 static int hf_isis_user_eco = -1;
59
60 static gint ett_isis = -1;
61
62 static const value_string isis_vals[] = {
63         { ISIS_TYPE_L1_HELLO,   "L1 HELLO"},
64         { ISIS_TYPE_L2_HELLO,   "L2 HELLO"},
65         { ISIS_TYPE_PTP_HELLO,  "P2P HELLO"},
66         { ISIS_TYPE_L1_LSP,     "L1 LSP"},
67         { ISIS_TYPE_L2_LSP,     "L2 LSP"},
68         { ISIS_TYPE_L1_CSNP,    "L1 CSNP"},
69         { ISIS_TYPE_L2_CSNP,    "L2 CSNP"},
70         { ISIS_TYPE_L1_PSNP,    "L1 PSNP"},
71         { ISIS_TYPE_L2_PSNP,    "L2 PSNP"},
72         { 0,            NULL} };
73
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  *      unt offset : Current offset into packet data.
85  *      int len : length of to dump.
86  *      proto_tree * : tree of display data.  May be NULL.
87  *      frame_data * fd : frame data
88  *      char * : format text
89  *
90  * Output:
91  *      void (may modify proto tree)
92  */
93 void
94 isis_dissect_unknown(int offset,guint length,proto_tree *tree,frame_data *fd,
95                 char *fmat, ...){
96         va_list ap;
97
98         if ( !IS_DATA_IN_FRAME(offset) ) {
99                 /* 
100                  * big oops   They were off the end of the packet already.
101                  * Just ignore this one.
102                  */
103                 return;
104         }
105         if ( !BYTES_ARE_IN_FRAME(offset, length) ) {
106                 /* 
107                  * length will take us past eop.  Truncate length.
108                  */
109                 length = END_OF_FRAME;
110         }
111
112         va_start(ap, fmat);
113         proto_tree_add_text(tree, offset, length, fmat, ap);
114         va_end(ap);
115 }
116
117 /*
118  * Name: isis_address_to_string()
119  *
120  * Description:
121  *      Function for taking a byte string and turn it into a "0000.0000...."
122  *      format ISIS address.
123  *
124  * Input:
125  *      u_char * : Packet data
126  *      unt offset : Current offset into packet data.
127  *      int len : length of to dump.
128  *
129  * Output:
130  *      static char * : print string
131  */
132 char 
133 *isis_address_to_string ( const u_char *pd, int offset, int len ) {
134         static char sbuf[768];
135         char *s;
136
137         sbuf[0] = 0;
138         s = sbuf;
139         while ( len > 0 ) {
140                 /* special case: len is 1, put ending on it */
141                 if ( len == 1 ) {
142                         s += sprintf ( s, "%02x", pd[offset++] );
143                         len--;
144                 } else {
145                         /* general case, just add 2 bytes */
146                         s+= sprintf ( s, "%02x%02x", pd[offset++],
147                                 pd[offset++] );
148                         len -= 2;
149                 }
150                 if ( len > 0 ) {
151                         s += sprintf ( s, "." );
152                 }
153         }
154         return sbuf;
155 }
156
157 /*
158  * Name: dissect_isis()
159  * 
160  * Description:
161  *      Main entry area for isis de-mangling.  This will build the
162  *      main isis tree data and call the sub-protocols as needed.
163  *
164  * Input:
165  *      u_char * : packet data
166  *      int : offset into packet where we are (packet_data[offset]== start
167  *              of what we care about)
168  *      frame_data * : frame data (whole packet with extra info)
169  *      proto_tree * : tree of display data.  May be NULL.
170  *
171  * Output:
172  *      void, but we will add to the proto_tree if it is not NULL.
173  */
174 void
175 dissect_isis(const u_char *pd, int offset, frame_data *fd, 
176                 proto_tree *tree) {
177         isis_hdr_t *ihdr;
178         proto_item *ti;
179         proto_tree *isis_tree = NULL;
180
181         if (!BYTES_ARE_IN_FRAME(offset, sizeof(*ihdr))) {
182                 isis_dissect_unknown(offset, sizeof(*ihdr), tree, fd,
183                         "not enough capture data for header (%d vs %d)",
184                         sizeof(*ihdr), END_OF_FRAME);
185                 return;
186         }
187
188         ihdr = (isis_hdr_t *) &pd[offset];
189
190         if (ihdr->isis_version != ISIS_REQUIRED_VERSION){
191                 isis_dissect_unknown(offset, END_OF_FRAME, tree, fd,
192                         "Unknown ISIS version (%d vs %d)",
193                         ihdr->isis_version, ISIS_REQUIRED_VERSION );
194                 return;
195         }
196         
197         
198         if (tree) {
199                 ti = proto_tree_add_item(tree, proto_isis, offset, 
200                         END_OF_FRAME, NULL );
201                 isis_tree = proto_item_add_subtree(ti, ett_isis);
202                 proto_tree_add_item(isis_tree, hf_isis_irpd, offset, 1,
203                         ihdr->isis_irpd );
204                 proto_tree_add_item(isis_tree, hf_isis_header_length,
205                         offset + 1, 1, ihdr->isis_header_length );
206                 proto_tree_add_item(isis_tree, hf_isis_version,
207                         offset + 2, 1, ihdr->isis_version );
208                 proto_tree_add_item(isis_tree, hf_isis_reserved,
209                         offset + 3, 1, ihdr->isis_reserved );
210                 proto_tree_add_uint_format(isis_tree, hf_isis_type,
211                         offset + 4, 1, ihdr->isis_type,
212                         "Type: %s (R:%s%s%s)",
213                         val_to_str(ihdr->isis_type & ISIS_TYPE_MASK, isis_vals,
214                                 "Unknown (0x%x)"),
215                         (ihdr->isis_type & ISIS_R8_MASK) ? "1" : "0",
216                         (ihdr->isis_type & ISIS_R7_MASK) ? "1" : "0",
217                         (ihdr->isis_type & ISIS_R6_MASK) ? "1" : "0");
218                 proto_tree_add_item(isis_tree, hf_isis_version2,
219                         offset + 5, 1, ihdr->isis_version2 );
220                 proto_tree_add_item(isis_tree, hf_isis_eco,
221                         offset + 6, 1, ihdr->isis_eco );
222                 proto_tree_add_item(isis_tree, hf_isis_user_eco,
223                         offset + 7, 1, ihdr->isis_user_eco );
224         }
225
226
227         /*
228          * Let us make sure we use the same names for all our decodes
229          * here.  First, dump the name into info column, and THEN
230          * dispatch the sub-type.
231          */
232         if (check_col(fd, COL_INFO)) {
233                 col_add_str(fd, COL_INFO, val_to_str ( 
234                         ihdr->isis_type&ISIS_TYPE_MASK, isis_vals,
235                         "Unknown (0x%x)" ) );
236         }
237
238         /*
239          * Advance offset (we are past the header).
240          */
241         offset += sizeof(*ihdr);
242         switch (ihdr->isis_type) {
243         case ISIS_TYPE_L1_HELLO:
244                 isis_dissect_isis_hello(ISIS_TYPE_L1_HELLO, 
245                         ihdr->isis_header_length, pd, offset, fd, isis_tree);
246                 break;
247         case ISIS_TYPE_L2_HELLO:
248                 isis_dissect_isis_hello(ISIS_TYPE_L2_HELLO, 
249                         ihdr->isis_header_length, pd, offset, fd, isis_tree);
250                 break;
251         case ISIS_TYPE_PTP_HELLO:
252                 isis_dissect_isis_hello(ISIS_TYPE_PTP_HELLO, 
253                         ihdr->isis_header_length, pd, offset, fd, isis_tree);
254                 break;
255         case ISIS_TYPE_L1_LSP:
256                 isis_dissect_isis_lsp(ISIS_TYPE_L1_LSP, ihdr->isis_header_length,
257                         pd, offset, fd, isis_tree);
258                 break;
259         case ISIS_TYPE_L2_LSP:
260                 isis_dissect_isis_lsp(ISIS_TYPE_L2_LSP, ihdr->isis_header_length,
261                         pd, offset, fd, isis_tree);
262                 break;
263         case ISIS_TYPE_L1_CSNP:
264                 isis_dissect_isis_csnp(ISIS_TYPE_L1_CSNP, 
265                         ihdr->isis_header_length, pd, offset, fd, isis_tree);
266                 break;
267         case ISIS_TYPE_L2_CSNP:
268                 isis_dissect_isis_csnp(ISIS_TYPE_L2_CSNP,
269                         ihdr->isis_header_length, pd, offset, fd, isis_tree);
270                 break;
271         case ISIS_TYPE_L1_PSNP:
272                 isis_dissect_isis_psnp(ISIS_TYPE_L1_PSNP, 
273                         ihdr->isis_header_length, pd, offset, fd, isis_tree);
274                 break;
275         case ISIS_TYPE_L2_PSNP:
276                 isis_dissect_isis_psnp(ISIS_TYPE_L2_PSNP,
277                         ihdr->isis_header_length, pd, offset, fd, isis_tree);
278                 break;
279         default:
280                 isis_dissect_unknown(offset, END_OF_FRAME, tree, fd,
281                         "unknown ISIS packet type" );
282         }
283 } /* dissect_isis */
284
285
286 /*
287  * Name: proto_register_isis()
288  *
289  * Description:
290  *      main register for isis protocol set.  We register some display
291  *      formats and the protocol module variables.
292  *
293  *      NOTE: this procedure to autolinked by the makefile process that
294  *      builds register.c
295  *
296  * Input: 
297  *      void
298  *
299  * Output:
300  *      void
301  */
302 void 
303 proto_register_isis(void) {
304         static hf_register_info hf[] = {
305                 { &hf_isis_irpd,
306                 { "Intradomain Routing Protocol Discriminator", "isis.irpd",    
307                   FT_UINT8, BASE_HEX, VALS(nlpid_vals), 0x0, "" }},
308
309                 { &hf_isis_header_length,
310                 { "HDR Length",         "isis.hdr_len", FT_UINT8, BASE_DEC, 
311                   NULL, 0x0, "" }},
312
313                 { &hf_isis_version,
314                 { "Version (==1)",              "isis.version", FT_UINT8, 
315                   BASE_DEC, NULL, 0x0, "" }},
316
317                 { &hf_isis_reserved,
318                 { "Reserved(==0)",                      "isis.reserved",        
319                   FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
320
321                 { &hf_isis_type,
322                 { "Type code",            "isis.type",  FT_UINT8, BASE_DEC, 
323                   VALS(isis_vals), 0xff, "" }},
324
325                 { &hf_isis_version2,
326                 { "Version2(==1)",   "isis.version2", FT_UINT8, BASE_DEC, NULL, 
327                    0x0, "" }},
328
329                 { &hf_isis_eco,
330                 { "ECO (==0)",          "isis.eco",FT_UINT8, BASE_DEC, NULL, 
331                   0x0, "" }},
332
333                 { &hf_isis_user_eco,
334                 { "User ECO (==0)", "isis.user_eco", FT_UINT8, BASE_DEC, NULL, 
335                   0x0, "" }},
336
337         };
338         /*
339          * Note, we pull in the unknown CLV handler here, since it
340          * is used by all ISIS packet types.
341          */
342         static gint *ett[] = {
343                 &ett_isis,
344         };
345
346         proto_isis = proto_register_protocol("clnp ISIS", "ISIS");
347         proto_register_field_array(proto_isis, hf, array_length(hf));
348         proto_register_subtree_array(ett, array_length(ett));
349 }