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