Fix the test in "dissect_smb_datetime()" for "no date/time specified"
[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.29 2002/04/24 20:25:02 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         gfloat  bw;
1130
1131         bw = tvb_get_ntohieee_float(tvb, offset);
1132         proto_tree_add_text (tree, tvb, offset-2, 6,
1133                 "Maximum link bandwidth : %.2f Mbps", bw*8/1000000 );
1134 }
1135
1136 /*
1137  * Name: dissect_subclv_rsv_bw ()
1138  *
1139  * Description: Called by function dissect_lsp_ext_is_reachability_clv().
1140  *
1141  *   This function is called by dissect_lsp_ext_is_reachability_clv()
1142  *   for dissect the reservable link bandwidth sub-CLV (code 10).
1143  *
1144  * Input:
1145  *   tvbuff_t * : tvbuffer for packet data
1146  *   proto_tree * : protocol display tree to fill out.
1147  *   int : offset into packet data where we are (beginning of the sub_clv value).
1148  *
1149  * Output:
1150  *   void
1151  */
1152 static void
1153 dissect_subclv_rsv_bw(tvbuff_t *tvb, proto_tree *tree, int offset)
1154 {
1155         gfloat  bw;
1156
1157         bw = tvb_get_ntohieee_float(tvb, offset);
1158         proto_tree_add_text (tree, tvb, offset-2, 6,
1159                 "Reservable link bandwidth: %.2f Mbps", bw*8/1000000 );
1160 }
1161
1162 /*
1163  * Name: dissect_subclv_unrsv_bw ()
1164  *
1165  * Description: Called by function dissect_lsp_ext_is_reachability_clv().
1166  *
1167  *   This function is called by dissect_lsp_ext_is_reachability_clv()
1168  *   for dissect the unreserved bandwidth sub-CLV (code 11).
1169  *
1170  * Input:
1171  *   tvbuff_t * : tvbuffer for packet data
1172  *   proto_tree * : protocol display tree to fill out.
1173  *   int : offset into packet data where we are (beginning of the sub_clv value).
1174  *
1175  * Output:
1176  *   void
1177  */
1178 static void
1179 dissect_subclv_unrsv_bw(tvbuff_t *tvb, proto_tree *tree, int offset)
1180 {
1181         proto_item *ti;
1182         proto_tree *ntree;
1183         gfloat     bw;
1184         int        i;
1185
1186         ti = proto_tree_add_text (tree, tvb, offset-2, 34, "Unreserved bandwidth:");
1187         ntree = proto_item_add_subtree (ti, ett_isis_lsp_subclv_unrsv_bw);
1188
1189         for (i = 0 ; i < 8 ; i++) {
1190                 bw = tvb_get_ntohieee_float(tvb, offset);;
1191                 proto_tree_add_text (ntree, tvb, offset+4*i, 4,
1192                         "priority level %d: %.2f Mbps", i, bw*8/1000000 );
1193         }
1194 }
1195
1196 /*
1197  * Name: dissect_lsp_ext_is_reachability_clv()
1198  *
1199  * Description: Decode a Extended IS Reachability CLV - code 22
1200  *
1201  *   The extended IS reachability TLV is an extended version
1202  *   of the IS reachability TLV (code 2). It encodes the metric
1203  *   as a 24-bit unsigned interger and allows to add sub-CLV(s).
1204  *
1205  * Input:
1206  *   tvbuff_t * : tvbuffer for packet data
1207  *   proto_tree * : protocol display tree to fill out.  May be NULL
1208  *   int : offset into packet data where we are.
1209  *   int : length of IDs in packet.
1210  *   int : length of clv we are decoding
1211  *
1212  * Output:
1213  *   void, but we will add to proto tree if !NULL.
1214  */
1215 static void 
1216 dissect_lsp_ext_is_reachability_clv(tvbuff_t *tvb, proto_tree *tree,
1217         int offset, int id_length, int length)
1218 {
1219         proto_item *ti;
1220         proto_tree *ntree = NULL;
1221         guint8     subclvs_len;
1222         guint8     len, i;
1223         guint8     clv_code, clv_len;
1224
1225         if (!tree) return;
1226
1227         while (length > 0) {
1228                 ti = proto_tree_add_text (tree, tvb, offset, -1,
1229                         "IS neighbor: %s",
1230                         print_system_id (tvb_get_ptr(tvb, offset, 7), 7) );
1231                 ntree = proto_item_add_subtree (ti, 
1232                         ett_isis_lsp_part_of_clv_ext_is_reachability );
1233                 
1234                 proto_tree_add_text (ntree, tvb, offset+7, 3,
1235                         "Metric: %d", tvb_get_ntoh24(tvb, offset+7) );
1236
1237                 subclvs_len = tvb_get_guint8(tvb, offset+10);
1238                 if (subclvs_len == 0) {
1239                         proto_tree_add_text (ntree, tvb, offset+10, 1, "no sub-TLVs present");
1240                 }
1241                 else {
1242                         i = 0;
1243                         while (i < subclvs_len) {
1244                                 clv_code = tvb_get_guint8(tvb, offset+11+i);
1245                                 clv_len  = tvb_get_guint8(tvb, offset+12+i);
1246                                 switch (clv_code) {
1247                                 case 3 :
1248                                         dissect_subclv_admin_group(tvb, ntree, offset+13+i);
1249                                         break;
1250                                 case 6 :
1251                                         proto_tree_add_text (ntree, tvb, offset+11+i, 6,
1252                                                 "IPv4 interface address: %s", ip_to_str (tvb_get_ptr(tvb, offset+13+i, 4)) );
1253                                         break;
1254                                 case 8 :
1255                                         proto_tree_add_text (ntree, tvb, offset+11+i, 6,
1256                                                 "IPv4 neighbor address: %s", ip_to_str (tvb_get_ptr(tvb, offset+13+i, 4)) );
1257                                         break;
1258                                 case 9 :
1259                                         dissect_subclv_max_bw (tvb, ntree, offset+13+i);
1260                                         break;
1261                                 case 10:
1262                                         dissect_subclv_rsv_bw (tvb, ntree, offset+13+i);
1263                                         break;
1264                                 case 11:
1265                                         dissect_subclv_unrsv_bw (tvb, ntree, offset+13+i);
1266                                         break;
1267                                 case 18:
1268                                         proto_tree_add_text (ntree, tvb, offset+11+i, 5,
1269                                                 "Traffic engineering default metric: %d", 
1270                                                 tvb_get_ntoh24(tvb, offset+13+i) );
1271                                         break;
1272                                 case 250:
1273                                 case 251:
1274                                 case 252:
1275                                 case 253:
1276                                 case 254:
1277                                         proto_tree_add_text (ntree, tvb, offset+11+i, clv_len+2,
1278                                                 "Unknown Cisco specific extensions: code %d, length %d",
1279                                                 clv_code, clv_len );
1280                                         break;
1281                                 default :
1282                                         proto_tree_add_text (ntree, tvb, offset+11+i, clv_len+2,
1283                                                 "Unknown sub-CLV: code %d, length %d", clv_code, clv_len );
1284                                         break;
1285                                 }
1286                                 i += clv_len + 2;
1287                         }
1288                 }
1289
1290                 len = 11 + subclvs_len;
1291                 proto_item_set_len (ti, len);
1292                 offset += len;
1293                 length -= len;
1294         }
1295 }
1296
1297 /* MT IS */
1298
1299
1300
1301
1302 static void
1303 dissect_lsp_mt_is_reachability_clv(tvbuff_t *tvb, proto_tree *tree, int offset, 
1304         int id_length, int length)
1305 {
1306         proto_item *ti;
1307         proto_tree *ntree = NULL;
1308         guint8     subclvs_len;
1309         guint8     len;
1310
1311         int  mt_block;
1312         char mt_desc[60]; 
1313
1314         if (!tree) return;
1315
1316         while (length > 0) {
1317
1318               /* fetch two bytes */
1319               mt_block = tvb_get_ntohs(tvb, offset);
1320         
1321               /* mask out the lower 12 bits */
1322               switch(mt_block&0x0fff) {
1323                 case 0:
1324                   strcpy(mt_desc,"IPv4 unicast");
1325                   break;
1326                 case 1:
1327                   strcpy(mt_desc,"In-Band Management");
1328                   break;
1329                 case 2:
1330                   strcpy(mt_desc,"IPv6 unicast");
1331                   break;
1332                 case 3:
1333                   strcpy(mt_desc,"Multicast");
1334                   break;
1335                 case 4095:
1336                   strcpy(mt_desc,"Development, Experimental or Proprietary");
1337                   break;
1338                 default:
1339                   strcpy(mt_desc,"Reserved for IETF Consensus");
1340               }
1341
1342                 proto_tree_add_text ( tree, tvb, offset, 2 ,
1343                         "%s Topology (0x%x)",
1344                                       mt_desc,
1345                                       mt_block&0xfff ); 
1346
1347                 ti = proto_tree_add_text (tree, tvb, offset+2, -1,
1348                         "IS neighbor: %s",
1349                         print_system_id(tvb_get_ptr(tvb, offset+2, 7), 7) );
1350               
1351                 ntree = proto_item_add_subtree (ti, 
1352                         ett_isis_lsp_part_of_clv_mt_is );
1353                 
1354                 proto_tree_add_text (ntree, tvb, offset+9, 3,
1355                         "Metric: %d", tvb_get_ntoh24(tvb, offset+9) );
1356
1357                 subclvs_len = tvb_get_guint8(tvb, offset+12);
1358                 if (subclvs_len == 0) {
1359                         proto_tree_add_text (ntree, tvb, offset+12, 1, "no sub-TLVs present");
1360                 } else {
1361                   proto_tree_add_text (ntree, tvb, offset+12, 1, "sub-TLVs present");
1362                     }
1363                 
1364                 len = 13 + subclvs_len;
1365                 proto_item_set_len (ti, len);
1366                 offset += len;
1367                 length -= len;          
1368                                 
1369         }
1370 }
1371
1372 /*
1373  * Name: dissect_lsp_partition_dis_clv()
1374  *
1375  * Description:
1376  *      This CLV is used to indicate which system is the designated
1377  *      IS for partition repair.  This means just putting out the
1378  *      "id_length"-octet IS.
1379  *
1380  * Input:
1381  *      tvbuff_t * : tvbuffer for packet data
1382  *      proto_tree * : protocol display tree to fill out.  May be NULL
1383  *      int : offset into packet data where we are.
1384  *      int : length of IDs in packet.
1385  *      int : length of clv we are decoding
1386  *
1387  * Output:
1388  *      void, but we will add to proto tree if !NULL.
1389  */
1390 static void 
1391 dissect_lsp_partition_dis_clv(tvbuff_t *tvb, proto_tree *tree, int offset, 
1392         int id_length, int length)
1393 {
1394         if ( length < id_length ) {
1395                 isis_dissect_unknown(tvb, tree, offset,
1396                                 "short lsp partition DIS(%d vs %d)", length,
1397                                 id_length );
1398                 return;
1399         }
1400         /* 
1401          * Gotta build a sub-tree for all our pieces
1402          */
1403         if ( tree ) {
1404                 proto_tree_add_text ( tree, tvb, offset, id_length, 
1405                         "Partition designated L2 IS: %s",
1406                         print_system_id( tvb_get_ptr(tvb, offset, id_length), id_length ) );
1407         }
1408         length -= id_length;
1409         offset += id_length;
1410         if ( length > 0 ){
1411                 isis_dissect_unknown(tvb, tree, offset,
1412                                 "Long lsp partition DIS, %d left over", length );
1413                 return;
1414         }
1415 }
1416
1417 /*
1418  * Name: dissect_lsp_prefix_neighbors_clv()
1419  *
1420  * Description:
1421  *      The prefix CLV describes what other (OSI) networks we can reach
1422  *      and what their cost is.  It is built from a metric block
1423  *      (see dissect_metric) followed by n addresses.
1424  *
1425  * Input:
1426  *      tvbuff_t * : tvbuffer for packet data
1427  *      proto_tree * : protocol display tree to fill out.  May be NULL
1428  *      int : offset into packet data where we are.
1429  *      int : length of IDs in packet.
1430  *      int : length of clv we are decoding
1431  *
1432  * Output:
1433  *      void, but we will add to proto tree if !NULL.
1434  */
1435 static void 
1436 dissect_lsp_prefix_neighbors_clv(tvbuff_t *tvb, proto_tree *tree, int offset, 
1437         int id_length, int length)
1438 {
1439         char *sbuf;
1440         int mylen;
1441
1442         if ( length < 4 ) {
1443                 isis_dissect_unknown(tvb, tree, offset,
1444                         "Short lsp prefix neighbors (%d vs 4)", length );
1445                 return;
1446         }
1447         if ( tree ) {
1448                 dissect_metric (tvb, tree, offset,
1449                         tvb_get_guint8(tvb, offset), "Default", TRUE );
1450                 dissect_metric (tvb, tree, offset+1,
1451                         tvb_get_guint8(tvb, offset+1), "Delay", FALSE );
1452                 dissect_metric (tvb, tree, offset+2,
1453                         tvb_get_guint8(tvb, offset+2), "Expense", FALSE );
1454                 dissect_metric (tvb, tree, offset+3,
1455                         tvb_get_guint8(tvb, offset+3), "Error", FALSE );
1456         }
1457         offset += 4;
1458         length -= 4;
1459         while ( length > 0 ) {
1460                 mylen = tvb_get_guint8(tvb, offset);
1461                 length--;
1462                 if (length<=0) {
1463                         isis_dissect_unknown(tvb, tree, offset,
1464                                 "Zero payload space after length in prefix neighbor" );
1465                         return;
1466                 }
1467                 if ( mylen > length) {
1468                         isis_dissect_unknown(tvb, tree, offset,
1469                                 "Interal length of prefix neighbor too long (%d vs %d)", 
1470                                 mylen, length );
1471                         return;
1472                 }
1473
1474                 /* 
1475                  * Lets turn the area address into "standard" 0000.0000.etc
1476                  * format string.  
1477                  */
1478                 sbuf =  print_area( tvb_get_ptr(tvb, offset+1, mylen), mylen );
1479                 /* and spit it out */
1480                 if ( tree ) {
1481                         proto_tree_add_text ( tree, tvb, offset, mylen + 1, 
1482                                 "Area address (%d): %s", mylen, sbuf );
1483                 }
1484                 offset += mylen + 1;
1485                 length -= mylen;        /* length already adjusted for len fld*/
1486         }
1487 }
1488
1489 /*
1490  * Name: isis_lsp_decode_lsp_id()
1491  *
1492  * Description: 
1493  *      Display a LSP id into the display tree.
1494  *
1495  * Input:
1496  *      tvbuff_t * : tvbuffer for packet data
1497  *      proto_tree * : tree to display into. REQUIRED
1498  *      int : offset into packet data where we are.
1499  *      char * : title string
1500  *      int : length of IDs in packet.
1501  *
1502  * Output:
1503  *      void, but we will add to proto tree
1504  */
1505 void
1506 isis_lsp_decode_lsp_id(tvbuff_t *tvb, proto_tree *tree, int offset,
1507         char *tstr, int id_length)
1508 {
1509         proto_tree_add_text(tree, tvb, offset, id_length + 2,
1510                 "%s: %s.%02x-%02x", tstr,
1511                         print_system_id( tvb_get_ptr(tvb, offset, id_length), id_length ),
1512                         tvb_get_guint8(tvb, offset+id_length),
1513                         tvb_get_guint8(tvb, offset+id_length+1) );
1514 }
1515
1516 /*
1517  * Name: isis_dissect_isis_lsp()
1518  *
1519  * Description:
1520  *      Print out the LSP part of the main header and then call the CLV
1521  *      de-mangler with the right list of valid CLVs.
1522  *
1523  * Input:
1524  *      tvbuff_t * : tvbuffer for packet data
1525  *      proto_tree * : protocol display tree to add to.  May be NULL.
1526  *      int offset : our offset into packet data.
1527  *      int : LSP type, a la packet-isis.h ISIS_TYPE_* values
1528  *      int : header length of packet.
1529  *      int : length of IDs in packet.
1530  *
1531  * Output:
1532  *      void, but we will add to proto tree if !NULL.
1533  */
1534 void 
1535 isis_dissect_isis_lsp(tvbuff_t *tvb, proto_tree *tree, int offset,
1536         int lsp_type, int header_length, int id_length)
1537 {
1538         proto_item      *ti;
1539         proto_tree      *lsp_tree = NULL;
1540         guint16         pdu_length;
1541         char            sbuf[128];
1542         int             inx, q, some, value, len;
1543
1544         if (tree) {
1545                 ti = proto_tree_add_text(tree, tvb, offset, -1,
1546                     PROTO_STRING_LSP);
1547                 lsp_tree = proto_item_add_subtree(ti, ett_isis_lsp);
1548         }
1549
1550         pdu_length = tvb_get_ntohs(tvb, offset);
1551         if (tree) {
1552                 proto_tree_add_uint(lsp_tree, hf_isis_lsp_pdu_length, tvb,
1553                         offset, 2, pdu_length);
1554         }
1555         offset += 2;
1556
1557         if (tree) {
1558                 proto_tree_add_uint(lsp_tree, hf_isis_lsp_remaining_life, tvb,
1559                         offset, 2, tvb_get_ntohs(tvb, offset));
1560         }
1561         offset += 2;
1562
1563         if (tree) {
1564                 isis_lsp_decode_lsp_id(tvb, lsp_tree, offset, 
1565                         "LSP ID", id_length);
1566         }
1567         offset += id_length + 2;
1568
1569         if (tree) {
1570                 proto_tree_add_uint(lsp_tree, hf_isis_lsp_sequence_number, tvb,
1571                         offset, 4, 
1572                         tvb_get_ntohl(tvb, offset));
1573         }
1574         offset += 4;
1575
1576         if (tree) {
1577                 /* XXX -> we could validate the cksum here! */
1578                 proto_tree_add_uint(lsp_tree, hf_isis_lsp_checksum, tvb,
1579                         offset, 2, tvb_get_ntohs(tvb, offset));
1580         }
1581         offset += 2;
1582
1583         if (tree) {
1584                 /*
1585                  * We need to build our type block values. 
1586                  */
1587                 sbuf[0] = 0;
1588                 some = 0;
1589                 value = ISIS_LSP_ATT(tvb_get_guint8(tvb, offset));
1590                 inx = 0;
1591                 for ( q = (1<<ISIS_LSP_ATT_SHIFT); q > 0; q = q >> 1 ){
1592                         if (q & value) { 
1593                                 if (some++) {
1594                                         strcat(sbuf, ", ");
1595                                 }
1596                                 strcat ( sbuf, isis_lsp_attached_bits[inx] );
1597                         }
1598                         inx++;
1599                 }
1600                 if (!some) { 
1601                         strcat ( sbuf, "default-only" );
1602                 }
1603                 proto_tree_add_text(lsp_tree, tvb, offset + 18, 1, 
1604                         "Type block(0x%02x): P:%d, Supported metric(s): %s, OL:%d, istype:%s",
1605                         tvb_get_guint8(tvb, offset),
1606                         ISIS_LSP_PARTITION(tvb_get_guint8(tvb, offset)) ? 1 : 0,
1607                         sbuf,
1608                         ISIS_LSP_HIPPITY(tvb_get_guint8(tvb, offset)) ? 1 : 0,
1609                         val_to_str(ISIS_LSP_IS_TYPE(tvb_get_guint8(tvb, offset)),
1610                                 isis_lsp_istype_vals, "Unknown (0x%x)")
1611                         );
1612         }
1613         offset += 1;
1614
1615         len = pdu_length - header_length;
1616         if (len < 0) {
1617                 isis_dissect_unknown(tvb, tree, offset,
1618                         "packet header length %d went beyond packet",
1619                          header_length );
1620                 return;
1621         }
1622         /*
1623          * Now, we need to decode our CLVs.  We need to pass in
1624          * our list of valid ones!
1625          */
1626         if (lsp_type == ISIS_TYPE_L1_LSP){
1627                 isis_dissect_clvs(tvb, lsp_tree, offset,
1628                         clv_l1_lsp_opts, len, id_length, 
1629                         ett_isis_lsp_clv_unknown );
1630         } else {
1631                 isis_dissect_clvs(tvb, lsp_tree, offset,
1632                         clv_l2_lsp_opts, len, id_length, 
1633                         ett_isis_lsp_clv_unknown );
1634         }
1635 }
1636 /*
1637  * Name: isis_register_lsp()
1638  *
1639  * Description: 
1640  *      Register our protocol sub-sets with protocol manager.
1641  *
1642  * Input: 
1643  *      int : protocol index for the ISIS protocol
1644  *
1645  * Output:
1646  *      void
1647  */
1648 void 
1649 isis_register_lsp(int proto_isis) {
1650         static hf_register_info hf[] = {
1651                 { &hf_isis_lsp_pdu_length,
1652                 { "PDU length",         "isis.lsp.pdu_length", FT_UINT16, 
1653                   BASE_DEC, NULL, 0x0, "", HFILL }},
1654
1655                 { &hf_isis_lsp_remaining_life,
1656                 { "Remaining lifetime", "isis.lsp.remaining_life", FT_UINT16, 
1657                   BASE_DEC, NULL, 0x0, "", HFILL }},
1658
1659                 { &hf_isis_lsp_sequence_number,
1660                 { "Sequence number",           "isis.lsp.sequence_number", 
1661                   FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
1662
1663                 { &hf_isis_lsp_checksum,
1664                 { "Checksum",           "isis.lsp.checksum",FT_UINT16, 
1665                   BASE_HEX, NULL, 0x0, "", HFILL }},
1666
1667                 { &hf_isis_lsp_clv_ipv4_int_addr,
1668                 { "IPv4 interface address", "isis.lsp.clv_ipv4_int_addr", FT_IPv4,
1669                    BASE_NONE, NULL, 0x0, "", HFILL }},
1670
1671                 { &hf_isis_lsp_clv_ipv6_int_addr,
1672                 { "IPv6 interface address", "isis.lsp.clv_ipv6_int_addr", FT_IPv6,
1673                    BASE_NONE, NULL, 0x0, "", HFILL }},
1674
1675                 { &hf_isis_lsp_clv_te_router_id,
1676                 { "Traffic Engineering Router ID", "isis.lsp.clv_te_router_id", FT_IPv4,
1677                    BASE_NONE, NULL, 0x0, "", HFILL }},
1678
1679                 { &hf_isis_lsp_clv_mt,
1680                 { "MT-ID                     ", "isis.lsp.clv_mt",
1681                         FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
1682         };
1683         static gint *ett[] = {
1684                 &ett_isis_lsp,
1685                 &ett_isis_lsp_clv_area_addr,
1686                 &ett_isis_lsp_clv_is_neighbors,
1687                 &ett_isis_lsp_clv_ext_is_reachability, /* CLV 22 */
1688                         &ett_isis_lsp_part_of_clv_ext_is_reachability,
1689                         &ett_isis_lsp_subclv_admin_group,
1690                         &ett_isis_lsp_subclv_unrsv_bw,
1691                 &ett_isis_lsp_clv_unknown,
1692                 &ett_isis_lsp_clv_partition_dis,
1693                 &ett_isis_lsp_clv_prefix_neighbors,
1694                 &ett_isis_lsp_clv_auth,
1695                 &ett_isis_lsp_clv_nlpid,
1696                 &ett_isis_lsp_clv_hostname,
1697                 &ett_isis_lsp_clv_ipv4_int_addr,
1698                 &ett_isis_lsp_clv_ipv6_int_addr, /* CLV 232 */
1699                 &ett_isis_lsp_clv_te_router_id,
1700                 &ett_isis_lsp_clv_ip_reachability,
1701                 &ett_isis_lsp_clv_ext_ip_reachability, /* CLV 135 */
1702                         &ett_isis_lsp_part_of_clv_ext_ip_reachability,
1703                 &ett_isis_lsp_clv_ipv6_reachability, /* CLV 236 */
1704                         &ett_isis_lsp_part_of_clv_ipv6_reachability,
1705                 &ett_isis_lsp_clv_mt,
1706                 &ett_isis_lsp_clv_mt_is,
1707                 &ett_isis_lsp_part_of_clv_mt_is,
1708         };
1709
1710         proto_register_field_array(proto_isis, hf, array_length(hf));
1711         proto_register_subtree_array(ett, array_length(ett));
1712 }