From Joerg Mayer: explicitly fill in all members of a
[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.17 2001/06/18 02:17:47 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 "epan/ipv4.h"
46 #include "packet.h"
47 #include "packet-osi.h"
48 #include "packet-ipv6.h"
49 #include "packet-isis.h"
50 #include "packet-isis-clv.h"
51 #include "packet-isis-lsp.h"
52 #include "resolv.h"
53
54 /* lsp packets */
55 static int proto_isis_lsp = -1;
56 static int hf_isis_lsp_pdu_length = -1;
57 static int hf_isis_lsp_remaining_life = -1;
58 static int hf_isis_lsp_sequence_number = -1;
59 static int hf_isis_lsp_checksum = -1;
60 static int hf_isis_lsp_clv_ipv4_int_addr = -1;
61 static int hf_isis_lsp_clv_ipv6_int_addr = -1;
62 static int hf_isis_lsp_clv_te_router_id = -1;
63
64 static gint ett_isis_lsp = -1;
65 static gint ett_isis_lsp_clv_area_addr = -1;
66 static gint ett_isis_lsp_clv_is_neighbors = -1;
67 static gint ett_isis_lsp_clv_ext_is_reachability = -1; /* CLV 22 */
68         static gint ett_isis_lsp_part_of_clv_ext_is_reachability = -1;
69         static gint ett_isis_lsp_subclv_admin_group = -1;
70         static gint ett_isis_lsp_subclv_unrsv_bw = -1;
71 static gint ett_isis_lsp_clv_unknown = -1;
72 static gint ett_isis_lsp_clv_partition_dis = -1;
73 static gint ett_isis_lsp_clv_prefix_neighbors = -1;
74 static gint ett_isis_lsp_clv_nlpid = -1;
75 static gint ett_isis_lsp_clv_hostname = -1;
76 static gint ett_isis_lsp_clv_te_router_id = -1;
77 static gint ett_isis_lsp_clv_auth = -1;
78 static gint ett_isis_lsp_clv_ipv4_int_addr = -1;
79 static gint ett_isis_lsp_clv_ipv6_int_addr = -1; /* CLV 232 */
80 static gint ett_isis_lsp_clv_ip_reachability = -1;
81 static gint ett_isis_lsp_clv_ext_ip_reachability = -1; /* CLV 135 */
82         static gint ett_isis_lsp_part_of_clv_ext_ip_reachability = -1;
83 static gint ett_isis_lsp_clv_ipv6_reachability = -1; /* CLV 236 */
84         static gint ett_isis_lsp_part_of_clv_ipv6_reachability = -1;
85
86 static const char *isis_lsp_attached_bits[] = {
87         "error", "expense", "delay", "default" };
88
89 static const value_string isis_lsp_istype_vals[] = {
90         { ISIS_LSP_TYPE_UNUSED0,        "Unused 0x0 (invalid)"},
91         { ISIS_LSP_TYPE_LEVEL_1,        "Level 1 IS"},
92         { ISIS_LSP_TYPE_UNUSED2,        "Unused 0x2 (invalid)"},
93         { ISIS_LSP_TYPE_LEVEL_2,        "Level 2 IS"},
94         { 0, NULL } };
95
96 /* 
97  * Predclare dissectors for use in clv dissection.
98  */
99 static void dissect_lsp_area_address_clv(const u_char *pd, int offset, 
100                 guint length, int id_length, frame_data *fd, proto_tree *tree);
101 static void dissect_lsp_l1_is_neighbors_clv(const u_char *pd, int offset, 
102                 guint length, int id_length, frame_data *fd, proto_tree *tree);
103 static void dissect_lsp_l1_es_neighbors_clv(const u_char *pd, int offset, 
104                 guint length, int id_length, frame_data *fd, proto_tree *tree);
105 static void dissect_lsp_l2_is_neighbors_clv(const u_char *pd, int offset, 
106                 guint length, int id_length, frame_data *fd, proto_tree *tree);
107 static void dissect_lsp_ext_is_reachability_clv(const u_char *pd, int offset, 
108                 guint length, int id_length, frame_data *fd, proto_tree *tree);
109 static void dissect_lsp_partition_dis_clv(const u_char *pd, int offset, 
110                 guint length, int id_length, frame_data *fd, proto_tree *tree);
111 static void dissect_lsp_prefix_neighbors_clv(const u_char *pd, int offset, 
112                 guint length, int id_length, frame_data *fd, proto_tree *tree);
113 static void dissect_lsp_ip_reachability_clv(const u_char *pd, int offset,
114                 guint length, int id_length, frame_data *fd, proto_tree *tree);
115 static void dissect_lsp_ext_ip_reachability_clv(const u_char *pd, int offset,
116                 guint length, int id_length, frame_data *fd, proto_tree *tree);
117 static void dissect_lsp_ipv6_reachability_clv(const u_char *pd, int offset,
118                 guint length, int id_length, frame_data *fd, proto_tree *tree);
119 static void dissect_lsp_nlpid_clv(const u_char *pd, int offset,
120                 guint length, int id_length, frame_data *fd, proto_tree *tree);
121 static void dissect_lsp_hostname_clv(const u_char *pd, int offset,
122                 guint length, int id_length, frame_data *fd, proto_tree *tree);
123 static void dissect_lsp_te_router_id_clv(const u_char *pd, int offset,
124                 guint length, int id_length, frame_data *fd, proto_tree *tree);
125 static void dissect_lsp_ip_int_addr_clv(const u_char *pd, int offset,
126                 guint length, int id_length, frame_data *fd, proto_tree *tree);
127 static void dissect_lsp_ipv6_int_addr_clv(const u_char *pd, int offset,
128                 guint length, int id_length, frame_data *fd, proto_tree *tree);
129 static void dissect_lsp_l1_auth_clv(const u_char *pd, int offset,
130                 guint length, int id_length, frame_data *fd, proto_tree *tree);
131 static void dissect_lsp_l2_auth_clv(const u_char *pd, int offset,
132                 guint length, int id_length, frame_data *fd, proto_tree *tree);
133
134 static const isis_clv_handle_t clv_l1_lsp_opts[] = {
135         {
136                 ISIS_CLV_L1_LSP_AREA_ADDRESS,
137                 "Area address(es)",
138                 &ett_isis_lsp_clv_area_addr,
139                 dissect_lsp_area_address_clv
140         },
141         {
142                 ISIS_CLV_L1_LSP_IS_NEIGHBORS,
143                 "IS Neighbor(s)",
144                 &ett_isis_lsp_clv_is_neighbors,
145                 dissect_lsp_l1_is_neighbors_clv
146         },
147         {
148                 ISIS_CLV_L1_LSP_ES_NEIGHBORS,
149                 "ES Neighbor(s)",
150                 &ett_isis_lsp_clv_is_neighbors,
151                 dissect_lsp_l1_es_neighbors_clv
152         },
153         {
154                 ISIS_CLV_L1_LSP_EXT_IS_REACHABLE,
155                 "Extended IS reachability",
156                 &ett_isis_lsp_clv_ext_is_reachability,
157                 dissect_lsp_ext_is_reachability_clv
158         },
159         {
160                 ISIS_CLV_L1_LSP_IP_INT_REACHABLE,
161                 "IP Internal reachability",
162                 &ett_isis_lsp_clv_ip_reachability,
163                 dissect_lsp_ip_reachability_clv
164         },
165         {
166                 ISIS_CLV_L1_LSP_IP_EXT_REACHABLE,
167                 "IP External reachability",
168                 &ett_isis_lsp_clv_ip_reachability,
169                 dissect_lsp_ip_reachability_clv
170         },
171         {
172                 ISIS_CLV_L1_LSP_EXT_IP_REACHABLE,
173                 "Extended IP Reachability",
174                 &ett_isis_lsp_clv_ext_ip_reachability,
175                 dissect_lsp_ext_ip_reachability_clv
176         },
177         {
178                 ISIS_CLV_L1_LSP_IPv6_REACHABLE,
179                 "IPv6 reachability",
180                 &ett_isis_lsp_clv_ipv6_reachability,
181                 dissect_lsp_ipv6_reachability_clv
182         },
183         {
184                 ISIS_CLV_L1_LSP_NLPID,
185                 "Protocols supported",
186                 &ett_isis_lsp_clv_nlpid,
187                 dissect_lsp_nlpid_clv
188         },
189         {
190                 ISIS_CLV_L1_LSP_HOSTNAME,
191                 "Hostname",
192                 &ett_isis_lsp_clv_hostname,
193                 dissect_lsp_hostname_clv
194         },
195         {
196                 ISIS_CLV_L1_LSP_TE_ROUTER_ID,
197                 "Traffic Engineering Router ID",
198                 &ett_isis_lsp_clv_te_router_id,
199                 dissect_lsp_te_router_id_clv
200         },
201         {
202                 ISIS_CLV_L1_LSP_IP_INTERFACE_ADDR,
203                 "IP Interface address(es)",
204                 &ett_isis_lsp_clv_ipv4_int_addr,
205                 dissect_lsp_ip_int_addr_clv
206         },
207         {
208                 ISIS_CLV_L1_LSP_IPv6_INTERFACE_ADDR,
209                 "IPv6 Interface address(es)",
210                 &ett_isis_lsp_clv_ipv6_int_addr,
211                 dissect_lsp_ipv6_int_addr_clv
212         },
213         {
214                 ISIS_CLV_L1_LSP_AUTHENTICATION_NS,
215                 "Authentication(non-spec)",
216                 &ett_isis_lsp_clv_auth,
217                 dissect_lsp_l1_auth_clv
218         },
219         {
220                 ISIS_CLV_L1_LSP_AUTHENTICATION,
221                 "Authentication",
222                 &ett_isis_lsp_clv_auth,
223                 dissect_lsp_l1_auth_clv
224         },
225         {
226                 0,
227                 "",
228                 NULL,
229                 NULL
230         }
231 };
232
233 static const isis_clv_handle_t clv_l2_lsp_opts[] = {
234         {
235                 ISIS_CLV_L1_LSP_AREA_ADDRESS,
236                 "Area address(es)",
237                 &ett_isis_lsp_clv_area_addr,
238                 dissect_lsp_area_address_clv
239         },
240         {
241                 ISIS_CLV_L2_LSP_IS_NEIGHBORS,
242                 "IS Neighbor(s)",
243                 &ett_isis_lsp_clv_is_neighbors,
244                 dissect_lsp_l2_is_neighbors_clv
245         },
246         {
247                 ISIS_CLV_L2_LSP_EXT_IS_REACHABLE,
248                 "Extended IS reachability",
249                 &ett_isis_lsp_clv_ext_is_reachability,
250                 dissect_lsp_ext_is_reachability_clv
251         },
252         {
253                 ISIS_CLV_L2_LSP_PARTITION_DIS,
254                 "Parition Designated Level 2 IS",
255                 &ett_isis_lsp_clv_partition_dis,
256                 dissect_lsp_partition_dis_clv
257         },
258         {
259                 ISIS_CLV_L2_LSP_PREFIX_NEIGHBORS,
260                 "Prefix neighbors",
261                 &ett_isis_lsp_clv_prefix_neighbors,
262                 dissect_lsp_prefix_neighbors_clv
263         },
264         {
265                 ISIS_CLV_L2_LSP_IP_INT_REACHABLE,
266                 "IP Internal reachability",
267                 &ett_isis_lsp_clv_ip_reachability,
268                 dissect_lsp_ip_reachability_clv
269         },
270         {
271                 ISIS_CLV_L2_LSP_IP_EXT_REACHABLE,
272                 "IP External reachability",
273                 &ett_isis_lsp_clv_ip_reachability,
274                 dissect_lsp_ip_reachability_clv
275         },
276         {
277                 ISIS_CLV_L2_LSP_NLPID,
278                 "Protocols supported",
279                 &ett_isis_lsp_clv_nlpid,
280                 dissect_lsp_nlpid_clv
281         },
282         {
283                 ISIS_CLV_L2_LSP_HOSTNAME,
284                 "Hostname",
285                 &ett_isis_lsp_clv_hostname,
286                 dissect_lsp_hostname_clv
287         },
288         {
289                 ISIS_CLV_L2_LSP_TE_ROUTER_ID,
290                 "Traffic Engineering Router ID",
291                 &ett_isis_lsp_clv_te_router_id,
292                 dissect_lsp_te_router_id_clv
293         },
294         {
295                 ISIS_CLV_L2_LSP_EXT_IP_REACHABLE,
296                 "Extended IP Reachability",
297                 &ett_isis_lsp_clv_ext_ip_reachability,
298                 dissect_lsp_ext_ip_reachability_clv
299         },
300         {
301                 ISIS_CLV_L2_LSP_IPv6_REACHABLE,
302                 "IPv6 reachability",
303                 &ett_isis_lsp_clv_ipv6_reachability,
304                 dissect_lsp_ipv6_reachability_clv
305         },
306         {
307                 ISIS_CLV_L2_LSP_IP_INTERFACE_ADDR,
308                 "IP Interface address(es)",
309                 &ett_isis_lsp_clv_ipv4_int_addr,
310                 dissect_lsp_ip_int_addr_clv
311         },
312         {
313                 ISIS_CLV_L2_LSP_IPv6_INTERFACE_ADDR,
314                 "IPv6 Interface address(es)",
315                 &ett_isis_lsp_clv_ipv6_int_addr,
316                 dissect_lsp_ipv6_int_addr_clv
317         },
318         {
319                 ISIS_CLV_L2_LSP_AUTHENTICATION_NS,
320                 "Authentication(non spec)",
321                 &ett_isis_lsp_clv_auth,
322                 dissect_lsp_l2_auth_clv
323         },
324         {
325                 ISIS_CLV_L2_LSP_AUTHENTICATION,
326                 "Authentication",
327                 &ett_isis_lsp_clv_auth,
328                 dissect_lsp_l2_auth_clv
329         },
330         {
331                 0,
332                 "",
333                 NULL,
334                 NULL
335         }
336 };
337
338
339 /*
340  * Name: dissect_metric()
341  * 
342  * Description:
343  *      Display a metric prefix portion.  ISIS has the concept of multple
344  *      metric per prefix (default, delay, expense, and error).  This
345  *      routine assists other dissectors by adding a single one of
346  *      these to the display tree..  
347  *
348  *      The 8th(msbit) bit in the metric octet is the "supported" bit.  The
349  *              "default" support is required, so we support a "force_supported"
350  *              flag that tells us that it MUST be zero (zero==supported,
351  *              so it really should be a "not supported" in the boolean sense)
352  *              and to display a protocol failure accordingly.  Notably,
353  *              Cisco IOS 12(6) blows this!
354  *      The 7th bit must be zero (reserved).
355  *
356  * Input:
357  *      u_char * : packet data
358  *      int : offset into packet data where we are.
359  *      guint : length of clv we are decoding
360  *      frame_data * : frame data (complete frame)
361  *      proto_tree * : protocol display tree to fill out.  May be NULL
362  *      int : force supported.  True is the supported bit MUST be zero.
363  * 
364  * Output:
365  *      void, but we will add to proto tree if !NULL.
366  */
367 static void 
368 dissect_metric(proto_tree *tree, int offset, guint8 value, 
369                 char *pstr, int force_supported ) {
370         int s;
371
372         if ( !tree ) return;
373
374         s = ISIS_LSP_CLV_METRIC_SUPPORTED(value);
375         proto_tree_add_text ( tree, NullTVB, offset, 1, 
376                 "%s Metric: %s%s %s%d:%d", pstr,
377                 s ? "Not supported" : "Supported",
378                 (s && force_supported) ? "(but is required to be)":"",
379                 ISIS_LSP_CLV_METRIC_RESERVED(value) ? "(reserved bit != 0)":"",
380                 ISIS_LSP_CLV_METRIC_VALUE(value), value );
381 }
382         
383
384 /*
385  * Name: dissect_lsp_ip_reachabillity_clv()
386  *
387  * Description:
388  *      Decode an IP reachability CLV.  This can be either internal or
389  *      external (the clv format does not change and which type we are
390  *      displaying is put there by the dispatcher).  All of these
391  *      are a metric block followed by an IP addr and mask.
392  *
393  * Input:
394  *      u_char * : packet data
395  *      int : current offset into packet data
396  *      guint : length of this clv
397  *      int : length of IDs in packet.
398  *      frame_data * : frame data
399  *      proto_tree * : proto tree to build on (may be null)
400  *
401  * Output:
402  *      void, will modify proto_tree if not null.
403  */
404 static void 
405 dissect_lsp_ip_reachability_clv(const u_char *pd, int offset, 
406                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
407         proto_item      *ti;
408         proto_tree      *ntree = NULL;
409         guint32         src, mask, prefix_len;
410
411         guint32 bitmasks[33] = {
412           0x00000000,
413           0x00000008, 0x0000000c, 0x0000000e, 0x0000000f,
414           0x000000f8, 0x000000fc, 0x000000fe, 0x000000ff,
415           0x000008ff, 0x00000cff, 0x00000eff, 0x00000fff,
416           0x0000f8ff, 0x0000fcff, 0x0000feff, 0x0000ffff,
417           0x0008ffff, 0x000cffff, 0x000effff, 0x000fffff,
418           0x00f8ffff, 0x00fcffff, 0x00feffff, 0x00ffffff,
419           0x08ffffff, 0x0cffffff, 0x0effffff, 0x0fffffff,
420           0xf8ffffff, 0xfcffffff, 0xfeffffff, 0xffffffff
421         };
422
423           
424         while ( length > 0 ) {
425                 if (length<12) {
426                         isis_dissect_unknown(offset, length, tree, fd,
427                                 "short IP reachability (%d vs 12)", length );
428                         return;
429                 }
430                 /* 
431                  * Gotta build a sub-tree for all our pieces
432                  */
433                 if ( tree ) {
434                         memcpy(&src, &pd[offset+4], 4);
435                         memcpy(&mask, &pd[offset+8], 4);
436
437                         /* find out if the mask matches one of 33 possible prefix lengths */
438
439                         prefix_len=0;
440
441                         while(prefix_len<=33) {
442                           if (bitmasks[prefix_len++]==mask) {
443                             prefix_len--;
444                             break;
445                           }
446                         }
447                         
448                         /* 34 indicates no match -> must be a discontiguous netmask
449                            lets dump the mask, otherwise print the prefix_len */
450
451                         if(prefix_len==34) {
452                           ti = proto_tree_add_text ( tree, NullTVB, offset, 12,
453                                 "IPv4 prefix: %s mask %s",
454                                 ip_to_str((guint8*)&src),
455                                 ip_to_str((guint8*)&mask));
456                         } else {
457                           ti = proto_tree_add_text ( tree, NullTVB, offset, 12, 
458                                 "IPv4 prefix: %s/%d",
459                                 ip_to_str((guint8*)&src),
460                                 prefix_len );
461                         };
462
463                         ntree = proto_item_add_subtree(ti, 
464                                 ett_isis_lsp_clv_ip_reachability);
465
466                         proto_tree_add_text (ntree, NullTVB, offset, 1,
467                                 "Default Metric: %d, %s, Distribution: %s",
468                                 ISIS_LSP_CLV_METRIC_VALUE(pd[offset]),
469                                 ISIS_LSP_CLV_METRIC_IE(pd[offset]) ? "External" : "Internal",
470                                 ISIS_LSP_CLV_METRIC_UPDOWN(pd[offset]) ? "down" : "up");
471
472
473                         if (ISIS_LSP_CLV_METRIC_SUPPORTED(pd[offset+1])) {
474                           proto_tree_add_text (ntree, NullTVB, offset+1, 1, "Delay Metric:   Not supported");
475                                                } else {
476                           proto_tree_add_text (ntree, NullTVB, offset+1, 1, "Delay Metric:   %d, %s",
477                                                ISIS_LSP_CLV_METRIC_VALUE(pd[offset+1]),
478                                                ISIS_LSP_CLV_METRIC_IE(pd[offset+1]) ? "External" : "Internal");
479                                                }
480
481                         if (ISIS_LSP_CLV_METRIC_SUPPORTED(pd[offset+2])) {
482                           proto_tree_add_text (ntree, NullTVB, offset+2, 1, "Expense Metric: Not supported");
483                         } else {
484                           proto_tree_add_text (ntree, NullTVB, offset+2, 1, "Exense Metric:  %d, %s",
485                                                ISIS_LSP_CLV_METRIC_VALUE(pd[offset+2]),
486                                                ISIS_LSP_CLV_METRIC_IE(pd[offset+2]) ? "External" : "Internal");
487                         }
488
489                         if (ISIS_LSP_CLV_METRIC_SUPPORTED(pd[offset+3])) {
490                           proto_tree_add_text (ntree, NullTVB, offset+3, 1, "Error Metric:   Not supported");
491                         } else {
492                           proto_tree_add_text (ntree, NullTVB, offset+3, 1, "Error Metric:   %d, %s",
493                                                ISIS_LSP_CLV_METRIC_VALUE(pd[offset+3]),
494                                                ISIS_LSP_CLV_METRIC_IE(pd[offset+3]) ? "External" : "Internal");
495                         }
496                 }
497                 offset += 12;
498                 length -= 12;
499         }
500 }
501
502 /*
503  * Name: dissect_lsp_ext_ip_reachability_clv()
504  *
505  * Description: Decode an Extended IP Reachability CLV - code 135.
506  *
507  *   The extended IP reachability TLV is an extended version
508  *   of the IP reachability TLVs (codes 128 and 130). It encodes 
509  *   the metric as a 32-bit unsigned interger and allows to add 
510  *   sub-CLV(s).
511  *
512  * Input:
513  *   u_char * : packet data
514  *   int : current offset into packet data
515  *   guint : length of this clv
516  *   int : length of IDs in packet.
517  *   frame_data * : frame data
518  *   proto_tree * : proto tree to build on (may be null)
519  *
520  * Output:
521  *   void, will modify proto_tree if not null.
522  */
523 static void 
524 dissect_lsp_ext_ip_reachability_clv(const u_char *pd, int offset, 
525                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
526         proto_item *pi = NULL;
527         proto_tree *subtree = NULL;
528         guint8     ctrl_info;
529         guint8     bit_length, byte_length;
530         guint8     prefix [4];
531         guint8     len;
532
533         if (!tree) return;
534
535         while (length > 0) {
536                 memset (prefix, 0, 4);
537                 ctrl_info = pd[offset+4];
538                 bit_length = ctrl_info & 0x3f;
539                 byte_length = (bit_length + 7) / 8;
540                 memcpy (prefix, &pd[offset+5], byte_length);
541                 pi = proto_tree_add_text (tree, NullTVB, offset, 0,
542                         "IPv4 prefix: %s/%d", 
543                         ip_to_str (prefix),
544                         bit_length );
545                 subtree = proto_item_add_subtree (pi, 
546                         ett_isis_lsp_part_of_clv_ext_ip_reachability);
547
548                 proto_tree_add_text (subtree, NullTVB, offset, 4,
549                         "Metric: %d, Distribution: %s", pntohl (&pd[offset]), ((ctrl_info & 0x80) == 0) ? "up" : "down" );
550
551                 proto_tree_add_text (subtree, NullTVB, offset+4, 1,
552                         "Sub_CLV(s): %s",
553                         ((ctrl_info & 0x40) == 0) ? "no" : "yes" );
554
555                 len = 5 + byte_length;
556                 if ((ctrl_info & 0x40) != 0)
557                         len += 1 + pd[offset+len] ;
558                 proto_item_set_len (pi, len);
559                 offset += len;
560                 length -= len;
561         }
562 }
563
564 /*
565  * Name: dissect_lsp_ipv6_reachability_clv()
566  *
567  * Description: Decode an IPv6 reachability CLV - code 236.
568  *
569  * Input:
570  *   u_char * : packet data
571  *   int : current offset into packet data
572  *   guint : length of this clv
573  *   int : length of IDs in packet.
574  *   frame_data * : frame data
575  *   proto_tree * : proto tree to build on (may be null)
576  *
577  * Output:
578  *   void, will modify proto_tree if not null.
579  */
580 static void 
581 dissect_lsp_ipv6_reachability_clv(const u_char *pd, int offset, 
582                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
583         proto_item        *ti;
584         proto_tree        *ntree = NULL;
585         guint8            bit_length, byte_length;
586         struct e_in6_addr prefix;
587         guint8            ctrl_info;
588         guint32           metric;
589         guint8            len;
590
591         if (!tree) return;
592         
593         memset (prefix.s6_addr, 0, 16);
594
595         while (length > 0) {
596                 bit_length = pd[offset+5];
597                 byte_length = (bit_length + 7) / 8;
598                 memcpy (prefix.s6_addr, &pd[offset+6], byte_length);
599                 ti = proto_tree_add_text (tree, NullTVB, offset, 0,
600                         "IP prefix: %s /%d", 
601                         ip6_to_str (&prefix),
602                         bit_length );
603                 ntree = proto_item_add_subtree (ti, ett_isis_lsp_part_of_clv_ipv6_reachability);
604
605                 metric = pntohl (&pd[offset]);
606                 proto_tree_add_text (ntree, NullTVB, offset, 4,
607                         "Metric: %d", metric);
608
609                 ctrl_info = pd[offset+4];
610                 proto_tree_add_text (ntree, NullTVB, offset+4, 1,
611                         "Distribution: %s, %s",
612                         ((ctrl_info & 0x80) == 0) ? "up" : "down",
613                         ((ctrl_info & 0x40) == 0) ? "internal" : "external" );
614
615                 proto_tree_add_text (ntree, NullTVB, offset+4, 1,
616                         "Reserved bits: 0x%x",
617                         (ctrl_info & 0x1f) );
618                 proto_tree_add_text (ntree, NullTVB, offset+4, 1,
619                         "Sub_CLV(s): %s",
620                         ((ctrl_info & 0x20) == 0) ? "no" : "yes" );
621
622                 len = 6 + byte_length;
623                 if ((ctrl_info & 0x20) != 0)
624                         len += 1 + pd[offset+len] ;
625                 proto_item_set_len (ti, len);
626                 offset += len;
627                 length -= len;
628         }
629 }
630
631 /*
632  * Name: dissect_lsp_nlpid_clv()
633  *
634  * Description:
635  *      Decode for a lsp packets NLPID clv.  Calls into the
636  *      clv common one.
637  *
638  * Input:
639  *      u_char * : packet data
640  *      int : current offset into packet data
641  *      guint : length of this clv
642  *      int : length of IDs in packet.
643  *      frame_data * : frame data
644  *      proto_tree * : proto tree to build on (may be null)
645  *
646  * Output:
647  *      void, will modify proto_tree if not null.
648  */
649 static void 
650 dissect_lsp_nlpid_clv(const u_char *pd, int offset, 
651                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
652         isis_dissect_nlpid_clv(pd, offset, length, fd, tree );
653 }
654
655 /*
656  * Name: dissect_lsp_hostname_clv()
657  *
658  * Description:
659  *      Decode for a lsp packets hostname clv.  Calls into the
660  *      clv common one.
661  *
662  * Input:
663  *      u_char * : packet data
664  *      int : current offset into packet data
665  *      guint : length of this clv
666  *      int : length of IDs in packet.
667  *      frame_data * : frame data
668  *      proto_tree * : proto tree to build on (may be null)
669  *
670  * Output:
671  *      void, will modify proto_tree if not null.
672  */
673 static void 
674 dissect_lsp_hostname_clv(const u_char *pd, int offset, 
675                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
676         isis_dissect_hostname_clv(pd, offset, length, fd, tree );
677 }
678
679
680 /*
681  * Name: dissect_lsp_te_router_id_clv()
682  *
683  * Description:
684  *      Decode for a lsp packets Traffic Engineering ID clv.  Calls into the
685  *      clv common one.
686  *
687  * Input:
688  *      u_char * : packet data
689  *      int : current offset into packet data
690  *      guint : length of this clv
691  *      int : length of IDs in packet.
692  *      frame_data * : frame data
693  *      proto_tree * : proto tree to build on (may be null)
694  *
695  * Output:
696  *      void, will modify proto_tree if not null.
697  */
698 static void
699 dissect_lsp_te_router_id_clv(const u_char *pd, int offset,
700                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
701         isis_dissect_te_router_id_clv(pd, offset, length, fd, tree,
702                 hf_isis_lsp_clv_te_router_id );
703 }
704
705
706
707
708 /*
709  * Name: dissect_lsp_ip_int_addr_clv()
710  *
711  * Description:
712  *      Decode for a lsp packets ip interface addr clv.  Calls into the
713  *      clv common one.
714  *
715  * Input:
716  *      u_char * : packet data
717  *      int : current offset into packet data
718  *      guint : length of this clv
719  *      int : length of IDs in packet.
720  *      frame_data * : frame data
721  *      proto_tree * : proto tree to build on (may be null)
722  *
723  * Output:
724  *      void, will modify proto_tree if not null.
725  */
726 static void 
727 dissect_lsp_ip_int_addr_clv(const u_char *pd, int offset,
728                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
729         isis_dissect_ip_int_clv(pd, offset, length, fd, tree, 
730                 hf_isis_lsp_clv_ipv4_int_addr );
731 }
732
733 /*
734  * Name: dissect_lsp_ipv6_int_addr_clv()
735  *
736  * Description: Decode an IPv6 interface addr CLV - code 232.
737  *
738  *   Calls into the clv common one.
739  *
740  * Input:
741  *   u_char * : packet data
742  *   int : current offset into packet data
743  *   guint : length of this clv
744  *   int : length of IDs in packet.
745  *   frame_data * : frame data
746  *   proto_tree * : proto tree to build on (may be null)
747  *
748  * Output:
749  *   void, will modify proto_tree if not null.
750  */
751 static void 
752 dissect_lsp_ipv6_int_addr_clv(const u_char *pd, int offset, 
753                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
754         isis_dissect_ipv6_int_clv(pd, offset, length, fd, tree, 
755                 hf_isis_lsp_clv_ipv6_int_addr );
756 }
757
758 /*
759  * Name: dissect_lsp_L1_auth_clv()
760  *
761  * Description:
762  *      Decode for a lsp packets authenticaion clv.  Calls into the
763  *      clv common one.  An auth inside a L1 LSP is a per area password
764  *
765  * Input:
766  *      u_char * : packet data
767  *      int : current offset into packet data
768  *      guint : length of this clv
769  *      int : length of IDs in packet.
770  *      frame_data * : frame data
771  *      proto_tree * : proto tree to build on (may be null)
772  *
773  * Output:
774  *      void, will modify proto_tree if not null.
775  */
776 static void 
777 dissect_lsp_l1_auth_clv(const u_char *pd, int offset, 
778                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
779         isis_dissect_authentication_clv(pd, offset, length, fd, tree, 
780                 "Per area authentication" );
781 }
782
783 /*
784  * Name: dissect_lsp_L2_auth_clv()
785  *
786  * Description:
787  *      Decode for a lsp packets authenticaion clv.  Calls into the
788  *      clv common one.  An auth inside a L2 LSP is a per domain password
789  *
790  * Input:
791  *      u_char * : packet data
792  *      int : current offset into packet data
793  *      guint : length of this clv
794  *      int : length of IDs in packet.
795  *      frame_data * : frame data
796  *      proto_tree * : proto tree to build on (may be null)
797  *
798  * Output:
799  *      void, will modify proto_tree if not null.
800  */
801 static void 
802 dissect_lsp_l2_auth_clv(const u_char *pd, int offset, 
803                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
804         isis_dissect_authentication_clv(pd, offset, length, fd, tree, 
805                 "Per domain authentication" );
806 }
807
808 /*
809  * Name: dissect_lsp_area_address_clv()
810  *
811  * Description:
812  *      Decode for a lsp packet's area address clv.  Call into clv common
813  *      one.
814  *
815  * Input:
816  *      u_char * : packet data
817  *      int : offset into packet data where we are.
818  *      guint : length of clv we are decoding
819  *      int : length of IDs in packet.
820  *      frame_data * : frame data (complete frame)
821  *      proto_tree * : protocol display tree to fill out.  May be NULL
822  *
823  * Output:
824  *      void, but we will add to proto tree if !NULL.
825  */
826 static void 
827 dissect_lsp_area_address_clv(const u_char *pd, int offset, 
828                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
829         isis_dissect_area_address_clv(pd, offset, length, fd, tree );
830 }
831
832 /*
833  * Name: dissect_lsp_eis_neighbors_clv_inner()
834  *
835  * Description:
836  *      Real work horse for showing neighbors.  This means we decode the
837  *      first octet as either virtual/!virtual (if show_virtual param is
838  *      set), or as a must == 0 reserved value.
839  *
840  *      Once past that, we decode n neighbor elements.  Each neighbor
841  *      is comprised of a metric block (is dissect_metric) and the
842  *      addresses.
843  *
844  * Input:
845  *      u_char * : packet data
846  *      int : offset into packet data where we are.
847  *      guint : length of clv we are decoding
848  *      int : length of IDs in packet.
849  *      frame_data * : frame data (complete frame)
850  *      proto_tree * : protocol display tree to fill out.  May be NULL
851  *      int : set to decode first octet as virtual vs reserved == 0
852  *      int : set to indicate EIS instead of IS (6 octet per addr instead of 7)
853  *
854  * Output:
855  *      void, but we will add to proto tree if !NULL.
856  */
857 static void 
858 dissect_lsp_eis_neighbors_clv_inner(const u_char *pd, int offset, 
859                 guint length, int id_length, frame_data *fd, proto_tree *tree,
860                 int show_virtual, int is_eis) {
861         proto_item      *ti;
862         proto_tree      *ntree = NULL;
863         int             tlen;
864
865         if (!is_eis) {
866                 id_length++;    /* IDs are one octet longer in IS neighbours */
867                 if ( tree ) {
868                         if ( show_virtual ) {
869                                 /* virtual path flag */
870                                 proto_tree_add_text ( tree, NullTVB, offset, 1, 
871                                    &pd[offset] ? "IsNotVirtual" : "IsVirtual" );
872                         } else {
873                                 proto_tree_add_text ( tree, NullTVB, offset, 1, 
874                                         "Reserved value 0x%02x, must == 0",
875                                         pd[offset]  );
876                         }
877                 }
878                 offset++;
879                 length--;
880         }
881         tlen = 4 + id_length;
882
883         while ( length > 0 ) {
884                 if (length<tlen) {
885                         isis_dissect_unknown(offset, length, tree, fd,
886                                 "short E/IS reachability (%d vs %d)", length,
887                                 tlen );
888                         return;
889                 }
890                 /* 
891                  * Gotta build a sub-tree for all our pieces
892                  */
893                 if ( tree ) {
894                         if ( is_eis ) {
895                                 ti = proto_tree_add_text ( tree, NullTVB, offset, tlen, 
896                                         "ES Neighbor: %s",
897                                 print_system_id( pd + offset + 4, id_length ) );
898                         } else {
899                                 ti = proto_tree_add_text ( tree, NullTVB, offset, tlen, 
900                                         "IS Neighbor:  %s",
901                                 print_system_id( pd + offset + 4, id_length ) );
902                         }
903                         ntree = proto_item_add_subtree(ti, 
904                                 ett_isis_lsp_clv_is_neighbors);
905
906
907
908                         proto_tree_add_text (ntree, NullTVB, offset, 1,
909                                              "Default Metric: %d, %s",
910                                              ISIS_LSP_CLV_METRIC_VALUE(pd[offset]),
911                                              ISIS_LSP_CLV_METRIC_IE(pd[offset]) ? "External" : "Internal");
912                                             
913                         if (ISIS_LSP_CLV_METRIC_SUPPORTED(pd[offset+1])) {
914                           proto_tree_add_text (ntree, NullTVB, offset+1, 1, "Delay Metric:   Not supported");
915                         } else {
916                           proto_tree_add_text (ntree, NullTVB, offset+1, 1, "Delay Metric:   %d, %s",
917                                              ISIS_LSP_CLV_METRIC_VALUE(pd[offset+1]),
918                                              ISIS_LSP_CLV_METRIC_IE(pd[offset+1]) ? "External" : "Internal");
919                         }
920
921
922                         if (ISIS_LSP_CLV_METRIC_SUPPORTED(pd[offset+2])) {
923                           proto_tree_add_text (ntree, NullTVB, offset+2, 1, "Expense Metric: Not supported");
924                         } else {
925                           proto_tree_add_text (ntree, NullTVB, offset+2, 1, "Expense Metric: %d, %s",
926                                                ISIS_LSP_CLV_METRIC_VALUE(pd[offset+2]),
927                                                ISIS_LSP_CLV_METRIC_IE(pd[offset+2]) ? "External" : "Internal");
928                         }
929
930                         if (ISIS_LSP_CLV_METRIC_SUPPORTED(pd[offset+3])) {
931                           proto_tree_add_text (ntree, NullTVB, offset+3, 1, "Error Metric:   Not supported");
932                         } else {
933                           proto_tree_add_text (ntree, NullTVB, offset+3, 1, "Error Metric:   %d, %s",
934                                                ISIS_LSP_CLV_METRIC_VALUE(pd[offset+3]),
935                                                ISIS_LSP_CLV_METRIC_IE(pd[offset+3]) ? "External" : "Internal");
936                         }
937          
938                         
939 /* this is redundant information
940                         Proto_tree_add_text ( ntree, NullTVB, offset + 4, id_length, 
941                                 "Neighbour ID: %s",
942                                 print_system_id( pd + offset + 4, id_length ) );
943 */
944                 }
945                 offset += tlen;
946                 length -= tlen;
947         }
948 }
949
950 /*
951  * Name: dissect_lsp_l1_is_neighbors_clv()
952  *
953  * Description:
954  *      Dispatch a l1 intermediate system neighbor by calling
955  *      the inner function with show virtual set to TRUE and is es set to FALSE.
956  *
957  * Input:
958  *      u_char * : packet data
959  *      int : offset into packet data where we are.
960  *      guint : length of clv we are decoding
961  *      int : length of IDs in packet.
962  *      frame_data * : frame data (complete frame)
963  *      proto_tree * : protocol display tree to fill out.  May be NULL
964  *
965  * Output:
966  *      void, but we will add to proto tree if !NULL.
967  */
968 static void 
969 dissect_lsp_l1_is_neighbors_clv(const u_char *pd, int offset, 
970                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
971         dissect_lsp_eis_neighbors_clv_inner( pd, offset, length, id_length,
972                 fd, tree, TRUE, FALSE );
973 }
974
975 /*
976  * Name: dissect_lsp_l1_es_neighbors_clv()
977  *
978  * Description:
979  *      Dispatch a l1 end or intermediate system neighbor by calling
980  *      the inner function with show virtual set to TRUE and es set to TRUE.
981  *
982  * Input:
983  *      u_char * : packet data
984  *      int : offset into packet data where we are.
985  *      guint : length of clv we are decoding
986  *      int : length of IDs in packet.
987  *      frame_data * : frame data (complete frame)
988  *      proto_tree * : protocol display tree to fill out.  May be NULL
989  *
990  * Output:
991  *      void, but we will add to proto tree if !NULL.
992  */
993 static void 
994 dissect_lsp_l1_es_neighbors_clv(const u_char *pd, int offset, 
995                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
996         dissect_lsp_eis_neighbors_clv_inner( pd, offset, length, id_length,
997                 fd, tree, TRUE, TRUE);
998 }
999
1000 /*
1001  * Name: dissect_lsp_l2_is_neighbors_clv()
1002  *
1003  * Description:
1004  *      Dispatch a l2 intermediate system neighbor by calling
1005  *      the inner function with show virtual set to FALSE, and is es set
1006  *      to FALSE
1007  *
1008  * Input:
1009  *      u_char * : packet data
1010  *      int : offset into packet data where we are.
1011  *      guint : length of clv we are decoding
1012  *      int : length of IDs in packet.
1013  *      frame_data * : frame data (complete frame)
1014  *      proto_tree * : protocol display tree to fill out.  May be NULL
1015  *
1016  * Output:
1017  *      void, but we will add to proto tree if !NULL.
1018  */
1019 static void 
1020 dissect_lsp_l2_is_neighbors_clv(const u_char *pd, int offset, 
1021                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
1022         dissect_lsp_eis_neighbors_clv_inner(pd, offset, length, id_length,
1023                 fd, tree, FALSE, FALSE);
1024 }
1025
1026 /*
1027  * Name: dissect_subclv_admin_group ()
1028  *
1029  * Description: Called by function dissect_lsp_ext_is_reachability_clv().
1030  *
1031  *   This function is called by dissect_lsp_ext_is_reachability_clv()
1032  *   for dissect the administrive group sub-CLV (code 3).
1033  *
1034  * Input:
1035  *   u_char * : packet data
1036  *   int : offset into packet data where we are (beginning of the sub_clv value).
1037  *   proto_tree * : protocol display tree to fill out.
1038  *
1039  * Output:
1040  *   void
1041  */
1042 static void
1043 dissect_subclv_admin_group (const u_char *pd, int offset, proto_tree  *tree) {
1044         proto_item *ti;
1045         proto_tree *ntree;
1046         guint32    clv_value;
1047         guint32    mask;
1048         int        i;
1049
1050         ti = proto_tree_add_text (tree, NullTVB, offset-2, 6, "Administrative group(s):");
1051         ntree = proto_item_add_subtree (ti, ett_isis_lsp_subclv_admin_group);
1052
1053         clv_value = pntohl (&pd[offset]);
1054         mask = 1;
1055         for (i = 0 ; i < 32 ; i++) {
1056                 if ( (clv_value & mask) != 0 ) {
1057                         proto_tree_add_text (ntree, NullTVB, offset, 4, "group %d", i);
1058                 }
1059                 mask <<= 1;
1060         }
1061 }
1062
1063 /*
1064  * Name: dissect_subclv_max_bw ()
1065  *
1066  * Description: Called by function dissect_lsp_ext_is_reachability_clv().
1067  *
1068  *   This function is called by dissect_lsp_ext_is_reachability_clv()
1069  *   for dissect the maximum link bandwidth sub-CLV (code 9).
1070  *
1071  * Input:
1072  *   u_char * : packet data
1073  *   int : offset into packet data where we are (beginning of the sub_clv value).
1074  *   proto_tree * : protocol display tree to fill out.
1075  *
1076  * Output:
1077  *   void
1078  */
1079 static void
1080 dissect_subclv_max_bw (const u_char *pd, int offset, proto_tree *tree) {
1081         guint32 ui;
1082         gfloat  bw;
1083
1084         ui = pntohl (&pd[offset]);
1085         memcpy (&bw, &ui, 4);
1086         proto_tree_add_text (tree, NullTVB, offset-2, 6,
1087                 "Maximum link bandwidth : %.2f Mbps", bw*8/1000000 );
1088 }
1089
1090 /*
1091  * Name: dissect_subclv_rsv_bw ()
1092  *
1093  * Description: Called by function dissect_lsp_ext_is_reachability_clv().
1094  *
1095  *   This function is called by dissect_lsp_ext_is_reachability_clv()
1096  *   for dissect the reservable link bandwidth sub-CLV (code 10).
1097  *
1098  * Input:
1099  *   u_char * : packet data
1100  *   int : offset into packet data where we are (beginning of the sub_clv value).
1101  *   proto_tree * : protocol display tree to fill out.
1102  *
1103  * Output:
1104  *   void
1105  */
1106 static void
1107 dissect_subclv_rsv_bw (const u_char *pd, int offset, proto_tree *tree) {
1108         guint32 ui;
1109         gfloat  bw;
1110
1111         ui = pntohl (&pd[offset]);
1112         memcpy (&bw, &ui, 4);
1113         proto_tree_add_text (tree, NullTVB, offset-2, 6,
1114                 "Reservable link bandwidth: %.2f Mbps", bw*8/1000000 );
1115 }
1116
1117 /*
1118  * Name: dissect_subclv_unrsv_bw ()
1119  *
1120  * Description: Called by function dissect_lsp_ext_is_reachability_clv().
1121  *
1122  *   This function is called by dissect_lsp_ext_is_reachability_clv()
1123  *   for dissect the unreserved bandwidth sub-CLV (code 11).
1124  *
1125  * Input:
1126  *   u_char * : packet data
1127  *   int : offset into packet data where we are (beginning of the sub_clv value).
1128  *   proto_tree * : protocol display tree to fill out.
1129  *
1130  * Output:
1131  *   void
1132  */
1133 static void
1134 dissect_subclv_unrsv_bw (const u_char *pd, int offset, proto_tree *tree) {
1135         proto_item *ti;
1136         proto_tree *ntree;
1137         guint32    ui;
1138         gfloat     bw;
1139         int        i;
1140
1141         ti = proto_tree_add_text (tree, NullTVB, offset-2, 34, "Unreserved bandwidth:");
1142         ntree = proto_item_add_subtree (ti, ett_isis_lsp_subclv_unrsv_bw);
1143
1144         for (i = 0 ; i < 8 ; i++) {
1145                 ui = pntohl (&pd[offset]);
1146                 memcpy (&bw, &ui, 4);
1147                 proto_tree_add_text (ntree, NullTVB, offset+4*i, 4,
1148                         "priority level %d: %.2f Mbps", i, bw*8/1000000 );
1149         }
1150 }
1151
1152 /*
1153  * Name: dissect_lsp_ext_is_reachability_clv()
1154  *
1155  * Description: Decode a Extended IS Reachability CLV - code 22
1156  *
1157  *   The extended IS reachability TLV is an extended version
1158  *   of the IS reachability TLV (code 2). It encodes the metric
1159  *   as a 24-bit unsigned interger and allows to add sub-CLV(s).
1160  *
1161  * Input:
1162  *   u_char * : packet data
1163  *   int : offset into packet data where we are.
1164  *   guint : length of clv we are decoding
1165  *   int : length of IDs in packet.
1166  *   frame_data * : frame data (complete frame)
1167  *   proto_tree * : protocol display tree to fill out.  May be NULL
1168  *
1169  * Output:
1170  *   void, but we will add to proto tree if !NULL.
1171  */
1172 static void 
1173 dissect_lsp_ext_is_reachability_clv(const u_char *pd, int offset, 
1174                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
1175         proto_item *ti;
1176         proto_tree *ntree = NULL;
1177         guint8     subclvs_len;
1178         guint8     len, i;
1179         guint8     clv_code, clv_len;
1180
1181         if (!tree) return;
1182
1183         while (length > 0) {
1184                 ti = proto_tree_add_text (tree, NullTVB, offset, 0,
1185                         "IS neighbor: %s",
1186                         print_system_id (&pd[offset], 7) );
1187                 ntree = proto_item_add_subtree (ti, 
1188                         ett_isis_lsp_part_of_clv_ext_is_reachability );
1189                 
1190                 proto_tree_add_text (ntree, NullTVB, offset+7, 3,
1191                         "Metric: %d", pntoh24 (&pd[offset+7]) );
1192
1193                 subclvs_len = pd[offset+10];
1194                 if (subclvs_len == 0) {
1195                         proto_tree_add_text (ntree, NullTVB, offset+10, 1, "No sub-CLV");
1196                 }
1197                 else {
1198                         i = 0;
1199                         while (i < subclvs_len) {
1200                                 clv_code = pd[offset+11+i];
1201                                 clv_len  = pd[offset+12+i];
1202                                 switch (clv_code) {
1203                                 case 3 :
1204                                         dissect_subclv_admin_group (pd, offset+13+i, ntree);
1205                                         break;
1206                                 case 6 :
1207                                         proto_tree_add_text (ntree, NullTVB, offset+11+i, 6,
1208                                                 "IPv4 interface address: %s", ip_to_str (&pd[offset+13+i]) );
1209                                         break;
1210                                 case 8 :
1211                                         proto_tree_add_text (ntree, NullTVB, offset+11+i, 6,
1212                                                 "IPv4 neighbor address: %s", ip_to_str (&pd[offset+13+i]) );
1213                                         break;
1214                                 case 9 :
1215                                         dissect_subclv_max_bw (pd, offset+13+i, ntree);
1216                                         break;
1217                                 case 10:
1218                                         dissect_subclv_rsv_bw (pd, offset+13+i, ntree);
1219                                         break;
1220                                 case 11:
1221                                         dissect_subclv_unrsv_bw (pd, offset+13+i, ntree);
1222                                         break;
1223                                 case 18:
1224                                         proto_tree_add_text (ntree, NullTVB, offset+11+i, 5,
1225                                                 "Traffic engineering default metric: %d", 
1226                                                 pntoh24 (&pd[offset+13+i]) );
1227                                         break;
1228                                 case 250:
1229                                 case 251:
1230                                 case 252:
1231                                 case 253:
1232                                 case 254:
1233                                         proto_tree_add_text (ntree, NullTVB, offset+11+i, clv_len+2,
1234                                                 "Unknown Cisco specific extensions: code %d, length %d",
1235                                                 clv_code, clv_len );
1236                                         break;
1237                                 default :
1238                                         proto_tree_add_text (ntree, NullTVB, offset+11+i, clv_len+2,
1239                                                 "Unknown sub-CLV: code %d, length %d", clv_code, clv_len );
1240                                         break;
1241                                 }
1242                                 i += clv_len + 2;
1243                         }
1244                 }
1245
1246                 len = 11 + subclvs_len;
1247                 proto_item_set_len (ti, len);
1248                 offset += len;
1249                 length -= len;
1250         }
1251 }
1252
1253 /*
1254  * Name: dissect_lsp_partition_dis_clv()
1255  *
1256  * Description:
1257  *      This CLV is used to indicate which system is the designated
1258  *      IS for partition repair.  This means just putting out the
1259  *      "id_length"-octet IS.
1260  *
1261  * Input:
1262  *      u_char * : packet data
1263  *      int : offset into packet data where we are.
1264  *      guint : length of clv we are decoding
1265  *      int : length of IDs in packet.
1266  *      frame_data * : frame data (complete frame)
1267  *      proto_tree * : protocol display tree to fill out.  May be NULL
1268  *
1269  * Output:
1270  *      void, but we will add to proto tree if !NULL.
1271  */
1272 static void 
1273 dissect_lsp_partition_dis_clv(const u_char *pd, int offset, 
1274                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
1275
1276         if ( length < id_length ) {
1277                 isis_dissect_unknown(offset, length, tree, fd,
1278                                 "short lsp parition DIS(%d vs %d)", length,
1279                                 id_length );
1280                 return;
1281         }
1282         /* 
1283          * Gotta build a sub-tree for all our pieces
1284          */
1285         if ( tree ) {
1286                 proto_tree_add_text ( tree, NullTVB, offset, id_length, 
1287                         "Partition designated L2 IS: %s",
1288                         print_system_id( pd + offset, id_length ) );
1289         }
1290         length -= id_length;
1291         offset += id_length;
1292         if ( length > 0 ){
1293                 isis_dissect_unknown(offset, length, tree, fd,
1294                                 "Long lsp parition DIS, %d left over", length );
1295                 return;
1296         }
1297 }
1298
1299 /*
1300  * Name: dissect_lsp_prefix_neighbors_clv()
1301  *
1302  * Description:
1303  *      The prefix CLV describes what other (OSI) networks we can reach
1304  *      and what their cost is.  It is built from a metric block
1305  *      (see dissect_metric) followed by n addresses.
1306  *
1307  * Input:
1308  *      u_char * : packet data
1309  *      int : offset into packet data where we are.
1310  *      guint : length of clv we are decoding
1311  *      int : length of IDs in packet.
1312  *      frame_data * : frame data (complete frame)
1313  *      proto_tree * : protocol display tree to fill out.  May be NULL
1314  *
1315  * Output:
1316  *      void, but we will add to proto tree if !NULL.
1317  */
1318 static void 
1319 dissect_lsp_prefix_neighbors_clv(const u_char *pd, int offset, 
1320                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
1321         char *sbuf;
1322         int mylen;
1323
1324         if ( length < 4 ) {
1325                 isis_dissect_unknown(offset, length, tree, fd,
1326                         "Short lsp prefix neighbors (%d vs 4)", length );
1327                 return;
1328         }
1329         if ( tree ) {
1330                 dissect_metric ( tree, offset, pd[offset], "Default", TRUE );
1331                 dissect_metric ( tree, offset + 1, pd[offset+1], 
1332                         "Delay", FALSE );
1333                 dissect_metric ( tree, offset + 2, pd[offset+2], 
1334                         "Expense", FALSE );
1335                 dissect_metric ( tree, offset + 3, pd[offset+3], 
1336                         "Error", FALSE );
1337         }
1338         offset += 4;
1339         length -= 4;
1340         while ( length > 0 ) {
1341                 mylen = pd[offset];
1342                 length--;
1343                 if (length<=0) {
1344                         isis_dissect_unknown(offset, length, tree, fd,
1345                                 "Zero payload space after length in prefix neighbor" );
1346                         return;
1347                 }
1348                 if ( mylen > length) {
1349                         isis_dissect_unknown(offset, length, tree, fd,
1350                                 "Interal length of prefix neighbor too long (%d vs %d)", 
1351                                 mylen, length );
1352                         return;
1353                 }
1354
1355                 /* 
1356                  * Lets turn the area address into "standard" 0000.0000.etc
1357                  * format string.  
1358                  */
1359                 sbuf =  print_area( pd + offset + 1, mylen );
1360                 /* and spit it out */
1361                 if ( tree ) {
1362                         proto_tree_add_text ( tree, NullTVB, offset, mylen + 1, 
1363                                 "Area address (%d): %s", mylen, sbuf );
1364                 }
1365                 offset += mylen + 1;
1366                 length -= mylen;        /* length already adjusted for len fld*/
1367         }
1368 }
1369
1370 /*
1371  * Name: isis_lsp_decode_lsp_id()
1372  *
1373  * Description: 
1374  *      Display a LSP id into the display tree.
1375  *
1376  * Input:
1377  *      char * : title string
1378  *      proto_tree * : tree to display into. REQUIRED
1379  *      u_char * : packet data
1380  *      int : offset into packet data where we are.
1381  *      int : length of IDs in packet.
1382  *
1383  * Output:
1384  *      void, but we will add to proto tree
1385  */
1386 void
1387 isis_lsp_decode_lsp_id(char *tstr, proto_tree *tree, const u_char *pd,
1388                 int offset, int id_length ) {
1389         proto_tree_add_text(tree, NullTVB, offset, id_length + 2,
1390                 "%s: %s.%02x-%02x", tstr,
1391                         print_system_id( pd + offset, id_length ),
1392                         pd[offset + id_length],
1393                         pd[offset + id_length + 1] );
1394 }
1395
1396 /*
1397  * Name: isis_dissect_isis_lsp()
1398  *
1399  * Description:
1400  *      Print out the LSP part of the main header and then call the CLV
1401  *      de-mangler with the right list of valid CLVs.
1402  *
1403  * Input:
1404  *      int : LSP type, a la packet-isis.h ISIS_TYPE_* values
1405  *      int : header length of packet.
1406  *      int : length of IDs in packet.
1407  *      u_char * : packet data
1408  *      int offset : our offset into packet data.
1409  *      frame_data * : frame data
1410  *      proto_tree * : protocol display tree to add to.  May be NULL.
1411  *
1412  * Output:
1413  *      void, but we will add to proto tree if !NULL.
1414  */
1415 void 
1416 isis_dissect_isis_lsp(int lsp_type, int header_length, int id_length,
1417                 const u_char *pd, int offset, frame_data *fd, proto_tree *tree){
1418         proto_item      *ti;
1419         proto_tree      *lsp_tree = NULL;
1420         int             hlen;
1421         guint16         pdu_length;
1422         char            sbuf[128];
1423         int             inx, q, some, value, len;
1424
1425         OLD_CHECK_DISPLAY_AS_DATA(proto_isis_lsp, pd, offset, fd, tree);
1426
1427         hlen = 2+2+id_length+2+4+2+1;
1428
1429         if (!BYTES_ARE_IN_FRAME(offset, hlen)) {
1430                 isis_dissect_unknown(offset, hlen, tree, fd,
1431                         "not enough capture data for header (%d vs %d)",
1432                         hlen, END_OF_FRAME);
1433                 return;
1434         }
1435         
1436         if (tree) {
1437                 ti = proto_tree_add_item(tree, proto_isis_lsp, NullTVB,
1438                         offset, END_OF_FRAME, FALSE);
1439                 lsp_tree = proto_item_add_subtree(ti, ett_isis_lsp);
1440         }
1441
1442         pdu_length = pntohs(&pd[offset]);
1443         if (tree) {
1444                 proto_tree_add_uint(lsp_tree, hf_isis_lsp_pdu_length, NullTVB,
1445                         offset, 2, pdu_length);
1446         }
1447         offset += 2;
1448
1449         if (tree) {
1450                 proto_tree_add_uint(lsp_tree, hf_isis_lsp_remaining_life, NullTVB,
1451                         offset, 2, pntohs(&pd[offset]));
1452         }
1453         offset += 2;
1454
1455         if (tree) {
1456                 isis_lsp_decode_lsp_id("LSP ID", lsp_tree, pd, offset,
1457                         id_length );
1458         }
1459         offset += id_length + 2;
1460
1461         if (tree) {
1462                 proto_tree_add_uint(lsp_tree, hf_isis_lsp_sequence_number, NullTVB,
1463                         offset, 4, 
1464                         pntohl(&pd[offset]));
1465         }
1466         offset += 4;
1467
1468         if (tree) {
1469                 /* XXX -> we could validate the cksum here! */
1470                 proto_tree_add_uint(lsp_tree, hf_isis_lsp_checksum, NullTVB,
1471                         offset, 2, pntohs(&pd[offset]));
1472         }
1473         offset += 2;
1474
1475         if (tree) {
1476                 /*
1477                  * We need to build our type block values. 
1478                  */
1479                 sbuf[0] = 0;
1480                 some = 0;
1481                 value = ISIS_LSP_ATT(pd[offset]);
1482                 inx = 0;
1483                 for ( q = (1<<ISIS_LSP_ATT_SHIFT); q > 0; q = q >> 1 ){
1484                         if (q & value) { 
1485                                 if (some++) {
1486                                         strcat(sbuf, ", ");
1487                                 }
1488                                 strcat ( sbuf, isis_lsp_attached_bits[inx] );
1489                         }
1490                         inx++;
1491                 }
1492                 if (!some) { 
1493                         strcat ( sbuf, "default-only" );
1494                 }
1495                 proto_tree_add_text(lsp_tree, NullTVB, offset + 18, 1, 
1496                         "Type block(0x%02x): P:%d, Supported metric(s): %s, OL:%d, istype:%s",
1497                         pd[offset],
1498                         ISIS_LSP_PARTITION(pd[offset]) ? 1 : 0,
1499                         sbuf,
1500                         ISIS_LSP_HIPPITY(pd[offset]) ? 1 : 0,
1501                         val_to_str(ISIS_LSP_IS_TYPE(pd[offset]),
1502                                 isis_lsp_istype_vals, "Unknown (0x%x)")
1503                         );
1504         }
1505         offset += 1;
1506
1507         len = pdu_length - header_length;
1508         if (len < 0) {
1509                 isis_dissect_unknown(offset, header_length, tree, fd,
1510                         "packet header length %d went beyond packet",
1511                          header_length );
1512                 return;
1513         }
1514         /*
1515          * Now, we need to decode our CLVs.  We need to pass in
1516          * our list of valid ones!
1517          */
1518         if (lsp_type == ISIS_TYPE_L1_LSP){
1519                 isis_dissect_clvs ( clv_l1_lsp_opts, len, id_length, pd,
1520                         offset, fd, lsp_tree, ett_isis_lsp_clv_unknown );
1521         } else {
1522                 isis_dissect_clvs ( clv_l2_lsp_opts, len, id_length, pd,
1523                         offset, fd, lsp_tree, ett_isis_lsp_clv_unknown );
1524         }
1525 }
1526 /*
1527  * Name: proto_register_isis_lsp()
1528  *
1529  * Description: 
1530  *      Register our protocol sub-sets with protocol manager.
1531  *      NOTE: this procedure is autolinked by the makefile process that
1532  *              builds register.c
1533  *
1534  * Input:
1535  *      u_char * : packet data
1536  *      int : offset into packet data where we are.
1537  *      guint : length of clv we are decoding
1538  *      frame_data * : frame data (complete frame)
1539  *      proto_tree * : protocol display tree to fill out.  May be NULL
1540  *
1541  * Output:
1542  *      void, but we will add to proto tree if !NULL.
1543  */
1544 void 
1545 proto_register_isis_lsp(void) {
1546         static hf_register_info hf[] = {
1547                 { &hf_isis_lsp_pdu_length,
1548                 { "PDU length",         "isis_lsp.pdu_length", FT_UINT16, 
1549                   BASE_DEC, NULL, 0x0, "", HFILL }},
1550
1551                 { &hf_isis_lsp_remaining_life,
1552                 { "Remaining life",     "isis_lsp.remaining_life", FT_UINT16, 
1553                   BASE_DEC, NULL, 0x0, "", HFILL }},
1554
1555                 { &hf_isis_lsp_sequence_number,
1556                 { "Sequence number",           "isis_lsp.sequence_number", 
1557                   FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
1558
1559                 { &hf_isis_lsp_checksum,
1560                 { "Checksum",           "isis_lsp.checksum",FT_UINT16, 
1561                   BASE_HEX, NULL, 0x0, "", HFILL }},
1562
1563                 { &hf_isis_lsp_clv_ipv4_int_addr,
1564                 { "IPv4 interface address", "isis_lsp.clv_ipv4_int_addr", FT_IPv4,
1565                    BASE_NONE, NULL, 0x0, "", HFILL }},
1566
1567                 { &hf_isis_lsp_clv_ipv6_int_addr,
1568                 { "IPv6 interface address", "isis_lsp.clv_ipv6_int_addr", FT_IPv6,
1569                    BASE_NONE, NULL, 0x0, "", HFILL }},
1570
1571                 { &hf_isis_lsp_clv_te_router_id,
1572                 { "Traffic Engineering Router ID", "isis_lsp.clv_te_router_id", FT_IPv4,
1573                    BASE_NONE, NULL, 0x0, "", HFILL }},
1574         };
1575         static gint *ett[] = {
1576                 &ett_isis_lsp,
1577                 &ett_isis_lsp_clv_area_addr,
1578                 &ett_isis_lsp_clv_is_neighbors,
1579                 &ett_isis_lsp_clv_ext_is_reachability, /* CLV 22 */
1580                         &ett_isis_lsp_part_of_clv_ext_is_reachability,
1581                         &ett_isis_lsp_subclv_admin_group,
1582                         &ett_isis_lsp_subclv_unrsv_bw,
1583                 &ett_isis_lsp_clv_unknown,
1584                 &ett_isis_lsp_clv_partition_dis,
1585                 &ett_isis_lsp_clv_prefix_neighbors,
1586                 &ett_isis_lsp_clv_auth,
1587                 &ett_isis_lsp_clv_nlpid,
1588                 &ett_isis_lsp_clv_hostname,
1589                 &ett_isis_lsp_clv_ipv4_int_addr,
1590                 &ett_isis_lsp_clv_ipv6_int_addr, /* CLV 232 */
1591                 &ett_isis_lsp_clv_te_router_id,
1592                 &ett_isis_lsp_clv_ip_reachability,
1593                 &ett_isis_lsp_clv_ext_ip_reachability, /* CLV 135 */
1594                         &ett_isis_lsp_part_of_clv_ext_ip_reachability,
1595                 &ett_isis_lsp_clv_ipv6_reachability, /* CLV 236 */
1596                         &ett_isis_lsp_part_of_clv_ipv6_reachability,
1597         };
1598
1599         proto_isis_lsp = proto_register_protocol(PROTO_STRING_LSP,
1600             "ISIS LSP", "isis_lsp");
1601         proto_register_field_array(proto_isis_lsp, hf, array_length(hf));
1602         proto_register_subtree_array(ett, array_length(ett));
1603 }
1604
1605