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