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