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