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