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