Revert "Fixup: tvb_* -> tvb_captured"
[metze/wireshark/wip.git] / epan / dissectors / packet-isis-snp.c
1 /* packet-isis-snp.c
2  * Routines for decoding isis complete & partial SNP and their payload
3  *
4  * Stuart Stanley <stuarts@mxmail.net>
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24
25 #include "config.h"
26
27 #include <glib.h>
28 #include <epan/packet.h>
29 #include <epan/expert.h>
30 #include "packet-osi.h"
31 #include "packet-isis.h"
32 #include "packet-isis-clv.h"
33
34 void proto_register_isis_csnp(void);
35 void proto_reg_handoff_isis_csnp(void);
36 void proto_register_isis_psnp(void);
37 void proto_reg_handoff_isis_psnp(void);
38 void proto_register_isis_lsp(void);
39 void proto_reg_handoff_isis_lsp(void);
40 void proto_register_isis_hello(void);
41 void proto_reg_handoff_isis_hello(void);
42
43 static int proto_isis_csnp = -1;
44 static int proto_isis_psnp = -1;
45
46 /* csnp packets */
47 static int hf_isis_csnp_pdu_length = -1;
48 static int hf_isis_csnp_source_id = -1;
49 static int hf_isis_csnp_start_lsp_id = -1;
50 static int hf_isis_csnp_end_lsp_id = -1;
51 static int hf_isis_csnp_lsp_id = -1;
52 static int hf_isis_csnp_lsp_seq_num = -1;
53 static int hf_isis_csnp_lsp_remain_life = -1;
54 static int hf_isis_csnp_lsp_checksum = -1;
55 static int hf_isis_csnp_checksum = -1;
56 static gint ett_isis_csnp = -1;
57 static gint ett_isis_csnp_clv_lsp_entries = -1;
58 static gint ett_isis_csnp_lsp_entry = -1;
59 static gint ett_isis_csnp_clv_authentication = -1;
60 static gint ett_isis_csnp_clv_ip_authentication = -1;
61 static gint ett_isis_csnp_clv_checksum = -1;
62 static gint ett_isis_csnp_clv_unknown = -1;
63
64 static expert_field ei_isis_csnp_short_packet = EI_INIT;
65 static expert_field ei_isis_csnp_long_packet = EI_INIT;
66 static expert_field ei_isis_csnp_authentication = EI_INIT;
67
68 /* psnp packets */
69 static int hf_isis_psnp_pdu_length = -1;
70 static int hf_isis_psnp_source_id = -1;
71 static gint ett_isis_psnp = -1;
72 static gint ett_isis_psnp_clv_lsp_entries = -1;
73 static gint ett_isis_psnp_lsp_entry = -1;
74 static gint ett_isis_psnp_clv_authentication = -1;
75 static gint ett_isis_psnp_clv_ip_authentication = -1;
76 static gint ett_isis_psnp_clv_checksum = -1;
77 static gint ett_isis_psnp_clv_unknown = -1;
78
79 static expert_field ei_isis_psnp_short_packet = EI_INIT;
80 static expert_field ei_isis_psnp_long_packet = EI_INIT;
81
82 static void
83 dissect_snp_authentication_clv(tvbuff_t *tvb, packet_info* pinfo, proto_tree *tree, int offset,
84         int id_length _U_, int length)
85 {
86         isis_dissect_authentication_clv(tree, pinfo, tvb, &ei_isis_csnp_authentication, offset, length);
87 }
88
89 static void
90 dissect_snp_ip_authentication_clv(tvbuff_t *tvb, packet_info* pinfo _U_, proto_tree *tree, int offset,
91         int id_length _U_, int length)
92 {
93         isis_dissect_ip_authentication_clv(tvb, tree, offset, length);
94 }
95
96 /*
97  * Name: dissect_snp_checksum_clv()
98  *
99  * Description:
100  *      dump and verify the optional checksum in TLV 12
101  */
102 static void
103 dissect_snp_checksum_clv(tvbuff_t *tvb, packet_info* pinfo,
104         proto_tree *tree, int offset, int id_length _U_, int length) {
105
106     guint16 pdu_length,checksum, cacl_checksum=0;
107     proto_item* ti;
108
109     if ( length != 2 ) {
110         proto_tree_add_expert_format(tree, pinfo, &ei_isis_csnp_short_packet, tvb, offset, -1,
111             "incorrect checksum length (%u), should be (2)", length );
112             return;
113     }
114
115     ti = proto_tree_add_item( tree, hf_isis_csnp_checksum, tvb, offset, length, ENC_BIG_ENDIAN);
116
117     checksum = tvb_get_ntohs(tvb, offset);
118
119         /* the check_and_get_checksum() function needs to know how big
120             * the packet is. we can either pass through the pdu-len through several layers
121             * of dissectors and wrappers or extract the PDU length field from the PDU specific header
122             * which is offseted 8 bytes (relative to the beginning of the IS-IS packet) in SNPs */
123
124     pdu_length = tvb_get_ntohs(tvb, 8);
125
126     /* unlike the LSP checksum verification which starts at an offset of 12 we start at offset 0*/
127     switch (check_and_get_checksum(tvb, 0, pdu_length, checksum, offset, &cacl_checksum))
128     {
129         case NO_CKSUM :
130              proto_item_append_text(ti, " [unused]");
131         break;
132         case DATA_MISSING :
133              expert_add_info_format(pinfo, ti, &ei_isis_csnp_long_packet,
134                                         "Packet length %d went beyond packet", tvb_length(tvb));
135         break;
136         case CKSUM_NOT_OK :
137              proto_item_append_text(ti, " [incorrect, should be 0x%04x]", cacl_checksum);
138         break;
139         case CKSUM_OK :
140              proto_item_append_text(ti, " [correct]");
141         break;
142     }
143 }
144
145 /*
146  * Name: dissect_snp_lsp_entries_clv()
147  *
148  * Description:
149  *      All the snp packets use a common payload format.  We have up
150  *      to n entries (based on length), which are made of:
151  *              2         : remaining life time
152  *              id_length : lsp id
153  *              4         : sequence number
154  *              2         : checksum
155  */
156 static void
157 dissect_snp_lsp_entries_clv(tvbuff_t *tvb, packet_info* pinfo, proto_tree *tree, int offset,
158         int id_length, int length)
159 {
160         proto_item *ti;
161         proto_tree *subtree;
162
163         while ( length > 0 ) {
164                 if ( length < 2+id_length+2+4+2 ) {
165                         proto_tree_add_expert_format(tree, pinfo, &ei_isis_csnp_short_packet, tvb, offset, -1,
166                                 "Short SNP header entry (%d vs %d)", length, 2+id_length+2+4+2 );
167                         return;
168                 }
169
170                 ti = proto_tree_add_text(tree, tvb, offset, 2+id_length+2+4+2, "LSP Entry");
171                 subtree = proto_item_add_subtree(ti,ett_isis_csnp_lsp_entry);
172
173                 proto_tree_add_item(tree, hf_isis_csnp_lsp_id, tvb, offset+2, id_length+2, ENC_NA);
174
175                 proto_tree_add_item(subtree, hf_isis_csnp_lsp_seq_num, tvb, offset+2+id_length+2, 4, ENC_BIG_ENDIAN);
176                 proto_tree_add_item(subtree, hf_isis_csnp_lsp_remain_life, tvb, offset, 2, ENC_BIG_ENDIAN);
177                 proto_tree_add_item(subtree, hf_isis_csnp_lsp_checksum, tvb, offset+2+id_length+2+4, 2, ENC_BIG_ENDIAN);
178
179                 length -= 2+id_length+2+4+2;
180                 offset += 2+id_length+2+4+2;
181         }
182
183 }
184
185 static const isis_clv_handle_t clv_l1_csnp_opts[] = {
186         {
187                 ISIS_CLV_LSP_ENTRIES,
188                 "LSP entries",
189                 &ett_isis_csnp_clv_lsp_entries,
190                 dissect_snp_lsp_entries_clv
191         },
192         {
193                 ISIS_CLV_AUTHENTICATION,
194                 "Authentication",
195                 &ett_isis_csnp_clv_authentication,
196                 dissect_snp_authentication_clv
197         },
198         {
199                 ISIS_CLV_IP_AUTHENTICATION,
200                 "IP Authentication",
201                 &ett_isis_csnp_clv_ip_authentication,
202                 dissect_snp_ip_authentication_clv
203         },
204         {
205                 ISIS_CLV_CHECKSUM,
206                 "Checksum",
207                 &ett_isis_csnp_clv_checksum,
208                 dissect_snp_checksum_clv
209         },
210         {
211                 0, "", NULL, NULL
212         }
213 };
214
215 static const isis_clv_handle_t clv_l2_csnp_opts[] = {
216         {
217                 ISIS_CLV_LSP_ENTRIES,
218                 "LSP entries",
219                 &ett_isis_csnp_clv_lsp_entries,
220                 dissect_snp_lsp_entries_clv
221         },
222         {
223                 ISIS_CLV_AUTHENTICATION,
224                 "Authentication",
225                 &ett_isis_csnp_clv_authentication,
226                 dissect_snp_authentication_clv
227         },
228         {
229                 ISIS_CLV_IP_AUTHENTICATION,
230                 "IP Authentication",
231                 &ett_isis_csnp_clv_ip_authentication,
232                 dissect_snp_ip_authentication_clv
233         },
234         {
235                 ISIS_CLV_CHECKSUM,
236                 "Checksum",
237                 &ett_isis_csnp_clv_checksum,
238                 dissect_snp_checksum_clv
239         },
240         {
241                 0, "", NULL, NULL
242         }
243 };
244
245 static const isis_clv_handle_t clv_l1_psnp_opts[] = {
246         {
247                 ISIS_CLV_LSP_ENTRIES,
248                 "LSP entries",
249                 &ett_isis_psnp_clv_lsp_entries,
250                 dissect_snp_lsp_entries_clv
251         },
252         {
253                 ISIS_CLV_AUTHENTICATION,
254                 "Authentication",
255                 &ett_isis_psnp_clv_authentication,
256                 dissect_snp_authentication_clv
257         },
258         {
259                 ISIS_CLV_IP_AUTHENTICATION,
260                 "IP Authentication",
261                 &ett_isis_psnp_clv_ip_authentication,
262                 dissect_snp_ip_authentication_clv
263         },
264         {
265                 ISIS_CLV_CHECKSUM,
266                 "Checksum",
267                 &ett_isis_psnp_clv_checksum,
268                 dissect_snp_checksum_clv
269         },
270         {
271                 0, "", NULL, NULL
272         }
273 };
274
275 static const isis_clv_handle_t clv_l2_psnp_opts[] = {
276         {
277                 ISIS_CLV_LSP_ENTRIES,
278                 "LSP entries",
279                 &ett_isis_psnp_clv_lsp_entries,
280                 dissect_snp_lsp_entries_clv
281         },
282         {
283                 ISIS_CLV_AUTHENTICATION,
284                 "Authentication",
285                 &ett_isis_psnp_clv_authentication,
286                 dissect_snp_authentication_clv
287         },
288         {
289                 ISIS_CLV_IP_AUTHENTICATION,
290                 "IP Authentication",
291                 &ett_isis_psnp_clv_ip_authentication,
292                 dissect_snp_ip_authentication_clv
293         },
294         {
295                 ISIS_CLV_CHECKSUM,
296                 "Checksum",
297                 &ett_isis_psnp_clv_checksum,
298                 dissect_snp_checksum_clv
299         },
300         {
301                 0, "", NULL, NULL
302         }
303 };
304
305 static void
306 dissect_isis_csnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset,
307         const isis_clv_handle_t *opts, int header_length, int id_length)
308 {
309         proto_item      *ti;
310         proto_tree      *csnp_tree = NULL;
311         guint16         pdu_length;
312         int             len;
313
314         col_set_str(pinfo->cinfo, COL_PROTOCOL, "ISIS CSNP");
315
316         ti = proto_tree_add_item(tree, proto_isis_csnp, tvb, offset, -1, ENC_NA);
317         csnp_tree = proto_item_add_subtree(ti, ett_isis_csnp);
318
319         pdu_length = tvb_get_ntohs(tvb, offset);
320         proto_tree_add_uint(csnp_tree, hf_isis_csnp_pdu_length, tvb,
321                         offset, 2, pdu_length);
322         offset += 2;
323
324         proto_tree_add_item(csnp_tree, hf_isis_csnp_source_id, tvb, offset, id_length, ENC_NA);
325         col_append_fstr(pinfo->cinfo, COL_INFO, ", Source-ID: %s", tvb_print_system_id( tvb, offset, id_length ));
326         offset += id_length + 1;
327
328         proto_tree_add_item(csnp_tree, hf_isis_csnp_start_lsp_id, tvb, offset, id_length + 2, ENC_NA);
329         col_append_fstr(pinfo->cinfo, COL_INFO, ", Start LSP-ID: %s",
330                                         tvb_print_system_id( tvb, offset, id_length+2 ));
331         offset += id_length + 2;
332
333         proto_tree_add_item(csnp_tree, hf_isis_csnp_end_lsp_id, tvb, offset, id_length + 2, ENC_NA);
334         col_append_fstr(pinfo->cinfo, COL_INFO, ", End LSP-ID: %s",
335                                         tvb_print_system_id( tvb, offset, id_length+2 ));
336         offset += id_length + 2;
337
338         len = pdu_length - header_length;
339         if (len < 0) {
340                 proto_tree_add_expert_format(tree, pinfo, &ei_isis_csnp_short_packet, tvb, offset, -1,
341                         "packet header length %d went beyond packet", header_length );
342                 return;
343         }
344
345         isis_dissect_clvs(tvb, pinfo, csnp_tree, offset,
346                         opts, &ei_isis_csnp_short_packet, len, id_length, ett_isis_csnp_clv_unknown );
347 }
348
349
350 static int
351 dissect_isis_l1_csnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
352 {
353         isis_data_t* isis = (isis_data_t*)data;
354         dissect_isis_csnp(tvb, pinfo, tree, 0,
355                 clv_l1_csnp_opts, isis->header_length, isis->system_id_len);
356         return tvb_length(tvb);
357 }
358
359 static int
360 dissect_isis_l2_csnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
361 {
362         isis_data_t* isis = (isis_data_t*)data;
363         dissect_isis_csnp(tvb, pinfo, tree, 0,
364                 clv_l2_csnp_opts, isis->header_length, isis->system_id_len);
365         return tvb_length(tvb);
366 }
367
368 static void
369 dissect_isis_psnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset,
370         const isis_clv_handle_t *opts, int header_length, int id_length)
371 {
372         proto_item      *ti;
373         proto_tree      *psnp_tree;
374         guint16         pdu_length;
375         int             len;
376
377         col_set_str(pinfo->cinfo, COL_PROTOCOL, "ISIS PSNP");
378
379         ti = proto_tree_add_item(tree, proto_isis_psnp, tvb, offset, -1, ENC_NA);
380         psnp_tree = proto_item_add_subtree(ti, ett_isis_psnp);
381
382         pdu_length = tvb_get_ntohs(tvb, offset);
383         proto_tree_add_uint(psnp_tree, hf_isis_psnp_pdu_length, tvb,
384                         offset, 2, pdu_length);
385         offset += 2;
386
387         proto_tree_add_item(psnp_tree, hf_isis_psnp_source_id, tvb, offset, id_length, ENC_NA);
388         col_append_fstr(pinfo->cinfo, COL_INFO, ", Source-ID: %s", tvb_print_system_id( tvb, offset, id_length ));
389
390         offset += id_length + 1;
391
392         len = pdu_length - header_length;
393         if (len < 0) {
394                 proto_tree_add_expert_format(tree, pinfo, &ei_isis_psnp_long_packet, tvb, offset, -1,
395                         "packet header length %d went beyond packet", header_length );
396                 return;
397         }
398         /* Call into payload dissector */
399         isis_dissect_clvs(tvb, pinfo, psnp_tree, offset,
400                         opts, &ei_isis_psnp_short_packet, len, id_length, ett_isis_psnp_clv_unknown );
401 }
402
403 static int
404 dissect_isis_l1_psnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
405 {
406         isis_data_t* isis = (isis_data_t*)data;
407         dissect_isis_psnp(tvb, pinfo, tree, 0,
408                 clv_l1_psnp_opts, isis->header_length, isis->system_id_len);
409         return tvb_length(tvb);
410 }
411
412 static int
413 dissect_isis_l2_psnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
414 {
415         isis_data_t* isis = (isis_data_t*)data;
416         dissect_isis_psnp(tvb, pinfo, tree, 0,
417                 clv_l2_psnp_opts, isis->header_length, isis->system_id_len);
418         return tvb_length(tvb);
419 }
420
421 void
422 proto_register_isis_csnp(void)
423 {
424         static hf_register_info hf[] = {
425                 { &hf_isis_csnp_pdu_length,
426                 { "PDU length",         "isis.csnp.pdu_length", FT_UINT16,
427                   BASE_DEC, NULL, 0x0, NULL, HFILL }},
428                 { &hf_isis_csnp_source_id,
429                 { "Source-ID", "isis.csnp.source_id",
430                         FT_SYSTEM_ID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
431                 { &hf_isis_csnp_start_lsp_id,
432                 { "Start LSP-ID", "isis.csnp.start_lsp_id",
433                         FT_SYSTEM_ID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
434                 { &hf_isis_csnp_end_lsp_id,
435                 { "End LSP-ID", "isis.csnp.end_lsp_id",
436                         FT_SYSTEM_ID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
437                 { &hf_isis_csnp_lsp_id,
438                 { "LSP-ID", "isis.csnp.lsp_id",
439                         FT_SYSTEM_ID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
440                 { &hf_isis_csnp_lsp_seq_num,
441                 { "LSP Sequence Number",                "isis.csnp.lsp_seq_num", FT_UINT32,
442                   BASE_HEX, NULL, 0x0, NULL, HFILL }},
443                 { &hf_isis_csnp_lsp_remain_life,
444                 { "Remaining Lifetime",         "isis.csnp.lsp_remain_life", FT_UINT16,
445                   BASE_DEC, NULL, 0x0, NULL, HFILL }},
446                 { &hf_isis_csnp_lsp_checksum,
447                 { "LSP checksum",               "isis.csnp.lsp_checksum", FT_UINT16,
448                   BASE_HEX, NULL, 0x0, NULL, HFILL }},
449                 { &hf_isis_csnp_checksum,
450                 { "Checksum",           "isis.csnp.checksum", FT_UINT16,
451                   BASE_HEX, NULL, 0x0, NULL, HFILL }},
452         };
453
454         static gint *ett[] = {
455                 &ett_isis_csnp,
456                 &ett_isis_csnp_clv_lsp_entries,
457                 &ett_isis_csnp_lsp_entry,
458                 &ett_isis_csnp_clv_authentication,
459                 &ett_isis_csnp_clv_ip_authentication,
460                 &ett_isis_csnp_clv_checksum,
461                 &ett_isis_csnp_clv_unknown,
462         };
463
464         static ei_register_info ei[] = {
465                 { &ei_isis_csnp_short_packet, { "isis.csnp.short_packet", PI_MALFORMED, PI_ERROR, "Short packet", EXPFILL }},
466                 { &ei_isis_csnp_long_packet, { "isis.csnp.long_packet", PI_MALFORMED, PI_ERROR, "Long packet", EXPFILL }},
467                 { &ei_isis_csnp_authentication, { "isis.csnp.authentication.unknown", PI_PROTOCOL, PI_WARN, "Unknown authentication type", EXPFILL }},
468         };
469         expert_module_t* expert_isis_csnp;
470
471         /* Register the protocol name and description */
472         proto_isis_csnp = proto_register_protocol(PROTO_STRING_CSNP, "ISIS CSNP", "isis.csnp");
473
474         proto_register_field_array(proto_isis_csnp, hf, array_length(hf));
475         proto_register_subtree_array(ett, array_length(ett));
476         expert_isis_csnp = expert_register_protocol(proto_isis_csnp);
477         expert_register_field_array(expert_isis_csnp, ei, array_length(ei));
478 }
479
480 void
481 proto_reg_handoff_isis_csnp(void)
482 {
483         dissector_add_uint("isis.type", ISIS_TYPE_L1_CSNP, new_create_dissector_handle(dissect_isis_l1_csnp, proto_isis_csnp));
484         dissector_add_uint("isis.type", ISIS_TYPE_L2_CSNP, new_create_dissector_handle(dissect_isis_l2_csnp, proto_isis_csnp));
485 }
486
487 void
488 proto_register_isis_psnp(void)
489 {
490         static hf_register_info hf[] = {
491                 { &hf_isis_psnp_pdu_length,
492                 { "PDU length",         "isis.psnp.pdu_length", FT_UINT16,
493                   BASE_DEC, NULL, 0x0, NULL, HFILL }},
494                 { &hf_isis_psnp_source_id,
495                 { "Source-ID", "isis.psnp.source_id",
496                         FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
497         };
498
499         static gint *ett[] = {
500                 &ett_isis_psnp,
501                 &ett_isis_psnp_clv_lsp_entries,
502                 &ett_isis_psnp_lsp_entry,
503                 &ett_isis_psnp_clv_authentication,
504                 &ett_isis_psnp_clv_ip_authentication,
505                 &ett_isis_psnp_clv_checksum,
506                 &ett_isis_psnp_clv_unknown,
507         };
508         static ei_register_info ei[] = {
509                 { &ei_isis_psnp_long_packet, { "isis.psnp.long_packet", PI_MALFORMED, PI_ERROR, "Long packet", EXPFILL }},
510                 { &ei_isis_psnp_short_packet, { "isis.psnp.short_packet", PI_MALFORMED, PI_ERROR, "Short packet", EXPFILL }},
511         };
512         expert_module_t* expert_isis_psnp;
513
514         /* Register the protocol name and description */
515         proto_isis_psnp = proto_register_protocol(PROTO_STRING_PSNP, "ISIS PSNP", "isis.psnp");
516
517         proto_register_field_array(proto_isis_psnp, hf, array_length(hf));
518         proto_register_subtree_array(ett, array_length(ett));
519         expert_isis_psnp = expert_register_protocol(proto_isis_psnp);
520         expert_register_field_array(expert_isis_psnp, ei, array_length(ei));
521 }
522
523 void
524 proto_reg_handoff_isis_psnp(void)
525 {
526         dissector_add_uint("isis.type", ISIS_TYPE_L1_PSNP, new_create_dissector_handle(dissect_isis_l1_psnp, proto_isis_psnp));
527         dissector_add_uint("isis.type", ISIS_TYPE_L2_PSNP, new_create_dissector_handle(dissect_isis_l2_psnp, proto_isis_psnp));
528 }