Put the error code into the Info column symbolically, if possible.
[obnox/wireshark/wip.git] / packet-isis-snp.c
1 /* packet-isis-snp.c
2  * Routines for decoding isis complete & partial SNP and their payload
3  *
4  * $Id: packet-isis-snp.c,v 1.10 2001/07/02 00:19:34 guy Exp $
5  * Stuart Stanley <stuarts@mxmail.net>
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@zing.org>
9  * Copyright 1998 Gerald Combs
10  *
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 "packet-osi.h"
42 #include "packet-isis.h"
43 #include "packet-isis-clv.h"
44 #include "packet-isis-lsp.h"
45 #include "packet-isis-snp.h"
46
47 /* csnp packets */
48 static int proto_isis_csnp = -1;
49 static int hf_isis_csnp_pdu_length = -1;
50 static gint ett_isis_csnp = -1;
51 static gint ett_isis_csnp_lsp_entries = -1;
52 static gint ett_isis_csnp_authentication = -1;
53 static gint ett_isis_csnp_clv_unknown = -1;
54
55 /* psnp packets */
56 static int proto_isis_psnp = -1;
57 static int hf_isis_psnp_pdu_length = -1;
58 static gint ett_isis_psnp = -1;
59 static gint ett_isis_psnp_lsp_entries = -1;
60 static gint ett_isis_psnp_authentication = -1;
61 static gint ett_isis_psnp_clv_unknown = -1;
62
63 static void dissect_l1_snp_authentication_clv(tvbuff_t *tvb, packet_info *pinfo,
64         proto_tree *tree, int offset,
65         int id_length, int length);
66 static void dissect_l2_snp_authentication_clv(tvbuff_t *tvb, packet_info *pinfo,
67         proto_tree *tree, int offset,
68         int id_length, int length);
69 static void dissect_snp_lsp_entries(tvbuff_t *tvb, packet_info *pinfo,
70         proto_tree *tree, int offset,
71         int id_length, int length);
72
73 static const isis_clv_handle_t clv_l1_csnp_opts[] = {
74         {
75                 ISIS_CLV_L1_CSNP_LSP_ENTRIES,
76                 "LSP entries",
77                 &ett_isis_csnp_lsp_entries,
78                 dissect_snp_lsp_entries
79         },
80         {
81                 ISIS_CLV_L1_CSNP_AUTHENTICATION_NS,
82                 "Authentication(non spec)",
83                 &ett_isis_csnp_authentication,
84                 dissect_l1_snp_authentication_clv
85         },
86         {
87                 ISIS_CLV_L1_CSNP_AUTHENTICATION,
88                 "Authentication",
89                 &ett_isis_csnp_authentication,
90                 dissect_l1_snp_authentication_clv
91         },
92         {
93                 0, "", NULL, NULL 
94         }
95 };
96
97 static const isis_clv_handle_t clv_l2_csnp_opts[] = {
98         {
99                 ISIS_CLV_L2_CSNP_LSP_ENTRIES,
100                 "LSP entries",
101                 &ett_isis_csnp_lsp_entries,
102                 dissect_snp_lsp_entries
103         },
104         {
105                 ISIS_CLV_L2_CSNP_AUTHENTICATION_NS,
106                 "Authentication(non spec)",
107                 &ett_isis_csnp_authentication,
108                 dissect_l2_snp_authentication_clv
109         },
110         {
111                 ISIS_CLV_L2_CSNP_AUTHENTICATION,
112                 "Authentication",
113                 &ett_isis_csnp_authentication,
114                 dissect_l2_snp_authentication_clv
115         },
116         {
117                 0, "", NULL, NULL 
118         }
119 };
120
121 static const isis_clv_handle_t clv_l1_psnp_opts[] = {
122         {
123                 ISIS_CLV_L1_PSNP_LSP_ENTRIES,
124                 "LSP entries",
125                 &ett_isis_psnp_lsp_entries,
126                 dissect_snp_lsp_entries
127         },
128         {
129                 ISIS_CLV_L1_PSNP_AUTHENTICATION_NS,
130                 "Authentication(non spec)",
131                 &ett_isis_psnp_authentication,
132                 dissect_l1_snp_authentication_clv
133         },
134         {
135                 ISIS_CLV_L1_PSNP_AUTHENTICATION,
136                 "Authentication",
137                 &ett_isis_psnp_authentication,
138                 dissect_l1_snp_authentication_clv
139         },
140         {
141                 0, "", NULL, NULL 
142         }
143 };
144
145 static const isis_clv_handle_t clv_l2_psnp_opts[] = {
146         {
147                 ISIS_CLV_L2_PSNP_LSP_ENTRIES,
148                 "LSP entries",
149                 &ett_isis_psnp_lsp_entries,
150                 dissect_snp_lsp_entries
151         },
152         {
153                 ISIS_CLV_L2_PSNP_AUTHENTICATION,
154                 "Authentication",
155                 &ett_isis_psnp_authentication,
156                 dissect_l2_snp_authentication_clv
157         },
158         {
159                 ISIS_CLV_L2_PSNP_AUTHENTICATION_NS,
160                 "Authentication(non spec)",
161                 &ett_isis_psnp_authentication,
162                 dissect_l2_snp_authentication_clv
163         },
164         {
165                 0, "", NULL, NULL 
166         }
167 };
168 /*
169  * Name: dissect_snp_lsp_entries()
170  *
171  * Description:
172  *      All the snp packets use a common payload format.  We have up
173  *      to n entries (based on length), which are made of:
174  *              2 : remaining life time
175  *              8 : lsp id
176  *              4 : sequence number
177  *              2 : checksum
178  *
179  * Input:
180  *      tvbuff_t * : tvbuffer for packet data
181  *      packet_info * : info for current packet
182  *      proto_tree * : protocol display tree to fill out.  May be NULL
183  *      int : offset into packet data where we are.
184  *      int : length of payload to decode.
185  *      int : length of IDs in packet.
186  *
187  * Output:
188  *      void, but we will add to proto tree if !NULL.
189  */
190 static void 
191 dissect_snp_lsp_entries(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
192         int offset, int id_length, int length)
193 {
194         while ( length > 0 ) {
195                 if ( length < 2+id_length+2+4+2 ) {
196                         isis_dissect_unknown(tvb, pinfo, tree, offset,
197                                 "Short SNP header entry (%d vs %d)", length,
198                                 2+id_length+2+4+2 );
199                         return;
200                 }
201                 
202                 proto_tree_add_text(tree, tvb, offset, 2, "Remaining life      : %d",
203                         tvb_get_ntohs(tvb, offset));
204                 length -= 2;
205                 offset += 2;
206
207                 isis_lsp_decode_lsp_id(tvb, pinfo, tree, offset,
208                          "LSP ID              ", id_length);
209                 length -= id_length + 2;
210                 offset += id_length + 2;
211
212                 proto_tree_add_text(tree, tvb, offset, 4, 
213                         "LSP Sequence Number : 0x%04x",
214                         tvb_get_ntohl(tvb, offset));
215                 length -= 4;
216                 offset += 4;
217
218                 proto_tree_add_text(tree, tvb, offset, 2, 
219                         "LSP checksum        : 0x%02x",
220                         tvb_get_ntohs(tvb, offset));
221                 length -= 2;
222                 offset += 2;
223         }
224
225 }
226
227 /*
228  * Name: isis_dissect_isis_csnp()
229  *
230  * Description:
231  *      Tear apart a L1 or L2 CSNP header and then call into payload dissect
232  *      to pull apart the lsp id payload.
233  *
234  * Input:
235  *      tvbuff_t * : tvbuffer for packet data
236  *      packet_info * : info for current packet
237  *      proto_tree * : protocol display tree to add to.  May be NULL.
238  *      int offset : our offset into packet data.
239  *      int : type (l1 csnp, l2 csnp)
240  *      int : header length of packet.
241  *      int : length of IDs in packet.
242  *
243  * Output:
244  *      void, but we will add to proto tree if !NULL.
245  */
246 void 
247 isis_dissect_isis_csnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
248         int offset, int type, int header_length, int id_length)
249 {
250         proto_item      *ti;
251         proto_tree      *csnp_tree = NULL;
252         guint16         pdu_length;
253         int             len;
254
255         if (!proto_is_protocol_enabled(proto_isis_csnp)) {
256                 dissect_data(tvb, offset, pinfo, tree);
257                 return;
258         }
259
260         if (tree) {
261                 ti = proto_tree_add_item(tree, proto_isis_csnp, tvb,
262                         offset, tvb_length_remaining(tvb, offset), FALSE);
263                 csnp_tree = proto_item_add_subtree(ti, ett_isis_csnp);
264         }
265
266         pdu_length = tvb_get_ntohs(tvb, offset);
267         if (tree) {
268                 proto_tree_add_uint(csnp_tree, hf_isis_csnp_pdu_length, tvb,
269                         offset, 2, pdu_length);
270         }
271         offset += 2;
272
273         if (tree) {
274                 proto_tree_add_text(csnp_tree, tvb, offset, id_length + 1, 
275                         "Source id    : %s",
276                                 print_system_id( tvb_get_ptr(tvb, offset, id_length+1), id_length+1 ) );
277         }
278         offset += id_length + 1;
279
280         if (tree) {
281                 isis_lsp_decode_lsp_id(tvb, pinfo, csnp_tree, offset,
282                         "Start LSP id ", id_length );
283         }
284         offset += id_length + 2;
285
286         if (tree) {
287                 isis_lsp_decode_lsp_id(tvb, pinfo, csnp_tree, offset,
288                          "End   LSP id ", id_length );
289         }
290         offset += id_length + 2;
291
292         len = pdu_length - header_length;
293         if (len < 0) {
294                 return;
295         }
296         /* Call into payload dissector */
297         if (type == ISIS_TYPE_L1_CSNP ) {
298                 isis_dissect_clvs(tvb, pinfo, csnp_tree, offset,
299                         clv_l1_csnp_opts, len, id_length,
300                         ett_isis_csnp_clv_unknown );
301         } else {
302                 isis_dissect_clvs(tvb, pinfo, csnp_tree, offset,
303                         clv_l2_csnp_opts, len, id_length,
304                         ett_isis_csnp_clv_unknown );
305         }
306 }
307
308 /*
309  * Name: isis_dissect_isis_psnp()
310  *
311  * Description:
312  *      Tear apart a L1 or L2 PSNP header and then call into payload dissect
313  *      to pull apart the lsp id payload.
314  *
315  * Input:
316  *      tvbuff_t * : tvbuffer for packet data
317  *      packet_info * : info for current packet
318  *      proto_tree * : protocol display tree to add to.  May be NULL.
319  *      int : our offset into packet data
320  *      int : type (l1 psnp, l2 psnp)
321  *      int : header length of packet.
322  *      int : length of IDs in packet.
323  *
324  * Output:
325  *      void, but we will add to proto tree if !NULL.
326  */
327 void 
328 isis_dissect_isis_psnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
329         int offset, int type, int header_length, int id_length)
330 {
331         proto_item      *ti;
332         proto_tree      *psnp_tree = NULL;
333         guint16         pdu_length;
334         int             len;
335
336         if (!proto_is_protocol_enabled(proto_isis_psnp)) {
337                 dissect_data(tvb, offset, pinfo, tree);
338                 return;
339         }
340
341         if (tree) {
342                 ti = proto_tree_add_item(tree, proto_isis_psnp, tvb,
343                         offset, tvb_length_remaining(tvb, offset), FALSE);
344                 psnp_tree = proto_item_add_subtree(ti, ett_isis_psnp);
345         }
346
347         pdu_length = tvb_get_ntohs(tvb, offset);
348         if (tree) {
349                 proto_tree_add_uint(psnp_tree, hf_isis_psnp_pdu_length, tvb,
350                         offset, 2, pdu_length);
351         }
352         offset += 2;
353
354         if (tree) {
355                 proto_tree_add_text(psnp_tree, tvb, offset, id_length + 1,
356                         "Source id: %s",
357                         print_system_id( tvb_get_ptr(tvb, offset, id_length+1), id_length + 1 ) );
358         }
359         offset += id_length + 1;
360
361         len = pdu_length - header_length;
362         if (len < 0) {
363                 isis_dissect_unknown(tvb, pinfo, tree, offset,
364                         "packet header length %d went beyond packet",
365                         header_length );
366                 return;
367         }
368         /* Call into payload dissector */
369         if (type == ISIS_TYPE_L1_CSNP ) {
370                 isis_dissect_clvs(tvb, pinfo, psnp_tree, offset,
371                         clv_l1_csnp_opts, len, id_length,
372                         ett_isis_psnp_clv_unknown );
373         } else {
374                 isis_dissect_clvs(tvb, pinfo, psnp_tree, offset,
375                         clv_l2_csnp_opts, len, id_length,
376                         ett_isis_psnp_clv_unknown );
377         }
378 }
379
380 /*
381  * Name: dissect_L1_snp_authentication_clv()
382  *
383  * Description:
384  *      Decode for a lsp packets authenticaion clv.  Calls into the
385  *      clv common one.  An auth inside a L1 SNP is a per area password
386  *
387  * Input:
388  *      tvbuff_t * : tvbuffer for packet data
389  *      packet_info * : info for current packet
390  *      proto_tree * : proto tree to build on (may be null)
391  *      int : current offset into packet data
392  *      int : length of IDs in packet.
393  *      int : length of this clv
394  *
395  * Output:
396  *      void, will modify proto_tree if not null.
397  */
398 static void 
399 dissect_l1_snp_authentication_clv(tvbuff_t *tvb, packet_info *pinfo,
400         proto_tree *tree, int offset,
401         int id_length, int length)
402 {
403         isis_dissect_authentication_clv(tvb, pinfo, tree, offset, length,
404                 "Per area authentication" );
405 }
406
407 /*
408  * Name: dissect_l2_authentication_clv()
409  *
410  * Description:
411  *      Decode for a lsp packets authenticaion clv.  Calls into the
412  *      clv common one.  An auth inside a L2 LSP is a per domain password
413  *
414  * Input:
415  *      tvbuff_t * : tvbuffer for packet data
416  *      packet_info * : info for current packet
417  *      proto_tree * : proto tree to build on (may be null)
418  *      int : current offset into packet data
419  *      int : length of IDs in packet.
420  *      int : length of this clv
421  *
422  * Output:
423  *      void, will modify proto_tree if not null.
424  */
425 static void 
426 dissect_l2_snp_authentication_clv(tvbuff_t *tvb, packet_info *pinfo,
427         proto_tree *tree, int offset,
428         int id_length, int length)
429 {
430         isis_dissect_authentication_clv(tvb, pinfo, tree, offset, length,
431                 "Per domain authentication" );
432 }
433
434 /*
435  * Name: proto_register_isis_csnp()
436  *
437  * Description: 
438  *      Register our protocol sub-sets with protocol manager.
439  *      NOTE: this procedure is autolinked by the makefile process that
440  *              builds register.c
441  *
442  */
443 void 
444 proto_register_isis_csnp(void) {
445         static hf_register_info hf[] = {
446                 { &hf_isis_csnp_pdu_length,
447                 { "PDU length",         "isis_csnp.pdu_length", FT_UINT16, 
448                   BASE_DEC, NULL, 0x0, "", HFILL }},
449         };
450         static gint *ett[] = {
451                 &ett_isis_csnp,
452                 &ett_isis_csnp_lsp_entries,
453                 &ett_isis_csnp_authentication,
454                 &ett_isis_csnp_clv_unknown,
455         };
456
457         proto_isis_csnp = proto_register_protocol(PROTO_STRING_CSNP,
458             "ISIS CSNP", "isis_csnp");
459         proto_register_field_array(proto_isis_csnp, hf, array_length(hf));
460         proto_register_subtree_array(ett, array_length(ett));
461 }
462
463
464 /*
465  * Name: proto_register_isis_psnp()
466  *
467  * Description: 
468  *      Register our protocol sub-sets with protocol manager.
469  *      NOTE: this procedure is autolinked by the makefile process that
470  *              builds register.c
471  */
472 void 
473 proto_register_isis_psnp(void) {
474         static hf_register_info hf[] = {
475                 { &hf_isis_psnp_pdu_length,
476                 { "PDU length",         "isis_psnp.pdu_length", FT_UINT16, 
477                   BASE_DEC, NULL, 0x0, "", HFILL }},
478         };
479         static gint *ett[] = {
480                 &ett_isis_psnp,
481                 &ett_isis_psnp_lsp_entries,
482                 &ett_isis_psnp_authentication,
483                 &ett_isis_psnp_clv_unknown,
484         };
485
486         proto_isis_psnp = proto_register_protocol(PROTO_STRING_PSNP,
487             "ISIS PSNP", "isis_psnp");
488         proto_register_field_array(proto_isis_psnp, hf, array_length(hf));
489         proto_register_subtree_array(ett, array_length(ett));
490 }