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