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