some compilers dont like unnamed unions and structs
[obnox/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  * $Id$
5  * Stuart Stanley <stuarts@mxmail.net>
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <glib.h>
33 #include <epan/packet.h>
34 #include "packet-osi.h"
35 #include "packet-isis.h"
36 #include "packet-isis-clv.h"
37 #include "packet-isis-lsp.h"
38 #include "packet-isis-snp.h"
39
40 /* csnp packets */
41 static int hf_isis_csnp_pdu_length = -1;
42 static gint ett_isis_csnp = -1;
43 static gint ett_isis_csnp_clv_lsp_entries = -1;
44 static gint ett_isis_csnp_lsp_entry = -1;
45 static gint ett_isis_csnp_clv_authentication = -1;
46 static gint ett_isis_csnp_clv_ip_authentication = -1;
47 static gint ett_isis_csnp_clv_checksum = -1;
48 static gint ett_isis_csnp_clv_unknown = -1;
49
50 /* psnp packets */
51 static int hf_isis_psnp_pdu_length = -1;
52 static gint ett_isis_psnp = -1;
53 static gint ett_isis_psnp_clv_lsp_entries = -1;
54 static gint ett_isis_psnp_lsp_entry = -1;
55 static gint ett_isis_psnp_clv_authentication = -1;
56 static gint ett_isis_psnp_clv_ip_authentication = -1;
57 static gint ett_isis_psnp_clv_checksum = -1;
58 static gint ett_isis_psnp_clv_unknown = -1;
59
60 static void dissect_snp_authentication_clv(tvbuff_t *tvb,
61         proto_tree *tree, int offset, int id_length, int length);
62 static void dissect_snp_ip_authentication_clv(tvbuff_t *tvb,
63         proto_tree *tree, int offset, int id_length, int length);
64 static void dissect_snp_checksum_clv(tvbuff_t *tvb,
65         proto_tree *tree, int offset, int id_length, int length);
66 static void dissect_snp_lsp_entries_clv(tvbuff_t *tvb,
67         proto_tree *tree, int offset, int id_length, int length);
68
69 static const isis_clv_handle_t clv_l1_csnp_opts[] = {
70         {
71                 ISIS_CLV_LSP_ENTRIES,
72                 "LSP entries",
73                 &ett_isis_csnp_clv_lsp_entries,
74                 dissect_snp_lsp_entries_clv
75         },
76         {
77                 ISIS_CLV_AUTHENTICATION,
78                 "Authentication",
79                 &ett_isis_csnp_clv_authentication,
80                 dissect_snp_authentication_clv
81         },
82         {
83                 ISIS_CLV_IP_AUTHENTICATION,
84                 "IP Authentication",
85                 &ett_isis_csnp_clv_ip_authentication,
86                 dissect_snp_ip_authentication_clv
87         },
88         {
89                 ISIS_CLV_CHECKSUM,
90                 "Checksum",
91                 &ett_isis_csnp_clv_checksum,
92                 dissect_snp_checksum_clv
93         },
94         {
95                 0, "", NULL, NULL
96         }
97 };
98
99 static const isis_clv_handle_t clv_l2_csnp_opts[] = {
100         {
101                 ISIS_CLV_LSP_ENTRIES,
102                 "LSP entries",
103                 &ett_isis_csnp_clv_lsp_entries,
104                 dissect_snp_lsp_entries_clv
105         },
106         {
107                 ISIS_CLV_AUTHENTICATION,
108                 "Authentication",
109                 &ett_isis_csnp_clv_authentication,
110                 dissect_snp_authentication_clv
111         },
112         {
113                 ISIS_CLV_IP_AUTHENTICATION,
114                 "IP Authentication",
115                 &ett_isis_csnp_clv_ip_authentication,
116                 dissect_snp_ip_authentication_clv
117         },
118         {
119                 ISIS_CLV_CHECKSUM,
120                 "Checksum",
121                 &ett_isis_csnp_clv_checksum,
122                 dissect_snp_checksum_clv
123         },
124         {
125                 0, "", NULL, NULL
126         }
127 };
128
129 static const isis_clv_handle_t clv_l1_psnp_opts[] = {
130         {
131                 ISIS_CLV_LSP_ENTRIES,
132                 "LSP entries",
133                 &ett_isis_psnp_clv_lsp_entries,
134                 dissect_snp_lsp_entries_clv
135         },
136         {
137                 ISIS_CLV_AUTHENTICATION,
138                 "Authentication",
139                 &ett_isis_psnp_clv_authentication,
140                 dissect_snp_authentication_clv
141         },
142         {
143                 ISIS_CLV_IP_AUTHENTICATION,
144                 "IP Authentication",
145                 &ett_isis_psnp_clv_ip_authentication,
146                 dissect_snp_ip_authentication_clv
147         },
148         {
149                 ISIS_CLV_CHECKSUM,
150                 "Checksum",
151                 &ett_isis_psnp_clv_checksum,
152                 dissect_snp_checksum_clv
153         },
154         {
155                 0, "", NULL, NULL
156         }
157 };
158
159 static const isis_clv_handle_t clv_l2_psnp_opts[] = {
160         {
161                 ISIS_CLV_LSP_ENTRIES,
162                 "LSP entries",
163                 &ett_isis_psnp_clv_lsp_entries,
164                 dissect_snp_lsp_entries_clv
165         },
166         {
167                 ISIS_CLV_AUTHENTICATION,
168                 "Authentication",
169                 &ett_isis_psnp_clv_authentication,
170                 dissect_snp_authentication_clv
171         },
172         {
173                 ISIS_CLV_IP_AUTHENTICATION,
174                 "IP Authentication",
175                 &ett_isis_psnp_clv_ip_authentication,
176                 dissect_snp_ip_authentication_clv
177         },
178         {
179                 ISIS_CLV_CHECKSUM,
180                 "Checksum",
181                 &ett_isis_psnp_clv_checksum,
182                 dissect_snp_checksum_clv
183         },
184         {
185                 0, "", NULL, NULL
186         }
187 };
188
189 /*
190  * Name: dissect_snp_lsp_entries_clv()
191  *
192  * Description:
193  *      All the snp packets use a common payload format.  We have up
194  *      to n entries (based on length), which are made of:
195  *              2         : remaining life time
196  *              id_length : lsp id
197  *              4         : sequence number
198  *              2         : checksum
199  *
200  * Input:
201  *      tvbuff_t * : tvbuffer for packet data
202  *      proto_tree * : protocol display tree to fill out.  May be NULL
203  *      int : offset into packet data where we are.
204  *      int : length of IDs in packet.
205  *      int : length of payload to decode.
206  *
207  * Output:
208  *      void, but we will add to proto tree if !NULL.
209  */
210 static void
211 dissect_snp_lsp_entries_clv(tvbuff_t *tvb, proto_tree *tree, int offset,
212         int id_length, int length)
213 {
214         proto_tree *subtree,*ti;
215
216         while ( length > 0 ) {
217                 if ( length < 2+id_length+2+4+2 ) {
218                         isis_dissect_unknown(tvb, tree, offset,
219                                 "Short SNP header entry (%d vs %d)", length,
220                                 2+id_length+2+4+2 );
221                         return;
222                 }
223
224                 ti = proto_tree_add_text(tree, tvb, offset, 2+id_length+2+4+2,
225                                     "LSP-ID: %s, Sequence: 0x%08x, Lifetime: %5us, Checksum: 0x%04x",
226                                            print_system_id( tvb_get_ptr(tvb, offset+2, id_length+2), id_length+2 ),
227                                            tvb_get_ntohl(tvb, offset+2+id_length+2),
228                                            tvb_get_ntohs(tvb, offset),
229                                            tvb_get_ntohs(tvb, offset+2+id_length+2+4));
230
231                 subtree = proto_item_add_subtree(ti,ett_isis_csnp_lsp_entry);
232
233                 proto_tree_add_text(subtree, tvb, offset+2, 8,
234                         "LSP-ID:             : %s",
235                         print_system_id( tvb_get_ptr(tvb, offset+2, id_length+2), id_length+2 ));
236
237                 proto_tree_add_text(subtree, tvb, offset+2+id_length+2, 4,
238                         "LSP Sequence Number : 0x%08x",
239                         tvb_get_ntohl(tvb, offset+2+id_length+2));
240
241                 proto_tree_add_text(subtree, tvb, offset, 2,
242                         "Remaining Lifetime  : %us",
243                         tvb_get_ntohs(tvb, offset));
244
245                 proto_tree_add_text(subtree, tvb, offset+2+id_length+2+4, 2,
246                         "LSP checksum        : 0x%04x",
247                         tvb_get_ntohs(tvb, offset+2+id_length+2+4));
248
249                 length -= 2+id_length+2+4+2;
250                 offset += 2+id_length+2+4+2;
251         }
252
253 }
254
255
256 /*
257  * Name: isis_dissect_isis_csnp()
258  *
259  * Description:
260  *      Tear apart a L1 or L2 CSNP header and then call into payload dissect
261  *      to pull apart the lsp id payload.
262  *
263  * Input:
264  *      tvbuff_t * : tvbuffer for packet data
265  *      proto_tree * : protocol display tree to add to.  May be NULL.
266  *      int offset : our offset into packet data.
267  *      int : type (l1 csnp, l2 csnp)
268  *      int : header length of packet.
269  *      int : length of IDs in packet.
270  *
271  * Output:
272  *      void, but we will add to proto tree if !NULL.
273  */
274 void
275 isis_dissect_isis_csnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset,
276         int type, int header_length, int id_length)
277 {
278         proto_item      *ti;
279         proto_tree      *csnp_tree = NULL;
280         guint16         pdu_length;
281         int             len;
282
283         if (tree) {
284                 ti = proto_tree_add_text(tree, tvb, offset, -1,
285                     PROTO_STRING_CSNP);
286                 csnp_tree = proto_item_add_subtree(ti, ett_isis_csnp);
287         }
288
289         pdu_length = tvb_get_ntohs(tvb, offset);
290         if (tree) {
291                 proto_tree_add_uint(csnp_tree, hf_isis_csnp_pdu_length, tvb,
292                         offset, 2, pdu_length);
293         }
294         offset += 2;
295
296         if (tree) {
297                 proto_tree_add_text(csnp_tree, tvb, offset, id_length + 1,
298                         "Source-ID:    %s",
299                                 print_system_id( tvb_get_ptr(tvb, offset, id_length+1), id_length+1 ) );
300         }
301         if (check_col(pinfo->cinfo, COL_INFO)) {
302                 col_append_fstr(pinfo->cinfo, COL_INFO, ", Source-ID: %s",
303                         print_system_id( tvb_get_ptr(tvb, offset, id_length+1), id_length+1 ) );
304         }
305         offset += id_length + 1;
306
307         if (tree) {
308                 proto_tree_add_text(csnp_tree, tvb, offset, id_length + 2,
309                         "Start LSP-ID: %s",
310                                     print_system_id( tvb_get_ptr(tvb, offset, id_length+2), id_length+2 ) );                
311         }
312         if (check_col(pinfo->cinfo, COL_INFO)) {
313                 col_append_fstr(pinfo->cinfo, COL_INFO, ", Start LSP-ID: %s",
314                         print_system_id( tvb_get_ptr(tvb, offset, id_length+2), id_length+2 ) );
315         }
316         offset += id_length + 2;
317
318         if (tree) {
319                 proto_tree_add_text(csnp_tree, tvb, offset, id_length + 2,
320                         "End LSP-ID: %s",
321                                     print_system_id( tvb_get_ptr(tvb, offset, id_length+2), id_length+2 ) );  
322         }
323         if (check_col(pinfo->cinfo, COL_INFO)) {
324                 col_append_fstr(pinfo->cinfo, COL_INFO, ", End LSP-ID: %s",
325                         print_system_id( tvb_get_ptr(tvb, offset, id_length+2), id_length+2 ) );
326         }
327         offset += id_length + 2;
328
329         len = pdu_length - header_length;
330         if (len < 0) {
331                 return;
332         }
333         /* Call into payload dissector */
334         if (type == ISIS_TYPE_L1_CSNP ) {
335                 isis_dissect_clvs(tvb, csnp_tree, offset,
336                         clv_l1_csnp_opts, len, id_length,
337                         ett_isis_csnp_clv_unknown );
338         } else {
339                 isis_dissect_clvs(tvb, csnp_tree, offset,
340                         clv_l2_csnp_opts, len, id_length,
341                         ett_isis_csnp_clv_unknown );
342         }
343 }
344
345 /*
346  * Name: isis_dissect_isis_psnp()
347  *
348  * Description:
349  *      Tear apart a L1 or L2 PSNP header and then call into payload dissect
350  *      to pull apart the lsp id payload.
351  *
352  * Input:
353  *      tvbuff_t * : tvbuffer for packet data
354  *      proto_tree * : protocol display tree to add to.  May be NULL.
355  *      int : our offset into packet data
356  *      int : type (l1 psnp, l2 psnp)
357  *      int : header length of packet.
358  *      int : length of IDs in packet.
359  *
360  * Output:
361  *      void, but we will add to proto tree if !NULL.
362  */
363 void
364 isis_dissect_isis_psnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset,
365         int type, int header_length, int id_length)
366 {
367         proto_item      *ti;
368         proto_tree      *psnp_tree = NULL;
369         guint16         pdu_length;
370         int             len;
371
372         if (tree) {
373                 ti = proto_tree_add_text(tree, tvb, offset, -1,
374                     PROTO_STRING_PSNP);
375                 psnp_tree = proto_item_add_subtree(ti, ett_isis_psnp);
376         }
377
378         pdu_length = tvb_get_ntohs(tvb, offset);
379         if (tree) {
380                 proto_tree_add_uint(psnp_tree, hf_isis_psnp_pdu_length, tvb,
381                         offset, 2, pdu_length);
382         }
383         offset += 2;
384
385         if (tree) {
386                 proto_tree_add_text(psnp_tree, tvb, offset, id_length + 1,
387                         "Source-ID: %s",
388                         print_system_id( tvb_get_ptr(tvb, offset, id_length+1), id_length + 1 ) );
389         }
390         if (check_col(pinfo->cinfo, COL_INFO)) {
391                 col_append_fstr(pinfo->cinfo, COL_INFO, ", Source-ID: %s",
392                         print_system_id( tvb_get_ptr(tvb, offset, id_length+1), id_length+1 ) );
393         }
394         offset += id_length + 1;
395
396         len = pdu_length - header_length;
397         if (len < 0) {
398                 isis_dissect_unknown(tvb, tree, offset,
399                         "packet header length %d went beyond packet",
400                         header_length );
401                 return;
402         }
403         /* Call into payload dissector */
404         if (type == ISIS_TYPE_L1_PSNP ) {
405                 isis_dissect_clvs(tvb, psnp_tree, offset,
406                         clv_l1_psnp_opts, len, id_length,
407                         ett_isis_psnp_clv_unknown );
408         } else {
409                 isis_dissect_clvs(tvb, psnp_tree, offset,
410                         clv_l2_psnp_opts, len, id_length,
411                         ett_isis_psnp_clv_unknown );
412         }
413 }
414
415 /*
416  * Name: dissect_snp_authentication_clv()
417  *
418  * Description:
419  *      Decode for a snp packets authenticaion clv.
420  *      Calls into the CLV common one.
421  *
422  * Input:
423  *      tvbuff_t * : tvbuffer for packet data
424  *      proto_tree * : proto tree to build on (may be null)
425  *      int : current offset into packet data
426  *      int : length of IDs in packet.
427  *      int : length of this clv
428  *
429  * Output:
430  *      void, will modify proto_tree if not null.
431  */
432 static void
433 dissect_snp_authentication_clv(tvbuff_t *tvb, proto_tree *tree, int offset,
434         int id_length _U_, int length)
435 {
436         isis_dissect_authentication_clv(tvb, tree, offset, length);
437 }
438
439 /*
440  * Name: dissect_snp_ip_authentication_clv()
441  *
442  * Description:
443  *      Decode for a snp packets authenticaion clv.
444  *      Calls into the CLV common one.
445  *
446  * Input:
447  *      tvbuff_t * : tvbuffer for packet data
448  *      proto_tree * : proto tree to build on (may be null)
449  *      int : current offset into packet data
450  *      int : length of IDs in packet.
451  *      int : length of this clv
452  *
453  * Output:
454  *      void, will modify proto_tree if not null.
455  */
456 static void
457 dissect_snp_ip_authentication_clv(tvbuff_t *tvb, proto_tree *tree, int offset,
458         int id_length _U_, int length)
459 {
460         isis_dissect_ip_authentication_clv(tvb, tree, offset, length);
461 }
462
463 /*
464  * Name: dissect_snp_checksum_clv()
465  *
466  * Description:
467  *      dump and verify the optional checksum in TLV 12
468  *
469  * Input:
470  *      tvbuff_t * : tvbuffer for packet data
471  *      proto_tree * : protocol display tree to fill out.  May be NULL
472  *      int : offset into packet data where we are.
473  *      int : length of clv we are decoding
474  *
475  * Output:
476  *      void, but we will add to proto tree if !NULL.
477  */
478
479 static void
480 dissect_snp_checksum_clv(tvbuff_t *tvb,
481         proto_tree *tree, int offset, int id_length _U_, int length) {
482
483         guint16 pdu_length,checksum, cacl_checksum=0;
484
485         if (tree) {
486                 if ( length != 2 ) {
487                         proto_tree_add_text ( tree, tvb, offset, length,
488                                               "incorrect checksum length (%u), should be (2)", length );
489                         return;
490                 }
491
492                 checksum = tvb_get_ntohs(tvb, offset);                  
493
494                 /* the check_and_get_checksum() function needs to know how big
495                  * the packet is. we can either pass through the pdu-len through several layers
496                  * of dissectors and wrappers or extract the PDU length field from the PDU specific header
497                  * which is offseted 8 bytes (relative to the beginning of the IS-IS packet) in SNPs */
498
499                 pdu_length = tvb_get_ntohs(tvb, 8);   
500
501                 /* unlike the LSP checksum verification which starts at an offset of 12 we start at offset 0*/
502                 switch (check_and_get_checksum(tvb, 0, pdu_length, checksum, offset, &cacl_checksum))
503                 {
504
505                         case NO_CKSUM :
506                                 proto_tree_add_text ( tree, tvb, offset, length,
507                                                       "Checksum: 0x%04x [unused]", checksum);
508                         break;
509                         case DATA_MISSING :
510                                 isis_dissect_unknown(tvb, tree, offset,
511                                                      "[packet length %d went beyond packet]",
512                                                      tvb_length_remaining(tvb, 0));
513                         break;
514                         case CKSUM_NOT_OK :
515                                 proto_tree_add_text ( tree, tvb, offset, length,
516                                                       "Checksum: 0x%04x [incorrect, should be 0x%04x]",
517                                                       checksum,
518                                                       cacl_checksum);
519                         break;
520                         case CKSUM_OK :
521                                 proto_tree_add_text ( tree, tvb, offset, length,
522                                                       "Checksum: 0x%04x [correct]", checksum);
523                         break;
524                         default :
525                                 g_message("'check_and_get_checksum' returned an invalid value");
526                 }
527         }
528 }
529
530 /*
531  * Name: isis_register_csnp()
532  *
533  * Description:
534  *      Register our protocol sub-sets with protocol manager.
535  *
536  * Input:
537  *      int : protocol index for the ISIS protocol
538  *
539  * Output:
540  *      void
541  */
542 void
543 isis_register_csnp(int proto_isis) {
544         static hf_register_info hf[] = {
545                 { &hf_isis_csnp_pdu_length,
546                 { "PDU length",         "isis.csnp.pdu_length", FT_UINT16,
547                   BASE_DEC, NULL, 0x0, "", HFILL }},
548         };
549         static gint *ett[] = {
550                 &ett_isis_csnp,
551                 &ett_isis_csnp_clv_lsp_entries,
552                 &ett_isis_csnp_lsp_entry,
553                 &ett_isis_csnp_clv_authentication,
554                 &ett_isis_csnp_clv_ip_authentication,
555                 &ett_isis_csnp_clv_checksum,
556                 &ett_isis_csnp_clv_unknown,
557         };
558
559         proto_register_field_array(proto_isis, hf, array_length(hf));
560         proto_register_subtree_array(ett, array_length(ett));
561 }
562
563
564 /*
565  * Name: isis_register_psnp()
566  *
567  * Description:
568  *      Register our protocol sub-sets with protocol manager.
569  *
570  * Input:
571  *      int : protocol index for the ISIS protocol
572  *
573  * Output:
574  *      void
575  */
576 void
577 isis_register_psnp(int proto_isis) {
578         static hf_register_info hf[] = {
579                 { &hf_isis_psnp_pdu_length,
580                 { "PDU length",         "isis.psnp.pdu_length", FT_UINT16,
581                   BASE_DEC, NULL, 0x0, "", HFILL }},
582         };
583         static gint *ett[] = {
584                 &ett_isis_psnp,
585                 &ett_isis_psnp_clv_lsp_entries,
586                 &ett_isis_psnp_lsp_entry,
587                 &ett_isis_psnp_clv_authentication,
588                 &ett_isis_psnp_clv_ip_authentication,
589                 &ett_isis_psnp_clv_checksum,
590                 &ett_isis_psnp_clv_unknown,
591         };
592
593         proto_register_field_array(proto_isis, hf, array_length(hf));
594         proto_register_subtree_array(ett, array_length(ett));
595 }