Add routines for adding items to a protocol tree that take arguments of
[obnox/wireshark/wip.git] / packet-isis-lsp.c
1 /* packet-isis-lsp.c
2  * Routines for decoding isis lsp packets and their CLVs
3  *
4  * $Id: packet-isis-lsp.c,v 1.7 2000/05/31 05:07:12 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
41 #ifdef HAVE_NET_INET_H
42 #include <net/inet.h>
43 #endif
44
45 #include "packet.h"
46 #include "packet-osi.h"
47 #include "packet-isis.h"
48 #include "packet-isis-clv.h"
49 #include "packet-isis-lsp.h"
50 #include "resolv.h"
51
52 /* lsp packets */
53 static int proto_isis_lsp = -1;
54 static int hf_isis_lsp_pdu_length = -1;
55 static int hf_isis_lsp_remaining_life = -1;
56 static int hf_isis_lsp_sequence_number = -1;
57 static int hf_isis_lsp_checksum = -1;
58 static int hf_isis_lsp_clv_ipv4_int_addr = -1;
59
60 static gint ett_isis_lsp = -1;
61 static gint ett_isis_lsp_clv_area_addr = -1;
62 static gint ett_isis_lsp_clv_is_neighbors = -1;
63 static gint ett_isis_lsp_clv_unknown = -1;
64 static gint ett_isis_lsp_clv_partition_dis = -1;
65 static gint ett_isis_lsp_clv_prefix_neighbors = -1;
66 static gint ett_isis_lsp_clv_nlpid = -1;
67 static gint ett_isis_lsp_clv_auth = -1;
68 static gint ett_isis_lsp_clv_ipv4_int_addr = -1;
69 static gint ett_isis_lsp_clv_ip_reachability = -1;
70
71 static const char *isis_lsp_attached_bits[] = {
72         "error", "expense", "delay", "default" };
73
74 static const value_string isis_lsp_istype_vals[] = {
75         { ISIS_LSP_TYPE_UNUSED0,        "Unused 0x0 (invalid)"},
76         { ISIS_LSP_TYPE_LEVEL_1,        "Level 1 IS"},
77         { ISIS_LSP_TYPE_UNUSED2,        "Unused 0x2 (invalid)"},
78         { ISIS_LSP_TYPE_LEVEL_2,        "Level 2 IS"},
79         { 0, NULL } };
80
81 /* 
82  * Predclare dissectors for use in clv dissection.
83  */
84 static void dissect_lsp_area_address_clv(const u_char *pd, int offset, 
85                 guint length, frame_data *fd, proto_tree *tree);
86 static void dissect_lsp_l1_is_neighbors_clv(const u_char *pd, int offset, 
87                 guint length, frame_data *fd, proto_tree *tree);
88 static void dissect_lsp_l1_es_neighbors_clv(const u_char *pd, int offset, 
89                 guint length, frame_data *fd, proto_tree *tree);
90 static void dissect_lsp_l2_is_neighbors_clv(const u_char *pd, int offset, 
91                 guint length, frame_data *fd, proto_tree *tree);
92 static void dissect_lsp_partition_dis_clv(const u_char *pd, int offset, 
93                 guint length, frame_data *fd, proto_tree *tree);
94 static void dissect_lsp_prefix_neighbors_clv(const u_char *pd, int offset, 
95                 guint length, frame_data *fd, proto_tree *tree);
96 static void dissect_lsp_ip_reachability_clv(const u_char *pd, int offset,
97                 guint length, frame_data *fd, proto_tree *tree);
98 static void dissect_lsp_nlpid_clv(const u_char *pd, int offset,
99                 guint length, frame_data *fd, proto_tree *tree);
100 static void dissect_lsp_ip_int_addr_clv(const u_char *pd, int offset,
101                 guint length, frame_data *fd, proto_tree *tree);
102 static void dissect_lsp_l1_auth_clv(const u_char *pd, int offset,
103                 guint length, frame_data *fd, proto_tree *tree);
104 static void dissect_lsp_l2_auth_clv(const u_char *pd, int offset,
105                 guint length, frame_data *fd, proto_tree *tree);
106
107 static const isis_clv_handle_t clv_l1_lsp_opts[] = {
108         {
109                 ISIS_CLV_L1_LSP_AREA_ADDRESS,
110                 "Area address(es)",
111                 &ett_isis_lsp_clv_area_addr,
112                 dissect_lsp_area_address_clv
113         },
114         {
115                 ISIS_CLV_L1_LSP_IS_NEIGHBORS,
116                 "IS Neighbor(s)",
117                 &ett_isis_lsp_clv_is_neighbors,
118                 dissect_lsp_l1_is_neighbors_clv
119         },
120         {
121                 ISIS_CLV_L1_LSP_ES_NEIGHBORS,
122                 "ES Neighbor(s)",
123                 &ett_isis_lsp_clv_is_neighbors,
124                 dissect_lsp_l1_es_neighbors_clv
125         },
126         {
127                 ISIS_CLV_L1_LSP_IP_INT_REACHABLE,
128                 "IP Internal reachability",
129                 &ett_isis_lsp_clv_ip_reachability,
130                 dissect_lsp_ip_reachability_clv
131         },
132         {
133                 ISIS_CLV_L1_LSP_NLPID,
134                 "NLPID",
135                 &ett_isis_lsp_clv_nlpid,
136                 dissect_lsp_nlpid_clv
137         },
138         {
139                 ISIS_CLV_L1_LSP_IP_INTERFACE_ADDR,
140                 "IP Interface address(es)",
141                 &ett_isis_lsp_clv_ipv4_int_addr,
142                 dissect_lsp_ip_int_addr_clv
143         },
144         {
145                 ISIS_CLV_L1_LSP_AUTHENTICATION_NS,
146                 "Authentication(non-spec)",
147                 &ett_isis_lsp_clv_auth,
148                 dissect_lsp_l1_auth_clv
149         },
150         {
151                 ISIS_CLV_L1_LSP_AUTHENTICATION,
152                 "Authentication",
153                 &ett_isis_lsp_clv_auth,
154                 dissect_lsp_l1_auth_clv
155         },
156         {
157                 0,
158                 "",
159                 NULL,
160                 NULL
161         }
162 };
163
164 static const isis_clv_handle_t clv_l2_lsp_opts[] = {
165         {
166                 ISIS_CLV_L1_LSP_AREA_ADDRESS,
167                 "Area address(es)",
168                 &ett_isis_lsp_clv_area_addr,
169                 dissect_lsp_area_address_clv
170         },
171         {
172                 ISIS_CLV_L2_LSP_IS_NEIGHBORS,
173                 "IS Neighbor(s)",
174                 &ett_isis_lsp_clv_is_neighbors,
175                 dissect_lsp_l2_is_neighbors_clv
176         },
177         {
178                 ISIS_CLV_L2_LSP_PARTITION_DIS,
179                 "Parition Designated Level 2 IS",
180                 &ett_isis_lsp_clv_partition_dis,
181                 dissect_lsp_partition_dis_clv
182         },
183         {
184                 ISIS_CLV_L2_LSP_PREFIX_NEIGHBORS,
185                 "Prefix neighbors",
186                 &ett_isis_lsp_clv_prefix_neighbors,
187                 dissect_lsp_prefix_neighbors_clv
188         },
189         {
190                 ISIS_CLV_L2_LSP_IP_INT_REACHABLE,
191                 "IP Internal reachability",
192                 &ett_isis_lsp_clv_ip_reachability,
193                 dissect_lsp_ip_reachability_clv
194         },
195         {
196                 ISIS_CLV_L2_LSP_NLPID,
197                 "NLPID",
198                 &ett_isis_lsp_clv_nlpid,
199                 dissect_lsp_nlpid_clv
200         },
201         {
202                 ISIS_CLV_L2_LSP_IP_EXT_REACHABLE,
203                 "IP external reachability",
204                 &ett_isis_lsp_clv_ip_reachability,
205                 dissect_lsp_ip_reachability_clv
206         },
207         {
208                 ISIS_CLV_L2_LSP_IP_INTERFACE_ADDR,
209                 "IP Interface address(es)",
210                 &ett_isis_lsp_clv_ipv4_int_addr,
211                 dissect_lsp_ip_int_addr_clv
212         },
213         {
214                 ISIS_CLV_L2_LSP_AUTHENTICATION_NS,
215                 "Authentication(non spec)",
216                 &ett_isis_lsp_clv_auth,
217                 dissect_lsp_l2_auth_clv
218         },
219         {
220                 ISIS_CLV_L2_LSP_AUTHENTICATION,
221                 "Authentication",
222                 &ett_isis_lsp_clv_auth,
223                 dissect_lsp_l2_auth_clv
224         },
225         {
226                 0,
227                 "",
228                 NULL,
229                 NULL
230         }
231 };
232
233
234 /*
235  * Name: dissect_metric()
236  * 
237  * Description:
238  *      Display a metric prefix portion.  ISIS has the concept of multple
239  *      metric per prefix (default, delay, expense, and error).  This
240  *      routine assists other dissectors by adding a single one of
241  *      these to the display tree..  
242  *
243  *      The 8th(msbit) bit in the metric octet is the "supported" bit.  The
244  *              "default" support is required, so we support a "force_supported"
245  *              flag that tells us that it MUST be zero (zero==supported,
246  *              so it really should be a "not supported" in the boolean sense)
247  *              and to display a protocol failure accordingly.  Notably,
248  *              Cisco IOS 12(6) blows this!
249  *      The 7th bit must be zero (reserved).
250  *
251  * Input:
252  *      u_char * : packet data
253  *      int : offset into packet data where we are.
254  *      guint : length of clv we are decoding
255  *      frame_data * : frame data (complete frame)
256  *      proto_tree * : protocol display tree to fill out.  May be NULL
257  *      int : force supported.  True is the supported bit MUST be zero.
258  * 
259  * Output:
260  *      void, but we will add to proto tree if !NULL.
261  */
262 static void 
263 dissect_metric(proto_tree *tree, int offset, guint8 value, 
264                 char *pstr, int force_supported ) {
265         int s;
266
267         if ( !tree ) return;
268
269         s = ISIS_LSP_CLV_METRIC_SUPPORTED(value);
270         proto_tree_add_text ( tree, NullTVB, offset, 1, 
271                 "%s Metric: %s%s %s%d:%d", pstr,
272                 s ? "Not supported" : "Supported",
273                 (s && force_supported) ? "(but is required to be)":"",
274                 ISIS_LSP_CLV_METRIC_RESERVED(value) ? "(reserved bit != 0)":"",
275                 ISIS_LSP_CLV_METRIC_VALUE(value), value );
276 }
277         
278
279 /*
280  * Name: dissect_lsp_ip_reachabillityclv()
281  *
282  * Description:
283  *      Decode an IP reachability CLV.  This can be either internal or
284  *      external (the clv format does not change and which type we are
285  *      displaying is put there by the dispatcher).  All of these
286  *      are a metric block followed by an IP addr and mask.
287  *
288  * Input:
289  *      u_char * : packet data
290  *      int : current offset into packet data
291  *      guint : length of this clv
292  *      frame_data * : frame data
293  *      proto_tree * : proto tree to build on (may be null)
294  *
295  * Output:
296  *      void, will modify proto_tree if not null.
297  */
298 static void 
299 dissect_lsp_ip_reachability_clv(const u_char *pd, int offset, 
300                 guint length, frame_data *fd, proto_tree *tree) {
301         proto_item      *ti;
302         proto_tree      *ntree = NULL;
303         guint32         src, mask;
304
305         while ( length > 0 ) {
306                 if (length<12) {
307                         isis_dissect_unknown(offset, length, tree, fd,
308                                 "short IP reachability (%d vs 12)", length );
309                         return;
310                 }
311                 /* 
312                  * Gotta build a sub-tree for all our pieces
313                  */
314                 if ( tree ) {
315                         memcpy(&src, &pd[offset+4], 4);
316                         memcpy(&mask, &pd[offset+8], 4);
317                         ti = proto_tree_add_text ( tree, NullTVB, offset, 12, 
318                                 "IP prefix: %s (%s) : %s",
319                                 get_hostname(src), ip_to_str((guint8*)&src),
320                                 ip_to_str((guint8*)&mask) );
321                         ntree = proto_item_add_subtree(ti, 
322                                 ett_isis_lsp_clv_ip_reachability);
323                         dissect_metric ( ntree, offset, pd[offset], "Default", 
324                                 TRUE );
325                         dissect_metric ( ntree, offset + 1, pd[offset+1], 
326                                 "Delay", FALSE );
327                         dissect_metric ( ntree, offset + 2, pd[offset+2], 
328                                 "Expense",FALSE );
329                         dissect_metric ( ntree, offset + 3, pd[offset+3], 
330                                 "Error", FALSE );
331                 }
332                 offset += 12;
333                 length -= 12;
334         }
335 }
336 /*
337  * Name: dissect_lsp_nlpid_clv()
338  *
339  * Description:
340  *      Decode for a lsp packets NLPID clv.  Calls into the
341  *      clv common one.
342  *
343  * Input:
344  *      u_char * : packet data
345  *      int : current offset into packet data
346  *      guint : length of this clv
347  *      frame_data * : frame data
348  *      proto_tree * : proto tree to build on (may be null)
349  *
350  * Output:
351  *      void, will modify proto_tree if not null.
352  */
353 static void 
354 dissect_lsp_nlpid_clv(const u_char *pd, int offset, 
355                 guint length, frame_data *fd, proto_tree *tree) {
356         isis_dissect_nlpid_clv(pd, offset, length, fd, tree );
357 }
358
359 /*
360  * Name: dissect_lsp_ip_int_addr_clv()
361  *
362  * Description:
363  *      Decode for a lsp packets ip interface addr clv.  Calls into the
364  *      clv common one.
365  *
366  * Input:
367  *      u_char * : packet data
368  *      int : current offset into packet data
369  *      guint : length of this clv
370  *      frame_data * : frame data
371  *      proto_tree * : proto tree to build on (may be null)
372  *
373  * Output:
374  *      void, will modify proto_tree if not null.
375  */
376 static void 
377 dissect_lsp_ip_int_addr_clv(const u_char *pd, int offset, 
378                 guint length, frame_data *fd, proto_tree *tree) {
379         isis_dissect_ip_int_clv(pd, offset, length, fd, tree, 
380                 hf_isis_lsp_clv_ipv4_int_addr );
381 }
382
383 /*
384  * Name: dissect_lsp_L1_auth_clv()
385  *
386  * Description:
387  *      Decode for a lsp packets authenticaion clv.  Calls into the
388  *      clv common one.  An auth inside a L1 LSP is a per area password
389  *
390  * Input:
391  *      u_char * : packet data
392  *      int : current offset into packet data
393  *      guint : length of this clv
394  *      frame_data * : frame data
395  *      proto_tree * : proto tree to build on (may be null)
396  *
397  * Output:
398  *      void, will modify proto_tree if not null.
399  */
400 static void 
401 dissect_lsp_l1_auth_clv(const u_char *pd, int offset, 
402                 guint length, frame_data *fd, proto_tree *tree) {
403         isis_dissect_authentication_clv(pd, offset, length, fd, tree, 
404                 "Per area authentication" );
405 }
406
407 /*
408  * Name: dissect_lsp_L2_auth_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  *      u_char * : packet data
416  *      int : current offset into packet data
417  *      guint : length of this clv
418  *      frame_data * : frame data
419  *      proto_tree * : proto tree to build on (may be null)
420  *
421  * Output:
422  *      void, will modify proto_tree if not null.
423  */
424 static void 
425 dissect_lsp_l2_auth_clv(const u_char *pd, int offset, 
426                 guint length, frame_data *fd, proto_tree *tree) {
427         isis_dissect_authentication_clv(pd, offset, length, fd, tree, 
428                 "Per domain authentication" );
429 }
430
431 /*
432  * Name: dissect_lsp_area_address_clv()
433  *
434  * Description:
435  *      Decode for a lsp packet's area address clv.  Call into clv common
436  *      one.
437  *
438  * Input:
439  *      u_char * : packet data
440  *      int : offset into packet data where we are.
441  *      guint : length of clv we are decoding
442  *      frame_data * : frame data (complete frame)
443  *      proto_tree * : protocol display tree to fill out.  May be NULL
444  *
445  * Output:
446  *      void, but we will add to proto tree if !NULL.
447  */
448 static void 
449 dissect_lsp_area_address_clv(const u_char *pd, int offset, 
450                 guint length, frame_data *fd, proto_tree *tree) {
451         isis_dissect_area_address_clv(pd, offset, length, fd, tree );
452 }
453
454 /*
455  * Name: dissect_lsp_eis_neighbors_clv_inner()
456  *
457  * Description:
458  *      Real work horse for showing neighbors.  This means we decode the
459  *      first octet as either virtual/!virtual (if show_virtual param is
460  *      set), or as a must == 0 reserved value.
461  *
462  *      Once past that, we decode n neighbor elements.  Each neighbor
463  *      is comprised of a metric block (is dissect_metric) and the
464  *      addresses.
465  *
466  * Input:
467  *      u_char * : packet data
468  *      int : offset into packet data where we are.
469  *      guint : length of clv we are decoding
470  *      frame_data * : frame data (complete frame)
471  *      proto_tree * : protocol display tree to fill out.  May be NULL
472  *      int : set to decode first octet as virtual vs reserved == 0
473  *      int : set to indicate EIS instead of IS (6 octet per addr instead of 7)
474  *
475  * Output:
476  *      void, but we will add to proto tree if !NULL.
477  */
478 static void 
479 dissect_lsp_eis_neighbors_clv_inner(const u_char *pd, int offset, 
480                 guint length, frame_data *fd, proto_tree *tree,
481                 int show_virtual, int is_eis) {
482         proto_item      *ti;
483         proto_tree      *ntree = NULL;
484         int             tlen;
485
486         if (is_eis) {
487                 tlen = 10;
488         } else {
489                 tlen = 11;
490                 if ( tree ) {
491                         if ( show_virtual ) {
492                                 /* virtual path flag */
493                                 proto_tree_add_text ( tree, NullTVB, offset, 1, 
494                                    &pd[offset] ? "IsNotVirtual" : "IsVirtual" );
495                         } else {
496                                 proto_tree_add_text ( tree, NullTVB, offset, 1, 
497                                         "Reserved value 0x%02x, must == 0",
498                                         pd[offset]  );
499                         }
500                 }
501                 offset++;
502                 length--;
503                         
504         }
505
506         while ( length > 0 ) {
507                 if (length<tlen) {
508                         isis_dissect_unknown(offset, length, tree, fd,
509                                 "short E/IS reachability (%d vs %d)", length,
510                                 tlen );
511                         return;
512                 }
513                 /* 
514                  * Gotta build a sub-tree for all our pieces
515                  */
516                 if ( tree ) {
517                         if ( is_eis ) {
518                                 ti = proto_tree_add_text ( tree, NullTVB, offset, 11, 
519                                         "ES Neighbor: %s",
520                                         print_system_id( pd + offset + 4, 6 ) );
521                         } else {
522                                 ti = proto_tree_add_text ( tree, NullTVB, offset, 11, 
523                                         "IS Neighbor:  %s",
524                print_system_id( pd + offset + 4, 6 ) );
525                         }
526                         ntree = proto_item_add_subtree(ti, 
527                                 ett_isis_lsp_clv_is_neighbors);
528                         dissect_metric ( ntree, offset, pd[offset], "Default", 
529                                 TRUE );
530                         dissect_metric ( ntree, offset + 1, pd[offset+1], 
531                                 "Delay", FALSE );
532                         dissect_metric ( ntree, offset + 2, pd[offset+2], 
533                                 "Expense",FALSE );
534                         dissect_metric ( ntree, offset + 3, pd[offset+3], 
535                                 "Error", FALSE );
536                 }
537                 offset += tlen;
538                 length -= tlen;
539         }
540 }
541
542 /*
543  * Name: dissect_lsp_l1_is_neighbors_clv()
544  *
545  * Description:
546  *      Dispatch a l1 intermediate system neighbor by calling
547  *      the inner function with show virtual set to TRUE and is es set to FALSE.
548  *
549  * Input:
550  *      u_char * : packet data
551  *      int : offset into packet data where we are.
552  *      guint : length of clv we are decoding
553  *      frame_data * : frame data (complete frame)
554  *      proto_tree * : protocol display tree to fill out.  May be NULL
555  *
556  * Output:
557  *      void, but we will add to proto tree if !NULL.
558  */
559 static void 
560 dissect_lsp_l1_is_neighbors_clv(const u_char *pd, int offset, 
561                 guint length, frame_data *fd, proto_tree *tree) {
562         dissect_lsp_eis_neighbors_clv_inner( pd, offset, length, fd, tree,TRUE,
563                 FALSE );
564 }
565
566 /*
567  * Name: dissect_lsp_l1_es_neighbors_clv()
568  *
569  * Description:
570  *      Dispatch a l1 end or intermediate system neighbor by calling
571  *      the inner function with show virtual set to TRUE and es set to TRUE.
572  *
573  * Input:
574  *      u_char * : packet data
575  *      int : offset into packet data where we are.
576  *      guint : length of clv we are decoding
577  *      frame_data * : frame data (complete frame)
578  *      proto_tree * : protocol display tree to fill out.  May be NULL
579  *
580  * Output:
581  *      void, but we will add to proto tree if !NULL.
582  */
583 static void 
584 dissect_lsp_l1_es_neighbors_clv(const u_char *pd, int offset, 
585                 guint length, frame_data *fd, proto_tree *tree) {
586         dissect_lsp_eis_neighbors_clv_inner( pd, offset, length, fd, tree,
587                 TRUE, TRUE);
588 }
589
590 /*
591  * Name: dissect_lsp_l2_is_neighbors_clv()
592  *
593  * Description:
594  *      Dispatch a l2 intermediate system neighbor by calling
595  *      the inner function with show virtual set to FALSE, and is es set
596  *      to FALSE
597  *
598  * Input:
599  *      u_char * : packet data
600  *      int : offset into packet data where we are.
601  *      guint : length of clv we are decoding
602  *      frame_data * : frame data (complete frame)
603  *      proto_tree * : protocol display tree to fill out.  May be NULL
604  *
605  * Output:
606  *      void, but we will add to proto tree if !NULL.
607  */
608 static void 
609 dissect_lsp_l2_is_neighbors_clv(const u_char *pd, int offset, 
610                 guint length, frame_data *fd, proto_tree *tree) {
611         dissect_lsp_eis_neighbors_clv_inner(pd,offset, length, fd, tree, FALSE,
612                 FALSE);
613 }
614
615 /*
616  * Name: dissect_lsp_partition_dis_clv()
617  *
618  * Description:
619  *      This CLV is used to indicate which system is the designated
620  *      IS for partition repair.  This means just putting out the 6 octet
621  *      IS.
622  *
623  * Input:
624  *      u_char * : packet data
625  *      int : offset into packet data where we are.
626  *      guint : length of clv we are decoding
627  *      frame_data * : frame data (complete frame)
628  *      proto_tree * : protocol display tree to fill out.  May be NULL
629  *
630  * Output:
631  *      void, but we will add to proto tree if !NULL.
632  */
633 static void 
634 dissect_lsp_partition_dis_clv(const u_char *pd, int offset, 
635                 guint length, frame_data *fd, proto_tree *tree) {
636
637         if ( length < 6 ) {
638                 isis_dissect_unknown(offset, length, tree, fd,
639                                 "short lsp parition DIS(%d vs 6)", length );
640                 return;
641         }
642         /* 
643          * Gotta build a sub-tree for all our pieces
644          */
645         if ( tree ) {
646                 proto_tree_add_text ( tree, NullTVB, offset+4, 6, 
647                         "Partition designated L2 IS: %s",
648                         print_system_id( pd + offset, 6 ) );
649         }
650         length -= 6;
651         offset +=  6;
652         if ( length > 0 ){
653                 isis_dissect_unknown(offset, length, tree, fd,
654                                 "Long lsp parition DIS, %d left over", length );
655                 return;
656         }
657 }
658
659 /*
660  * Name: dissect_lsp_prefix_neighbors_clv()
661  *
662  * Description:
663  *      The prefix CLV describes what other (OSI) networks we can reach
664  *      and what their cost is.  It is built from a metric block
665  *      (see dissect_metric) followed by n addresses.
666  *
667  * Input:
668  *      u_char * : packet data
669  *      int : offset into packet data where we are.
670  *      guint : length of clv we are decoding
671  *      frame_data * : frame data (complete frame)
672  *      proto_tree * : protocol display tree to fill out.  May be NULL
673  *
674  * Output:
675  *      void, but we will add to proto tree if !NULL.
676  */
677 static void 
678 dissect_lsp_prefix_neighbors_clv(const u_char *pd, int offset, 
679                 guint length, frame_data *fd, proto_tree *tree) {
680         char *sbuf;
681         int mylen;
682
683         if ( length < 4 ) {
684                 isis_dissect_unknown(offset, length, tree, fd,
685                         "Short lsp prefix neighbors (%d vs 4)", length );
686                 return;
687         }
688         if ( tree ) {
689                 dissect_metric ( tree, offset, pd[offset], "Default", TRUE );
690                 dissect_metric ( tree, offset + 1, pd[offset+1], 
691                         "Delay", FALSE );
692                 dissect_metric ( tree, offset + 2, pd[offset+2], 
693                         "Expense", FALSE );
694                 dissect_metric ( tree, offset + 3, pd[offset+3], 
695                         "Error", FALSE );
696         }
697         offset += 4;
698         length -= 4;
699         while ( length > 0 ) {
700                 mylen = pd[offset];
701                 length--;
702                 if (length<=0) {
703                         isis_dissect_unknown(offset, length, tree, fd,
704                                 "Zero payload space after length in prefix neighbor" );
705                         return;
706                 }
707                 if ( mylen > length) {
708                         isis_dissect_unknown(offset, length, tree, fd,
709                                 "Interal length of prefix neighbor too long (%d vs %d)", 
710                                 mylen, length );
711                         return;
712                 }
713
714                 /* 
715                  * Lets turn the area address into "standard" 0000.0000.etc
716                  * format string.  
717                  */
718                 sbuf =  print_area( pd + offset + 1, mylen );
719                 /* and spit it out */
720                 if ( tree ) {
721                         proto_tree_add_text ( tree, NullTVB, offset, mylen + 1, 
722                                 "Area address (%d): %s", mylen, sbuf );
723                 }
724                 offset += mylen + 1;
725                 length -= mylen;        /* length already adjusted for len fld*/
726         }
727 }
728
729 /*
730  * Name: isis_lsp_decode_lsp_id()
731  *
732  * Description: 
733  *      Display a LSP id into the display tree.
734  *
735  * Input:
736  *      char * : title string
737  *      proto_tree * : tree to display into. REQUIRED
738  *      int : offset into packet data where we are.
739  *      isis_lsp_id_t * : id to display.
740  *
741  * Output:
742  *      void, but we will add to proto tree
743  */
744 void
745 isis_lsp_decode_lsp_id(char *tstr, proto_tree *tree, int offset, 
746                 isis_lsp_id_t *id ) {
747         proto_tree_add_text(tree, NullTVB, offset, 8, 
748                 "%s: %s.%02x-%02x", tstr,
749                         print_system_id( id->source_id, 6 ),
750                         id->psuodonode_id,
751                         id->lsp_number );
752 }
753
754 /*
755  * Name: isis_dissect_isis_lsp()
756  *
757  * Description:
758  *      Print out the LSP part of the main header and then call the CLV
759  *      de-mangler with the right list of valid CLVs.
760  *
761  * Input:
762  *      u_char * : packet data
763  *      int : offset into packet data where we are.
764  *      guint : length of clv we are decoding
765  *      frame_data * : frame data (complete frame)
766  *      proto_tree * : protocol display tree to fill out.  May be NULL
767  *
768  * Output:
769  *      void, but we will add to proto tree if !NULL.
770  */
771 void 
772 isis_dissect_isis_lsp(int lsp_type, int header_length, 
773                 const u_char *pd, int offset, frame_data *fd, proto_tree *tree){
774         isis_lsp_t      *ilp;
775         proto_item      *ti;
776         proto_tree      *lsp_tree = NULL;
777         int             hlen;
778         char            sbuf[128];
779         int             inx, q, some, value, len;
780
781         hlen = sizeof(*ilp);
782
783         if (!BYTES_ARE_IN_FRAME(offset, hlen)) {
784                 isis_dissect_unknown(offset, hlen, tree, fd,
785                         "not enough capture data for header (%d vs %d)",
786                         hlen, END_OF_FRAME);
787                 return;
788         }
789         
790         ilp = (isis_lsp_t *) &pd[offset];
791
792         if (tree) {
793                 ti = proto_tree_add_item(tree, proto_isis_lsp, NullTVB,
794                         offset, END_OF_FRAME, FALSE);
795                 lsp_tree = proto_item_add_subtree(ti, ett_isis_lsp);
796                 proto_tree_add_uint(lsp_tree, hf_isis_lsp_pdu_length, NullTVB,
797                         offset, 2, pntohs(&ilp->isis_lsp_pdu_length));
798                 proto_tree_add_uint(lsp_tree, hf_isis_lsp_remaining_life, NullTVB,
799                         offset + 2, 2, pntohs(&ilp->isis_lsp_remaining_life));
800                 isis_lsp_decode_lsp_id("LSP ID", lsp_tree, offset + 4, 
801                         &ilp->isis_lsp_id );
802                 proto_tree_add_uint(lsp_tree, hf_isis_lsp_sequence_number, NullTVB,
803                         offset + 12, 4, 
804                         pntohl(&ilp->isis_lsp_sequence_number));
805
806                 /* XXX -> we could validate the cksum here! */
807                 proto_tree_add_uint(lsp_tree, hf_isis_lsp_checksum, NullTVB,
808                         offset + 16, 2, pntohs(&ilp->isis_lsp_checksum));
809
810                 /*
811                  * We need to build our type block values. 
812                  */
813                 sbuf[0] = 0;
814                 some = 0;
815                 value = ISIS_LSP_ATT(ilp->isis_lsp_type_block);
816                 inx = 0;
817                 for ( q = (1<<ISIS_LSP_ATT_SHIFT); q > 0; q = q >> 1 ){
818                         if (q & value) { 
819                                 if (some++) {
820                                         strcat(sbuf, ", ");
821                                 }
822                                 strcat ( sbuf, isis_lsp_attached_bits[inx] );
823                         }
824                         inx++;
825                 }
826                 if (!some) { 
827                         strcat ( sbuf, "<none set!>" );
828                 }
829                 proto_tree_add_text(lsp_tree, NullTVB, offset + 18, 1, 
830                         "Type block(0x%02x): P:%d, Supported metric(s): %s, OL:%d, istype:%s",
831                         ilp->isis_lsp_type_block, 
832                         ISIS_LSP_PARTITION(ilp->isis_lsp_type_block) ? 1 : 0,
833                         sbuf,
834                         ISIS_LSP_HIPPITY(ilp->isis_lsp_type_block) ? 1 : 0,
835                         val_to_str(ISIS_LSP_IS_TYPE(ilp->isis_lsp_type_block),
836                                 isis_lsp_istype_vals, "Unknown (0x%x)")
837                         );
838
839         }
840
841         offset += hlen;
842         len = pntohs(&ilp->isis_lsp_pdu_length);
843         len -= header_length;
844         if (len < 0) {
845                 isis_dissect_unknown(offset, header_length, tree, fd,
846                         "packet header length %d went beyond packet",
847                          header_length );
848                 return;
849         }
850         /*
851          * Now, we need to decode our CLVs.  We need to pass in
852          * our list of valid ones!
853          */
854         if (lsp_type == ISIS_TYPE_L1_LSP){
855                 isis_dissect_clvs ( clv_l1_lsp_opts, len, pd, offset, fd, 
856                         lsp_tree, ett_isis_lsp_clv_unknown );
857         } else {
858                 isis_dissect_clvs ( clv_l2_lsp_opts, len, pd, offset, fd, 
859                         lsp_tree, ett_isis_lsp_clv_unknown );
860         }
861 }
862 /*
863  * Name: proto_register_isis_lsp()
864  *
865  * Description: 
866  *      Register our protocol sub-sets with protocol manager.
867  *      NOTE: this procedure is autolinked by the makefile process that
868  *              builds register.c
869  *
870  * Input:
871  *      u_char * : packet data
872  *      int : offset into packet data where we are.
873  *      guint : length of clv we are decoding
874  *      frame_data * : frame data (complete frame)
875  *      proto_tree * : protocol display tree to fill out.  May be NULL
876  *
877  * Output:
878  *      void, but we will add to proto tree if !NULL.
879  */
880 void 
881 proto_register_isis_lsp(void) {
882         static hf_register_info hf[] = {
883                 { &hf_isis_lsp_pdu_length,
884                 { "PDU length",         "isis_lsp.pdu_length", FT_UINT16, 
885                   BASE_DEC, NULL, 0x0, "" }},
886
887                 { &hf_isis_lsp_remaining_life,
888                 { "Remaining life",     "isis_lsp.remaining_life", FT_UINT16, 
889                   BASE_DEC, NULL, 0x0, "" }},
890
891                 { &hf_isis_lsp_sequence_number,
892                 { "Sequence number",           "isis_lsp.sequence_number", 
893                   FT_UINT32, BASE_HEX, NULL, 0x0, "" }},
894
895                 { &hf_isis_lsp_checksum,
896                 { "Checksum",           "isis_lsp.checksum",FT_UINT16, 
897                   BASE_HEX, NULL, 0x0, "" }},
898
899                 { &hf_isis_lsp_clv_ipv4_int_addr,
900                 { "IPv4 interface address: ", "isis_lsp.clv_ipv4_int_addr", FT_IPv4,
901                    BASE_NONE, NULL, 0x0, "" }},
902         };
903         static gint *ett[] = {
904                 &ett_isis_lsp,
905                 &ett_isis_lsp_clv_area_addr,
906                 &ett_isis_lsp_clv_is_neighbors,
907                 &ett_isis_lsp_clv_unknown,
908                 &ett_isis_lsp_clv_partition_dis,
909                 &ett_isis_lsp_clv_prefix_neighbors,
910                 &ett_isis_lsp_clv_auth,
911                 &ett_isis_lsp_clv_nlpid,
912                 &ett_isis_lsp_clv_ipv4_int_addr,
913                 &ett_isis_lsp_clv_ip_reachability,
914         };
915
916         proto_isis_lsp = proto_register_protocol( PROTO_STRING_LSP, "isis_lsp");
917         proto_register_field_array(proto_isis_lsp, hf, array_length(hf));
918         proto_register_subtree_array(ett, array_length(ett));
919 }