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