Make the "isis_hello.source_id" an FT_BYTES field rather than an
[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.8 2000/06/19 08:33:48 guy Exp $
5  * Stuart Stanley <stuarts@mxmail.net>
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@zing.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * 
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  *
26  *
27  */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
35 #endif
36
37 #include <stdio.h>
38 #include <string.h>
39 #include <glib.h>
40
41 #ifdef HAVE_NET_INET_H
42 #include <net/inet.h>
43 #endif
44
45 #include "packet.h"
46 #include "packet-osi.h"
47 #include "packet-isis.h"
48 #include "packet-isis-clv.h"
49 #include "packet-isis-lsp.h"
50 #include "resolv.h"
51
52 /* lsp packets */
53 static int proto_isis_lsp = -1;
54 static int hf_isis_lsp_pdu_length = -1;
55 static int hf_isis_lsp_remaining_life = -1;
56 static int hf_isis_lsp_sequence_number = -1;
57 static int hf_isis_lsp_checksum = -1;
58 static int hf_isis_lsp_clv_ipv4_int_addr = -1;
59
60 static gint ett_isis_lsp = -1;
61 static gint ett_isis_lsp_clv_area_addr = -1;
62 static gint ett_isis_lsp_clv_is_neighbors = -1;
63 static gint ett_isis_lsp_clv_unknown = -1;
64 static gint ett_isis_lsp_clv_partition_dis = -1;
65 static gint ett_isis_lsp_clv_prefix_neighbors = -1;
66 static gint ett_isis_lsp_clv_nlpid = -1;
67 static gint ett_isis_lsp_clv_auth = -1;
68 static gint ett_isis_lsp_clv_ipv4_int_addr = -1;
69 static gint ett_isis_lsp_clv_ip_reachability = -1;
70
71 static const char *isis_lsp_attached_bits[] = {
72         "error", "expense", "delay", "default" };
73
74 static const value_string isis_lsp_istype_vals[] = {
75         { ISIS_LSP_TYPE_UNUSED0,        "Unused 0x0 (invalid)"},
76         { ISIS_LSP_TYPE_LEVEL_1,        "Level 1 IS"},
77         { ISIS_LSP_TYPE_UNUSED2,        "Unused 0x2 (invalid)"},
78         { ISIS_LSP_TYPE_LEVEL_2,        "Level 2 IS"},
79         { 0, NULL } };
80
81 /* 
82  * Predclare dissectors for use in clv dissection.
83  */
84 static void dissect_lsp_area_address_clv(const u_char *pd, int offset, 
85                 guint length, int id_length, frame_data *fd, proto_tree *tree);
86 static void dissect_lsp_l1_is_neighbors_clv(const u_char *pd, int offset, 
87                 guint length, int id_length, frame_data *fd, proto_tree *tree);
88 static void dissect_lsp_l1_es_neighbors_clv(const u_char *pd, int offset, 
89                 guint length, int id_length, frame_data *fd, proto_tree *tree);
90 static void dissect_lsp_l2_is_neighbors_clv(const u_char *pd, int offset, 
91                 guint length, int id_length, frame_data *fd, proto_tree *tree);
92 static void dissect_lsp_partition_dis_clv(const u_char *pd, int offset, 
93                 guint length, int id_length, frame_data *fd, proto_tree *tree);
94 static void dissect_lsp_prefix_neighbors_clv(const u_char *pd, int offset, 
95                 guint length, int id_length, frame_data *fd, proto_tree *tree);
96 static void dissect_lsp_ip_reachability_clv(const u_char *pd, int offset,
97                 guint length, int id_length, frame_data *fd, proto_tree *tree);
98 static void dissect_lsp_nlpid_clv(const u_char *pd, int offset,
99                 guint length, int id_length, frame_data *fd, proto_tree *tree);
100 static void dissect_lsp_ip_int_addr_clv(const u_char *pd, int offset,
101                 guint length, int id_length, frame_data *fd, proto_tree *tree);
102 static void dissect_lsp_l1_auth_clv(const u_char *pd, int offset,
103                 guint length, int id_length, frame_data *fd, proto_tree *tree);
104 static void dissect_lsp_l2_auth_clv(const u_char *pd, int offset,
105                 guint length, int id_length, frame_data *fd, proto_tree *tree);
106
107 static const isis_clv_handle_t clv_l1_lsp_opts[] = {
108         {
109                 ISIS_CLV_L1_LSP_AREA_ADDRESS,
110                 "Area address(es)",
111                 &ett_isis_lsp_clv_area_addr,
112                 dissect_lsp_area_address_clv
113         },
114         {
115                 ISIS_CLV_L1_LSP_IS_NEIGHBORS,
116                 "IS Neighbor(s)",
117                 &ett_isis_lsp_clv_is_neighbors,
118                 dissect_lsp_l1_is_neighbors_clv
119         },
120         {
121                 ISIS_CLV_L1_LSP_ES_NEIGHBORS,
122                 "ES Neighbor(s)",
123                 &ett_isis_lsp_clv_is_neighbors,
124                 dissect_lsp_l1_es_neighbors_clv
125         },
126         {
127                 ISIS_CLV_L1_LSP_IP_INT_REACHABLE,
128                 "IP Internal reachability",
129                 &ett_isis_lsp_clv_ip_reachability,
130                 dissect_lsp_ip_reachability_clv
131         },
132         {
133                 ISIS_CLV_L1_LSP_NLPID,
134                 "NLPID",
135                 &ett_isis_lsp_clv_nlpid,
136                 dissect_lsp_nlpid_clv
137         },
138         {
139                 ISIS_CLV_L1_LSP_IP_INTERFACE_ADDR,
140                 "IP Interface address(es)",
141                 &ett_isis_lsp_clv_ipv4_int_addr,
142                 dissect_lsp_ip_int_addr_clv
143         },
144         {
145                 ISIS_CLV_L1_LSP_AUTHENTICATION_NS,
146                 "Authentication(non-spec)",
147                 &ett_isis_lsp_clv_auth,
148                 dissect_lsp_l1_auth_clv
149         },
150         {
151                 ISIS_CLV_L1_LSP_AUTHENTICATION,
152                 "Authentication",
153                 &ett_isis_lsp_clv_auth,
154                 dissect_lsp_l1_auth_clv
155         },
156         {
157                 0,
158                 "",
159                 NULL,
160                 NULL
161         }
162 };
163
164 static const isis_clv_handle_t clv_l2_lsp_opts[] = {
165         {
166                 ISIS_CLV_L1_LSP_AREA_ADDRESS,
167                 "Area address(es)",
168                 &ett_isis_lsp_clv_area_addr,
169                 dissect_lsp_area_address_clv
170         },
171         {
172                 ISIS_CLV_L2_LSP_IS_NEIGHBORS,
173                 "IS Neighbor(s)",
174                 &ett_isis_lsp_clv_is_neighbors,
175                 dissect_lsp_l2_is_neighbors_clv
176         },
177         {
178                 ISIS_CLV_L2_LSP_PARTITION_DIS,
179                 "Parition Designated Level 2 IS",
180                 &ett_isis_lsp_clv_partition_dis,
181                 dissect_lsp_partition_dis_clv
182         },
183         {
184                 ISIS_CLV_L2_LSP_PREFIX_NEIGHBORS,
185                 "Prefix neighbors",
186                 &ett_isis_lsp_clv_prefix_neighbors,
187                 dissect_lsp_prefix_neighbors_clv
188         },
189         {
190                 ISIS_CLV_L2_LSP_IP_INT_REACHABLE,
191                 "IP Internal reachability",
192                 &ett_isis_lsp_clv_ip_reachability,
193                 dissect_lsp_ip_reachability_clv
194         },
195         {
196                 ISIS_CLV_L2_LSP_NLPID,
197                 "NLPID",
198                 &ett_isis_lsp_clv_nlpid,
199                 dissect_lsp_nlpid_clv
200         },
201         {
202                 ISIS_CLV_L2_LSP_IP_EXT_REACHABLE,
203                 "IP external reachability",
204                 &ett_isis_lsp_clv_ip_reachability,
205                 dissect_lsp_ip_reachability_clv
206         },
207         {
208                 ISIS_CLV_L2_LSP_IP_INTERFACE_ADDR,
209                 "IP Interface address(es)",
210                 &ett_isis_lsp_clv_ipv4_int_addr,
211                 dissect_lsp_ip_int_addr_clv
212         },
213         {
214                 ISIS_CLV_L2_LSP_AUTHENTICATION_NS,
215                 "Authentication(non spec)",
216                 &ett_isis_lsp_clv_auth,
217                 dissect_lsp_l2_auth_clv
218         },
219         {
220                 ISIS_CLV_L2_LSP_AUTHENTICATION,
221                 "Authentication",
222                 &ett_isis_lsp_clv_auth,
223                 dissect_lsp_l2_auth_clv
224         },
225         {
226                 0,
227                 "",
228                 NULL,
229                 NULL
230         }
231 };
232
233
234 /*
235  * Name: dissect_metric()
236  * 
237  * Description:
238  *      Display a metric prefix portion.  ISIS has the concept of multple
239  *      metric per prefix (default, delay, expense, and error).  This
240  *      routine assists other dissectors by adding a single one of
241  *      these to the display tree..  
242  *
243  *      The 8th(msbit) bit in the metric octet is the "supported" bit.  The
244  *              "default" support is required, so we support a "force_supported"
245  *              flag that tells us that it MUST be zero (zero==supported,
246  *              so it really should be a "not supported" in the boolean sense)
247  *              and to display a protocol failure accordingly.  Notably,
248  *              Cisco IOS 12(6) blows this!
249  *      The 7th bit must be zero (reserved).
250  *
251  * Input:
252  *      u_char * : packet data
253  *      int : offset into packet data where we are.
254  *      guint : length of clv we are decoding
255  *      frame_data * : frame data (complete frame)
256  *      proto_tree * : protocol display tree to fill out.  May be NULL
257  *      int : force supported.  True is the supported bit MUST be zero.
258  * 
259  * Output:
260  *      void, but we will add to proto tree if !NULL.
261  */
262 static void 
263 dissect_metric(proto_tree *tree, int offset, guint8 value, 
264                 char *pstr, int force_supported ) {
265         int s;
266
267         if ( !tree ) return;
268
269         s = ISIS_LSP_CLV_METRIC_SUPPORTED(value);
270         proto_tree_add_text ( tree, NullTVB, offset, 1, 
271                 "%s Metric: %s%s %s%d:%d", pstr,
272                 s ? "Not supported" : "Supported",
273                 (s && force_supported) ? "(but is required to be)":"",
274                 ISIS_LSP_CLV_METRIC_RESERVED(value) ? "(reserved bit != 0)":"",
275                 ISIS_LSP_CLV_METRIC_VALUE(value), value );
276 }
277         
278
279 /*
280  * Name: dissect_lsp_ip_reachabillityclv()
281  *
282  * Description:
283  *      Decode an IP reachability CLV.  This can be either internal or
284  *      external (the clv format does not change and which type we are
285  *      displaying is put there by the dispatcher).  All of these
286  *      are a metric block followed by an IP addr and mask.
287  *
288  * Input:
289  *      u_char * : packet data
290  *      int : current offset into packet data
291  *      guint : length of this clv
292  *      int : length of IDs in packet.
293  *      frame_data * : frame data
294  *      proto_tree * : proto tree to build on (may be null)
295  *
296  * Output:
297  *      void, will modify proto_tree if not null.
298  */
299 static void 
300 dissect_lsp_ip_reachability_clv(const u_char *pd, int offset, 
301                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
302         proto_item      *ti;
303         proto_tree      *ntree = NULL;
304         guint32         src, mask;
305
306         while ( length > 0 ) {
307                 if (length<12) {
308                         isis_dissect_unknown(offset, length, tree, fd,
309                                 "short IP reachability (%d vs 12)", length );
310                         return;
311                 }
312                 /* 
313                  * Gotta build a sub-tree for all our pieces
314                  */
315                 if ( tree ) {
316                         memcpy(&src, &pd[offset+4], 4);
317                         memcpy(&mask, &pd[offset+8], 4);
318                         ti = proto_tree_add_text ( tree, NullTVB, offset, 12, 
319                                 "IP prefix: %s (%s) : %s",
320                                 get_hostname(src), ip_to_str((guint8*)&src),
321                                 ip_to_str((guint8*)&mask) );
322                         ntree = proto_item_add_subtree(ti, 
323                                 ett_isis_lsp_clv_ip_reachability);
324                         dissect_metric ( ntree, offset, pd[offset], "Default", 
325                                 TRUE );
326                         dissect_metric ( ntree, offset + 1, pd[offset+1], 
327                                 "Delay", FALSE );
328                         dissect_metric ( ntree, offset + 2, pd[offset+2], 
329                                 "Expense",FALSE );
330                         dissect_metric ( ntree, offset + 3, pd[offset+3], 
331                                 "Error", FALSE );
332                 }
333                 offset += 12;
334                 length -= 12;
335         }
336 }
337 /*
338  * Name: dissect_lsp_nlpid_clv()
339  *
340  * Description:
341  *      Decode for a lsp packets NLPID clv.  Calls into the
342  *      clv common one.
343  *
344  * Input:
345  *      u_char * : packet data
346  *      int : current offset into packet data
347  *      guint : length of this clv
348  *      int : length of IDs in packet.
349  *      frame_data * : frame data
350  *      proto_tree * : proto tree to build on (may be null)
351  *
352  * Output:
353  *      void, will modify proto_tree if not null.
354  */
355 static void 
356 dissect_lsp_nlpid_clv(const u_char *pd, int offset, 
357                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
358         isis_dissect_nlpid_clv(pd, offset, length, fd, tree );
359 }
360
361 /*
362  * Name: dissect_lsp_ip_int_addr_clv()
363  *
364  * Description:
365  *      Decode for a lsp packets ip interface addr clv.  Calls into the
366  *      clv common one.
367  *
368  * Input:
369  *      u_char * : packet data
370  *      int : current offset into packet data
371  *      guint : length of this clv
372  *      int : length of IDs in packet.
373  *      frame_data * : frame data
374  *      proto_tree * : proto tree to build on (may be null)
375  *
376  * Output:
377  *      void, will modify proto_tree if not null.
378  */
379 static void 
380 dissect_lsp_ip_int_addr_clv(const u_char *pd, int offset, 
381                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
382         isis_dissect_ip_int_clv(pd, offset, length, fd, tree, 
383                 hf_isis_lsp_clv_ipv4_int_addr );
384 }
385
386 /*
387  * Name: dissect_lsp_L1_auth_clv()
388  *
389  * Description:
390  *      Decode for a lsp packets authenticaion clv.  Calls into the
391  *      clv common one.  An auth inside a L1 LSP is a per area password
392  *
393  * Input:
394  *      u_char * : packet data
395  *      int : current offset into packet data
396  *      guint : length of this clv
397  *      int : length of IDs in packet.
398  *      frame_data * : frame data
399  *      proto_tree * : proto tree to build on (may be null)
400  *
401  * Output:
402  *      void, will modify proto_tree if not null.
403  */
404 static void 
405 dissect_lsp_l1_auth_clv(const u_char *pd, int offset, 
406                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
407         isis_dissect_authentication_clv(pd, offset, length, fd, tree, 
408                 "Per area authentication" );
409 }
410
411 /*
412  * Name: dissect_lsp_L2_auth_clv()
413  *
414  * Description:
415  *      Decode for a lsp packets authenticaion clv.  Calls into the
416  *      clv common one.  An auth inside a L2 LSP is a per domain password
417  *
418  * Input:
419  *      u_char * : packet data
420  *      int : current offset into packet data
421  *      guint : length of this clv
422  *      int : length of IDs in packet.
423  *      frame_data * : frame data
424  *      proto_tree * : proto tree to build on (may be null)
425  *
426  * Output:
427  *      void, will modify proto_tree if not null.
428  */
429 static void 
430 dissect_lsp_l2_auth_clv(const u_char *pd, int offset, 
431                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
432         isis_dissect_authentication_clv(pd, offset, length, fd, tree, 
433                 "Per domain authentication" );
434 }
435
436 /*
437  * Name: dissect_lsp_area_address_clv()
438  *
439  * Description:
440  *      Decode for a lsp packet's area address clv.  Call into clv common
441  *      one.
442  *
443  * Input:
444  *      u_char * : packet data
445  *      int : offset into packet data where we are.
446  *      guint : length of clv we are decoding
447  *      int : length of IDs in packet.
448  *      frame_data * : frame data (complete frame)
449  *      proto_tree * : protocol display tree to fill out.  May be NULL
450  *
451  * Output:
452  *      void, but we will add to proto tree if !NULL.
453  */
454 static void 
455 dissect_lsp_area_address_clv(const u_char *pd, int offset, 
456                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
457         isis_dissect_area_address_clv(pd, offset, length, fd, tree );
458 }
459
460 /*
461  * Name: dissect_lsp_eis_neighbors_clv_inner()
462  *
463  * Description:
464  *      Real work horse for showing neighbors.  This means we decode the
465  *      first octet as either virtual/!virtual (if show_virtual param is
466  *      set), or as a must == 0 reserved value.
467  *
468  *      Once past that, we decode n neighbor elements.  Each neighbor
469  *      is comprised of a metric block (is dissect_metric) and the
470  *      addresses.
471  *
472  * Input:
473  *      u_char * : packet data
474  *      int : offset into packet data where we are.
475  *      guint : length of clv we are decoding
476  *      int : length of IDs in packet.
477  *      frame_data * : frame data (complete frame)
478  *      proto_tree * : protocol display tree to fill out.  May be NULL
479  *      int : set to decode first octet as virtual vs reserved == 0
480  *      int : set to indicate EIS instead of IS (6 octet per addr instead of 7)
481  *
482  * Output:
483  *      void, but we will add to proto tree if !NULL.
484  */
485 static void 
486 dissect_lsp_eis_neighbors_clv_inner(const u_char *pd, int offset, 
487                 guint length, int id_length, frame_data *fd, proto_tree *tree,
488                 int show_virtual, int is_eis) {
489         proto_item      *ti;
490         proto_tree      *ntree = NULL;
491         int             tlen;
492
493         if (!is_eis) {
494                 id_length++;    /* IDs are one octet longer in IS neighbours */
495                 if ( tree ) {
496                         if ( show_virtual ) {
497                                 /* virtual path flag */
498                                 proto_tree_add_text ( tree, NullTVB, offset, 1, 
499                                    &pd[offset] ? "IsNotVirtual" : "IsVirtual" );
500                         } else {
501                                 proto_tree_add_text ( tree, NullTVB, offset, 1, 
502                                         "Reserved value 0x%02x, must == 0",
503                                         pd[offset]  );
504                         }
505                 }
506                 offset++;
507                 length--;
508         }
509         tlen = 4 + id_length;
510
511         while ( length > 0 ) {
512                 if (length<tlen) {
513                         isis_dissect_unknown(offset, length, tree, fd,
514                                 "short E/IS reachability (%d vs %d)", length,
515                                 tlen );
516                         return;
517                 }
518                 /* 
519                  * Gotta build a sub-tree for all our pieces
520                  */
521                 if ( tree ) {
522                         if ( is_eis ) {
523                                 ti = proto_tree_add_text ( tree, NullTVB, offset, tlen, 
524                                         "ES Neighbor: %s",
525                                 print_system_id( pd + offset + 4, id_length ) );
526                         } else {
527                                 ti = proto_tree_add_text ( tree, NullTVB, offset, tlen, 
528                                         "IS Neighbor:  %s",
529                                 print_system_id( pd + offset + 4, id_length ) );
530                         }
531                         ntree = proto_item_add_subtree(ti, 
532                                 ett_isis_lsp_clv_is_neighbors);
533                         dissect_metric ( ntree, offset, pd[offset], "Default", 
534                                 TRUE );
535                         dissect_metric ( ntree, offset + 1, pd[offset+1], 
536                                 "Delay", FALSE );
537                         dissect_metric ( ntree, offset + 2, pd[offset+2], 
538                                 "Expense",FALSE );
539                         dissect_metric ( ntree, offset + 3, pd[offset+3], 
540                                 "Error", FALSE );
541                         proto_tree_add_text ( ntree, NullTVB, offset + 4, id_length, 
542                                 "Neighbour ID: %s",
543                                 print_system_id( pd + offset + 4, id_length ) );
544                 }
545                 offset += tlen;
546                 length -= tlen;
547         }
548 }
549
550 /*
551  * Name: dissect_lsp_l1_is_neighbors_clv()
552  *
553  * Description:
554  *      Dispatch a l1 intermediate system neighbor by calling
555  *      the inner function with show virtual set to TRUE and is es set to FALSE.
556  *
557  * Input:
558  *      u_char * : packet data
559  *      int : offset into packet data where we are.
560  *      guint : length of clv we are decoding
561  *      int : length of IDs in packet.
562  *      frame_data * : frame data (complete frame)
563  *      proto_tree * : protocol display tree to fill out.  May be NULL
564  *
565  * Output:
566  *      void, but we will add to proto tree if !NULL.
567  */
568 static void 
569 dissect_lsp_l1_is_neighbors_clv(const u_char *pd, int offset, 
570                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
571         dissect_lsp_eis_neighbors_clv_inner( pd, offset, length, id_length,
572                 fd, tree, TRUE, FALSE );
573 }
574
575 /*
576  * Name: dissect_lsp_l1_es_neighbors_clv()
577  *
578  * Description:
579  *      Dispatch a l1 end or intermediate system neighbor by calling
580  *      the inner function with show virtual set to TRUE and es set to TRUE.
581  *
582  * Input:
583  *      u_char * : packet data
584  *      int : offset into packet data where we are.
585  *      guint : length of clv we are decoding
586  *      int : length of IDs in packet.
587  *      frame_data * : frame data (complete frame)
588  *      proto_tree * : protocol display tree to fill out.  May be NULL
589  *
590  * Output:
591  *      void, but we will add to proto tree if !NULL.
592  */
593 static void 
594 dissect_lsp_l1_es_neighbors_clv(const u_char *pd, int offset, 
595                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
596         dissect_lsp_eis_neighbors_clv_inner( pd, offset, length, id_length,
597                 fd, tree, TRUE, TRUE);
598 }
599
600 /*
601  * Name: dissect_lsp_l2_is_neighbors_clv()
602  *
603  * Description:
604  *      Dispatch a l2 intermediate system neighbor by calling
605  *      the inner function with show virtual set to FALSE, and is es set
606  *      to FALSE
607  *
608  * Input:
609  *      u_char * : packet data
610  *      int : offset into packet data where we are.
611  *      guint : length of clv we are decoding
612  *      int : length of IDs in packet.
613  *      frame_data * : frame data (complete frame)
614  *      proto_tree * : protocol display tree to fill out.  May be NULL
615  *
616  * Output:
617  *      void, but we will add to proto tree if !NULL.
618  */
619 static void 
620 dissect_lsp_l2_is_neighbors_clv(const u_char *pd, int offset, 
621                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
622         dissect_lsp_eis_neighbors_clv_inner(pd, offset, length, id_length,
623                 fd, tree, FALSE, FALSE);
624 }
625
626 /*
627  * Name: dissect_lsp_partition_dis_clv()
628  *
629  * Description:
630  *      This CLV is used to indicate which system is the designated
631  *      IS for partition repair.  This means just putting out the
632  *      "id_length"-octet IS.
633  *
634  * Input:
635  *      u_char * : packet data
636  *      int : offset into packet data where we are.
637  *      guint : length of clv we are decoding
638  *      int : length of IDs in packet.
639  *      frame_data * : frame data (complete frame)
640  *      proto_tree * : protocol display tree to fill out.  May be NULL
641  *
642  * Output:
643  *      void, but we will add to proto tree if !NULL.
644  */
645 static void 
646 dissect_lsp_partition_dis_clv(const u_char *pd, int offset, 
647                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
648
649         if ( length < id_length ) {
650                 isis_dissect_unknown(offset, length, tree, fd,
651                                 "short lsp parition DIS(%d vs %d)", length,
652                                 id_length );
653                 return;
654         }
655         /* 
656          * Gotta build a sub-tree for all our pieces
657          */
658         if ( tree ) {
659                 proto_tree_add_text ( tree, NullTVB, offset, id_length, 
660                         "Partition designated L2 IS: %s",
661                         print_system_id( pd + offset, id_length ) );
662         }
663         length -= id_length;
664         offset += id_length;
665         if ( length > 0 ){
666                 isis_dissect_unknown(offset, length, tree, fd,
667                                 "Long lsp parition DIS, %d left over", length );
668                 return;
669         }
670 }
671
672 /*
673  * Name: dissect_lsp_prefix_neighbors_clv()
674  *
675  * Description:
676  *      The prefix CLV describes what other (OSI) networks we can reach
677  *      and what their cost is.  It is built from a metric block
678  *      (see dissect_metric) followed by n addresses.
679  *
680  * Input:
681  *      u_char * : packet data
682  *      int : offset into packet data where we are.
683  *      guint : length of clv we are decoding
684  *      int : length of IDs in packet.
685  *      frame_data * : frame data (complete frame)
686  *      proto_tree * : protocol display tree to fill out.  May be NULL
687  *
688  * Output:
689  *      void, but we will add to proto tree if !NULL.
690  */
691 static void 
692 dissect_lsp_prefix_neighbors_clv(const u_char *pd, int offset, 
693                 guint length, int id_length, frame_data *fd, proto_tree *tree) {
694         char *sbuf;
695         int mylen;
696
697         if ( length < 4 ) {
698                 isis_dissect_unknown(offset, length, tree, fd,
699                         "Short lsp prefix neighbors (%d vs 4)", length );
700                 return;
701         }
702         if ( tree ) {
703                 dissect_metric ( tree, offset, pd[offset], "Default", TRUE );
704                 dissect_metric ( tree, offset + 1, pd[offset+1], 
705                         "Delay", FALSE );
706                 dissect_metric ( tree, offset + 2, pd[offset+2], 
707                         "Expense", FALSE );
708                 dissect_metric ( tree, offset + 3, pd[offset+3], 
709                         "Error", FALSE );
710         }
711         offset += 4;
712         length -= 4;
713         while ( length > 0 ) {
714                 mylen = pd[offset];
715                 length--;
716                 if (length<=0) {
717                         isis_dissect_unknown(offset, length, tree, fd,
718                                 "Zero payload space after length in prefix neighbor" );
719                         return;
720                 }
721                 if ( mylen > length) {
722                         isis_dissect_unknown(offset, length, tree, fd,
723                                 "Interal length of prefix neighbor too long (%d vs %d)", 
724                                 mylen, length );
725                         return;
726                 }
727
728                 /* 
729                  * Lets turn the area address into "standard" 0000.0000.etc
730                  * format string.  
731                  */
732                 sbuf =  print_area( pd + offset + 1, mylen );
733                 /* and spit it out */
734                 if ( tree ) {
735                         proto_tree_add_text ( tree, NullTVB, offset, mylen + 1, 
736                                 "Area address (%d): %s", mylen, sbuf );
737                 }
738                 offset += mylen + 1;
739                 length -= mylen;        /* length already adjusted for len fld*/
740         }
741 }
742
743 /*
744  * Name: isis_lsp_decode_lsp_id()
745  *
746  * Description: 
747  *      Display a LSP id into the display tree.
748  *
749  * Input:
750  *      char * : title string
751  *      proto_tree * : tree to display into. REQUIRED
752  *      u_char * : packet data
753  *      int : offset into packet data where we are.
754  *      int : length of IDs in packet.
755  *
756  * Output:
757  *      void, but we will add to proto tree
758  */
759 void
760 isis_lsp_decode_lsp_id(char *tstr, proto_tree *tree, const u_char *pd,
761                 int offset, int id_length ) {
762         proto_tree_add_text(tree, NullTVB, offset, id_length + 2,
763                 "%s: %s.%02x-%02x", tstr,
764                         print_system_id( pd + offset, id_length ),
765                         pd[offset + id_length],
766                         pd[offset + id_length + 1] );
767 }
768
769 /*
770  * Name: isis_dissect_isis_lsp()
771  *
772  * Description:
773  *      Print out the LSP part of the main header and then call the CLV
774  *      de-mangler with the right list of valid CLVs.
775  *
776  * Input:
777  *      int : LSP type, a la packet-isis.h ISIS_TYPE_* values
778  *      int : header length of packet.
779  *      int : length of IDs in packet.
780  *      u_char * : packet data
781  *      int offset : our offset into packet data.
782  *      frame_data * : frame data
783  *      proto_tree * : protocol display tree to add to.  May be NULL.
784  *
785  * Output:
786  *      void, but we will add to proto tree if !NULL.
787  */
788 void 
789 isis_dissect_isis_lsp(int lsp_type, int header_length, int id_length,
790                 const u_char *pd, int offset, frame_data *fd, proto_tree *tree){
791         proto_item      *ti;
792         proto_tree      *lsp_tree = NULL;
793         int             hlen;
794         guint16         pdu_length;
795         char            sbuf[128];
796         int             inx, q, some, value, len;
797
798         hlen = 2+2+id_length+2+4+2+1;
799
800         if (!BYTES_ARE_IN_FRAME(offset, hlen)) {
801                 isis_dissect_unknown(offset, hlen, tree, fd,
802                         "not enough capture data for header (%d vs %d)",
803                         hlen, END_OF_FRAME);
804                 return;
805         }
806         
807         if (tree) {
808                 ti = proto_tree_add_item(tree, proto_isis_lsp, NullTVB,
809                         offset, END_OF_FRAME, FALSE);
810                 lsp_tree = proto_item_add_subtree(ti, ett_isis_lsp);
811         }
812
813         pdu_length = pntohs(&pd[offset]);
814         if (tree) {
815                 proto_tree_add_uint(lsp_tree, hf_isis_lsp_pdu_length, NullTVB,
816                         offset, 2, pdu_length);
817         }
818         offset += 2;
819
820         if (tree) {
821                 proto_tree_add_uint(lsp_tree, hf_isis_lsp_remaining_life, NullTVB,
822                         offset, 2, pntohs(&pd[offset]));
823         }
824         offset += 2;
825
826         if (tree) {
827                 isis_lsp_decode_lsp_id("LSP ID", lsp_tree, pd, offset,
828                         id_length );
829         }
830         offset += id_length + 2;
831
832         if (tree) {
833                 proto_tree_add_uint(lsp_tree, hf_isis_lsp_sequence_number, NullTVB,
834                         offset, 4, 
835                         pntohl(&pd[offset]));
836         }
837         offset += 4;
838
839         if (tree) {
840                 /* XXX -> we could validate the cksum here! */
841                 proto_tree_add_uint(lsp_tree, hf_isis_lsp_checksum, NullTVB,
842                         offset, 2, pntohs(&pd[offset]));
843         }
844         offset += 2;
845
846         if (tree) {
847                 /*
848                  * We need to build our type block values. 
849                  */
850                 sbuf[0] = 0;
851                 some = 0;
852                 value = ISIS_LSP_ATT(pd[offset]);
853                 inx = 0;
854                 for ( q = (1<<ISIS_LSP_ATT_SHIFT); q > 0; q = q >> 1 ){
855                         if (q & value) { 
856                                 if (some++) {
857                                         strcat(sbuf, ", ");
858                                 }
859                                 strcat ( sbuf, isis_lsp_attached_bits[inx] );
860                         }
861                         inx++;
862                 }
863                 if (!some) { 
864                         strcat ( sbuf, "<none set!>" );
865                 }
866                 proto_tree_add_text(lsp_tree, NullTVB, offset + 18, 1, 
867                         "Type block(0x%02x): P:%d, Supported metric(s): %s, OL:%d, istype:%s",
868                         pd[offset],
869                         ISIS_LSP_PARTITION(pd[offset]) ? 1 : 0,
870                         sbuf,
871                         ISIS_LSP_HIPPITY(pd[offset]) ? 1 : 0,
872                         val_to_str(ISIS_LSP_IS_TYPE(pd[offset]),
873                                 isis_lsp_istype_vals, "Unknown (0x%x)")
874                         );
875         }
876         offset += 1;
877
878         len = pdu_length - header_length;
879         if (len < 0) {
880                 isis_dissect_unknown(offset, header_length, tree, fd,
881                         "packet header length %d went beyond packet",
882                          header_length );
883                 return;
884         }
885         /*
886          * Now, we need to decode our CLVs.  We need to pass in
887          * our list of valid ones!
888          */
889         if (lsp_type == ISIS_TYPE_L1_LSP){
890                 isis_dissect_clvs ( clv_l1_lsp_opts, len, id_length, pd,
891                         offset, fd, lsp_tree, ett_isis_lsp_clv_unknown );
892         } else {
893                 isis_dissect_clvs ( clv_l2_lsp_opts, len, id_length, pd,
894                         offset, fd, lsp_tree, ett_isis_lsp_clv_unknown );
895         }
896 }
897 /*
898  * Name: proto_register_isis_lsp()
899  *
900  * Description: 
901  *      Register our protocol sub-sets with protocol manager.
902  *      NOTE: this procedure is autolinked by the makefile process that
903  *              builds register.c
904  *
905  * Input:
906  *      u_char * : packet data
907  *      int : offset into packet data where we are.
908  *      guint : length of clv we are decoding
909  *      frame_data * : frame data (complete frame)
910  *      proto_tree * : protocol display tree to fill out.  May be NULL
911  *
912  * Output:
913  *      void, but we will add to proto tree if !NULL.
914  */
915 void 
916 proto_register_isis_lsp(void) {
917         static hf_register_info hf[] = {
918                 { &hf_isis_lsp_pdu_length,
919                 { "PDU length",         "isis_lsp.pdu_length", FT_UINT16, 
920                   BASE_DEC, NULL, 0x0, "" }},
921
922                 { &hf_isis_lsp_remaining_life,
923                 { "Remaining life",     "isis_lsp.remaining_life", FT_UINT16, 
924                   BASE_DEC, NULL, 0x0, "" }},
925
926                 { &hf_isis_lsp_sequence_number,
927                 { "Sequence number",           "isis_lsp.sequence_number", 
928                   FT_UINT32, BASE_HEX, NULL, 0x0, "" }},
929
930                 { &hf_isis_lsp_checksum,
931                 { "Checksum",           "isis_lsp.checksum",FT_UINT16, 
932                   BASE_HEX, NULL, 0x0, "" }},
933
934                 { &hf_isis_lsp_clv_ipv4_int_addr,
935                 { "IPv4 interface address: ", "isis_lsp.clv_ipv4_int_addr", FT_IPv4,
936                    BASE_NONE, NULL, 0x0, "" }},
937         };
938         static gint *ett[] = {
939                 &ett_isis_lsp,
940                 &ett_isis_lsp_clv_area_addr,
941                 &ett_isis_lsp_clv_is_neighbors,
942                 &ett_isis_lsp_clv_unknown,
943                 &ett_isis_lsp_clv_partition_dis,
944                 &ett_isis_lsp_clv_prefix_neighbors,
945                 &ett_isis_lsp_clv_auth,
946                 &ett_isis_lsp_clv_nlpid,
947                 &ett_isis_lsp_clv_ipv4_int_addr,
948                 &ett_isis_lsp_clv_ip_reachability,
949         };
950
951         proto_isis_lsp = proto_register_protocol( PROTO_STRING_LSP, "isis_lsp");
952         proto_register_field_array(proto_isis_lsp, hf, array_length(hf));
953         proto_register_subtree_array(ett, array_length(ett));
954 }