]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcpdump/print-isoclns.c
This commit was generated by cvs2svn to compensate for changes in r147078,
[FreeBSD/FreeBSD.git] / contrib / tcpdump / print-isoclns.c
1 /*
2  * Copyright (c) 1992, 1993, 1994, 1995, 1996
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that: (1) source code distributions
7  * retain the above copyright notice and this paragraph in its entirety, (2)
8  * distributions including binary code include the above copyright notice and
9  * this paragraph in its entirety in the documentation or other materials
10  * provided with the distribution, and (3) all advertising materials mentioning
11  * features or use of this software display the following acknowledgement:
12  * ``This product includes software developed by the University of California,
13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14  * the University nor the names of its contributors may be used to endorse
15  * or promote products derived from this software without specific prior
16  * written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  *
21  * Original code by Matt Thomas, Digital Equipment Corporation
22  *
23  * Extensively modified by Hannes Gredler (hannes@juniper.net) for more
24  * complete IS-IS & CLNP support.
25  *
26  * $FreeBSD$
27  */
28
29 #ifndef lint
30 static const char rcsid[] _U_ =
31     "@(#) $Header: /tcpdump/master/tcpdump/print-isoclns.c,v 1.133 2005/04/06 21:32:40 mcr Exp $ (LBL)";
32 #endif
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include <tcpdump-stdinc.h>
39
40 #include <stdio.h>
41 #include <string.h>
42
43 #include "interface.h"
44 #include "addrtoname.h"
45 #include "ethertype.h"
46 #include "ether.h"
47 #include "nlpid.h"
48 #include "extract.h"
49 #include "gmpls.h"
50 #include "oui.h"
51
52 #define IPV4            1       /* AFI value */
53 #define IPV6            2       /* AFI value */
54
55 /*
56  * IS-IS is defined in ISO 10589.  Look there for protocol definitions.
57  */
58
59 #define SYSTEM_ID_LEN   ETHER_ADDR_LEN
60 #define NODE_ID_LEN     SYSTEM_ID_LEN+1
61 #define LSP_ID_LEN      SYSTEM_ID_LEN+2
62
63 #define ISIS_VERSION    1
64 #define ESIS_VERSION    1
65 #define CLNP_VERSION    1
66
67 #define ISIS_PDU_TYPE_MASK      0x1F
68 #define ESIS_PDU_TYPE_MASK      0x1F
69 #define CLNP_PDU_TYPE_MASK      0x1F
70 #define CLNP_FLAG_MASK          0xE0
71 #define ISIS_LAN_PRIORITY_MASK  0x7F
72
73 #define ISIS_PDU_L1_LAN_IIH     15
74 #define ISIS_PDU_L2_LAN_IIH     16
75 #define ISIS_PDU_PTP_IIH        17
76 #define ISIS_PDU_L1_LSP         18
77 #define ISIS_PDU_L2_LSP         20
78 #define ISIS_PDU_L1_CSNP        24
79 #define ISIS_PDU_L2_CSNP        25
80 #define ISIS_PDU_L1_PSNP        26
81 #define ISIS_PDU_L2_PSNP        27
82
83 static struct tok isis_pdu_values[] = {
84     { ISIS_PDU_L1_LAN_IIH,       "L1 Lan IIH"},
85     { ISIS_PDU_L2_LAN_IIH,       "L2 Lan IIH"},
86     { ISIS_PDU_PTP_IIH,          "p2p IIH"},
87     { ISIS_PDU_L1_LSP,           "L1 LSP"},
88     { ISIS_PDU_L2_LSP,           "L2 LSP"},
89     { ISIS_PDU_L1_CSNP,          "L1 CSNP"},
90     { ISIS_PDU_L2_CSNP,          "L2 CSNP"},
91     { ISIS_PDU_L1_PSNP,          "L1 PSNP"},
92     { ISIS_PDU_L2_PSNP,          "L2 PSNP"},
93     { 0, NULL}
94 };
95
96 /*
97  * A TLV is a tuple of a type, length and a value and is normally used for
98  * encoding information in all sorts of places.  This is an enumeration of
99  * the well known types.
100  *
101  * list taken from rfc3359 plus some memory from veterans ;-)
102  */
103
104 #define ISIS_TLV_AREA_ADDR           1   /* iso10589 */
105 #define ISIS_TLV_IS_REACH            2   /* iso10589 */
106 #define ISIS_TLV_ESNEIGH             3   /* iso10589 */
107 #define ISIS_TLV_PART_DIS            4   /* iso10589 */
108 #define ISIS_TLV_PREFIX_NEIGH        5   /* iso10589 */
109 #define ISIS_TLV_ISNEIGH             6   /* iso10589 */
110 #define ISIS_TLV_ISNEIGH_VARLEN      7   /* iso10589 */
111 #define ISIS_TLV_PADDING             8   /* iso10589 */
112 #define ISIS_TLV_LSP                 9   /* iso10589 */
113 #define ISIS_TLV_AUTH                10  /* iso10589, rfc3567 */
114 #define ISIS_TLV_CHECKSUM            12  /* rfc3358 */
115 #define ISIS_TLV_LSP_BUFFERSIZE      14  /* iso10589 rev2 */
116 #define ISIS_TLV_EXT_IS_REACH        22  /* draft-ietf-isis-traffic-05 */
117 #define ISIS_TLV_IS_ALIAS_ID         24  /* draft-ietf-isis-ext-lsp-frags-02 */
118 #define ISIS_TLV_DECNET_PHASE4       42
119 #define ISIS_TLV_LUCENT_PRIVATE      66
120 #define ISIS_TLV_INT_IP_REACH        128 /* rfc1195, rfc2966 */
121 #define ISIS_TLV_PROTOCOLS           129 /* rfc1195 */
122 #define ISIS_TLV_EXT_IP_REACH        130 /* rfc1195, rfc2966 */
123 #define ISIS_TLV_IDRP_INFO           131 /* rfc1195 */
124 #define ISIS_TLV_IPADDR              132 /* rfc1195 */
125 #define ISIS_TLV_IPAUTH              133 /* rfc1195 */
126 #define ISIS_TLV_TE_ROUTER_ID        134 /* draft-ietf-isis-traffic-05 */
127 #define ISIS_TLV_EXTD_IP_REACH       135 /* draft-ietf-isis-traffic-05 */
128 #define ISIS_TLV_HOSTNAME            137 /* rfc2763 */
129 #define ISIS_TLV_SHARED_RISK_GROUP   138 /* draft-ietf-isis-gmpls-extensions */
130 #define ISIS_TLV_NORTEL_PRIVATE1     176
131 #define ISIS_TLV_NORTEL_PRIVATE2     177
132 #define ISIS_TLV_RESTART_SIGNALING   211 /* draft-ietf-isis-restart-01 */
133 #define ISIS_TLV_MT_IS_REACH         222 /* draft-ietf-isis-wg-multi-topology-05 */
134 #define ISIS_TLV_MT_SUPPORTED        229 /* draft-ietf-isis-wg-multi-topology-05 */
135 #define ISIS_TLV_IP6ADDR             232 /* draft-ietf-isis-ipv6-02 */
136 #define ISIS_TLV_MT_IP_REACH         235 /* draft-ietf-isis-wg-multi-topology-05 */
137 #define ISIS_TLV_IP6_REACH           236 /* draft-ietf-isis-ipv6-02 */
138 #define ISIS_TLV_MT_IP6_REACH        237 /* draft-ietf-isis-wg-multi-topology-05 */
139 #define ISIS_TLV_PTP_ADJ             240 /* rfc3373 */
140 #define ISIS_TLV_IIH_SEQNR           241 /* draft-shen-isis-iih-sequence-00 */
141 #define ISIS_TLV_VENDOR_PRIVATE      250 /* draft-ietf-isis-experimental-tlv-01 */
142
143 static struct tok isis_tlv_values[] = {
144     { ISIS_TLV_AREA_ADDR,          "Area address(es)"},
145     { ISIS_TLV_IS_REACH,           "IS Reachability"},
146     { ISIS_TLV_ESNEIGH,            "ES Neighbor(s)"},
147     { ISIS_TLV_PART_DIS,           "Partition DIS"},
148     { ISIS_TLV_PREFIX_NEIGH,       "Prefix Neighbors"},
149     { ISIS_TLV_ISNEIGH,            "IS Neighbor(s)"},
150     { ISIS_TLV_ISNEIGH_VARLEN,     "IS Neighbor(s) (variable length)"},
151     { ISIS_TLV_PADDING,            "Padding"},
152     { ISIS_TLV_LSP,                "LSP entries"},
153     { ISIS_TLV_AUTH,               "Authentication"},
154     { ISIS_TLV_CHECKSUM,           "Checksum"},
155     { ISIS_TLV_LSP_BUFFERSIZE,     "LSP Buffersize"},
156     { ISIS_TLV_EXT_IS_REACH,       "Extended IS Reachability"},
157     { ISIS_TLV_IS_ALIAS_ID,        "IS Alias ID"},
158     { ISIS_TLV_DECNET_PHASE4,      "DECnet Phase IV"},
159     { ISIS_TLV_LUCENT_PRIVATE,     "Lucent Proprietary"},
160     { ISIS_TLV_INT_IP_REACH,       "IPv4 Internal Reachability"},
161     { ISIS_TLV_PROTOCOLS,          "Protocols supported"},
162     { ISIS_TLV_EXT_IP_REACH,       "IPv4 External Reachability"},
163     { ISIS_TLV_IDRP_INFO,          "Inter-Domain Information Type"},
164     { ISIS_TLV_IPADDR,             "IPv4 Interface address(es)"},
165     { ISIS_TLV_IPAUTH,             "IPv4 authentication (deprecated)"},
166     { ISIS_TLV_TE_ROUTER_ID,       "Traffic Engineering Router ID"},
167     { ISIS_TLV_EXTD_IP_REACH,      "Extended IPv4 Reachability"},
168     { ISIS_TLV_SHARED_RISK_GROUP,  "Shared Risk Link Group"},
169     { ISIS_TLV_NORTEL_PRIVATE1,    "Nortel Proprietary"},
170     { ISIS_TLV_NORTEL_PRIVATE2,    "Nortel Proprietary"},
171     { ISIS_TLV_HOSTNAME,           "Hostname"},
172     { ISIS_TLV_RESTART_SIGNALING,  "Restart Signaling"},
173     { ISIS_TLV_MT_IS_REACH,        "Multi Topology IS Reachability"},
174     { ISIS_TLV_MT_SUPPORTED,       "Multi Topology"},
175     { ISIS_TLV_IP6ADDR,            "IPv6 Interface address(es)"},
176     { ISIS_TLV_MT_IP_REACH,        "Multi-Topology IPv4 Reachability"},
177     { ISIS_TLV_IP6_REACH,          "IPv6 reachability"},
178     { ISIS_TLV_MT_IP6_REACH,       "Multi-Topology IP6 Reachability"},
179     { ISIS_TLV_PTP_ADJ,            "Point-to-point Adjacency State"},
180     { ISIS_TLV_IIH_SEQNR,          "Hello PDU Sequence Number"},
181     { ISIS_TLV_VENDOR_PRIVATE,     "Vendor Private"},
182     { 0, NULL }
183 };
184
185 #define ESIS_OPTION_PROTOCOLS        129
186 #define ESIS_OPTION_QOS_MAINTENANCE  195 /* iso9542 */
187 #define ESIS_OPTION_SECURITY         197 /* iso9542 */
188 #define ESIS_OPTION_ES_CONF_TIME     198 /* iso9542 */
189 #define ESIS_OPTION_PRIORITY         205 /* iso9542 */
190 #define ESIS_OPTION_ADDRESS_MASK     225 /* iso9542 */
191 #define ESIS_OPTION_SNPA_MASK        226 /* iso9542 */
192
193 static struct tok esis_option_values[] = {
194     { ESIS_OPTION_PROTOCOLS,       "Protocols supported"},
195     { ESIS_OPTION_QOS_MAINTENANCE, "QoS Maintenance" },
196     { ESIS_OPTION_SECURITY,        "Security" },
197     { ESIS_OPTION_ES_CONF_TIME,    "ES Configuration Time" },
198     { ESIS_OPTION_PRIORITY,        "Priority" },
199     { ESIS_OPTION_ADDRESS_MASK,    "Addressk Mask" },
200     { ESIS_OPTION_SNPA_MASK,       "SNPA Mask" },
201     { 0, NULL }
202 };
203
204 #define CLNP_OPTION_DISCARD_REASON   193
205 #define CLNP_OPTION_QOS_MAINTENANCE  195 /* iso8473 */
206 #define CLNP_OPTION_PRIORITY         205 /* iso8473 */
207
208 static struct tok clnp_option_values[] = {
209     { CLNP_OPTION_DISCARD_REASON,  "Discard Reason"},
210     { CLNP_OPTION_PRIORITY,        "Priority"},
211     { CLNP_OPTION_QOS_MAINTENANCE, "QoS Maintenance"},
212     { 0, NULL }
213 };
214
215 static struct tok clnp_option_rfd_class_values[] = {
216     { 0x0, "General"},
217     { 0x8, "Address"},
218     { 0x9, "Source Routeing"},
219     { 0xa, "Lifetime"},
220     { 0xb, "PDU Discarded"},
221     { 0xc, "Reassembly"},
222     { 0, NULL }
223 };
224
225 static struct tok clnp_option_rfd_general_values[] = {
226     { 0x0, "Reason not specified"},
227     { 0x1, "Protocol procedure error"},
228     { 0x2, "Incorrect checksum"},
229     { 0x3, "PDU discarded due to congestion"},
230     { 0x4, "Header syntax error (cannot be parsed)"},
231     { 0x5, "Segmentation needed but not permitted"},
232     { 0x6, "Incomplete PDU received"},
233     { 0x7, "Duplicate option"},
234     { 0, NULL }
235 };
236
237 static struct tok clnp_option_rfd_address_values[] = {
238     { 0x0, "Destination address unreachable"},
239     { 0x1, "Destination address unknown"},
240     { 0, NULL }
241 };
242
243 static struct tok clnp_option_rfd_source_routeing_values[] = {
244     { 0x0, "Unspecified source routeing error"},
245     { 0x1, "Syntax error in source routeing field"},
246     { 0x2, "Unknown address in source routeing field"},
247     { 0x3, "Path not acceptable"},
248     { 0, NULL }
249 };
250
251 static struct tok clnp_option_rfd_lifetime_values[] = {
252     { 0x0, "Lifetime expired while data unit in transit"},
253     { 0x1, "Lifetime expired during reassembly"},
254     { 0, NULL }
255 };
256
257 static struct tok clnp_option_rfd_pdu_discard_values[] = {
258     { 0x0, "Unsupported option not specified"},
259     { 0x1, "Unsupported protocol version"},
260     { 0x2, "Unsupported security option"},
261     { 0x3, "Unsupported source routeing option"},
262     { 0x4, "Unsupported recording of route option"},
263     { 0, NULL }
264 };
265
266 static struct tok clnp_option_rfd_reassembly_values[] = {
267     { 0x0, "Reassembly interference"},
268     { 0, NULL }
269 };
270
271 /* array of 16 error-classes */
272 static struct tok *clnp_option_rfd_error_class[] = {
273     clnp_option_rfd_general_values,
274     NULL,
275     NULL,
276     NULL,
277     NULL,
278     NULL,
279     NULL,
280     NULL,
281     clnp_option_rfd_address_values,
282     clnp_option_rfd_source_routeing_values,
283     clnp_option_rfd_lifetime_values,
284     clnp_option_rfd_pdu_discard_values,
285     clnp_option_rfd_reassembly_values,
286     NULL,
287     NULL,
288     NULL
289 };
290
291
292 #define ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP           3 /* draft-ietf-isis-traffic-05 */
293 #define ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID  4 /* draft-ietf-isis-gmpls-extensions */
294 #define ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID        5 /* draft-ietf-isis-traffic-05 */
295 #define ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR        6 /* draft-ietf-isis-traffic-05 */
296 #define ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR    8 /* draft-ietf-isis-traffic-05 */
297 #define ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW           9 /* draft-ietf-isis-traffic-05 */
298 #define ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW        10 /* draft-ietf-isis-traffic-05 */
299 #define ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW        11 /* draft-ietf-isis-traffic-05 */
300 #define ISIS_SUBTLV_EXT_IS_REACH_DIFFSERV_TE          12 /* draft-ietf-tewg-diff-te-proto-06 */
301 #define ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC            18 /* draft-ietf-isis-traffic-05 */
302 #define ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE 20 /* draft-ietf-isis-gmpls-extensions */
303 #define ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR    21 /* draft-ietf-isis-gmpls-extensions */
304
305 static struct tok isis_ext_is_reach_subtlv_values[] = {
306     { ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP,            "Administrative groups" },
307     { ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID,   "Link Local/Remote Identifier" },
308     { ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID,         "Link Remote Identifier" },
309     { ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR,         "IPv4 interface address" },
310     { ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR,     "IPv4 neighbor address" },
311     { ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW,            "Maximum link bandwidth" },
312     { ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW,          "Reservable link bandwidth" },
313     { ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW,          "Unreserved bandwidth" },
314     { ISIS_SUBTLV_EXT_IS_REACH_DIFFSERV_TE,            "Diffserv TE" },
315     { ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC,              "Traffic Engineering Metric" },
316     { ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE,   "Link Protection Type" },
317     { ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR,      "Interface Switching Capability" },
318     { 250,                                             "Reserved for cisco specific extensions" },
319     { 251,                                             "Reserved for cisco specific extensions" },
320     { 252,                                             "Reserved for cisco specific extensions" },
321     { 253,                                             "Reserved for cisco specific extensions" },
322     { 254,                                             "Reserved for cisco specific extensions" },
323     { 255,                                             "Reserved for future expansion" },
324     { 0, NULL }
325 };
326
327 #define ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32          1 /* draft-ietf-isis-admin-tags-01 */
328 #define ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64          2 /* draft-ietf-isis-admin-tags-01 */
329 #define ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR  117 /* draft-ietf-isis-wg-multi-topology-05 */
330
331 static struct tok isis_ext_ip_reach_subtlv_values[] = {
332     { ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32,           "32-Bit Administrative tag" },
333     { ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64,           "64-Bit Administrative tag" },
334     { ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR,     "Management Prefix Color" },
335     { 0, NULL }
336 };
337
338 #define ISIS_SUBTLV_AUTH_SIMPLE        1
339 #define ISIS_SUBTLV_AUTH_MD5          54
340 #define ISIS_SUBTLV_AUTH_MD5_LEN      16
341 #define ISIS_SUBTLV_AUTH_PRIVATE     255
342
343 static struct tok isis_subtlv_auth_values[] = {
344     { ISIS_SUBTLV_AUTH_SIMPLE,  "simple text password"},
345     { ISIS_SUBTLV_AUTH_MD5,     "HMAC-MD5 password"},
346     { ISIS_SUBTLV_AUTH_PRIVATE, "Routing Domain private password"},
347     { 0, NULL }
348 };
349
350 #define ISIS_SUBTLV_IDRP_RES           0
351 #define ISIS_SUBTLV_IDRP_LOCAL         1
352 #define ISIS_SUBTLV_IDRP_ASN           2
353
354 static struct tok isis_subtlv_idrp_values[] = {
355     { ISIS_SUBTLV_IDRP_RES,         "Reserved"},
356     { ISIS_SUBTLV_IDRP_LOCAL,       "Routing-Domain Specific"},
357     { ISIS_SUBTLV_IDRP_ASN,         "AS Number Tag"},
358     { 0, NULL}
359 };
360
361 #define CLNP_SEGMENT_PART  0x80
362 #define CLNP_MORE_SEGMENTS 0x40
363 #define CLNP_REQUEST_ER    0x20
364
365 static struct tok clnp_flag_values[] = {
366     { CLNP_SEGMENT_PART, "Segmentation permitted"},
367     { CLNP_MORE_SEGMENTS, "more Segments"},
368     { CLNP_REQUEST_ER, "request Error Report"},
369     { 0, NULL}
370 };
371
372 #define ISIS_MASK_LSP_OL_BIT(x)            ((x)&0x4)
373 #define ISIS_MASK_LSP_ISTYPE_BITS(x)       ((x)&0x3)
374 #define ISIS_MASK_LSP_PARTITION_BIT(x)     ((x)&0x80)
375 #define ISIS_MASK_LSP_ATT_BITS(x)          ((x)&0x78)
376 #define ISIS_MASK_LSP_ATT_ERROR_BIT(x)     ((x)&0x40)
377 #define ISIS_MASK_LSP_ATT_EXPENSE_BIT(x)   ((x)&0x20)
378 #define ISIS_MASK_LSP_ATT_DELAY_BIT(x)     ((x)&0x10)
379 #define ISIS_MASK_LSP_ATT_DEFAULT_BIT(x)   ((x)&0x8)
380
381 #define ISIS_MASK_MTID(x)                  ((x)&0x0fff)
382 #define ISIS_MASK_MTFLAGS(x)               ((x)&0xf000)
383
384 static struct tok isis_mt_flag_values[] = {
385     { 0x4000,                  "sub-TLVs present"},
386     { 0x8000,                  "ATT bit set"},
387     { 0, NULL}
388 };
389
390 #define ISIS_MASK_TLV_EXTD_IP_UPDOWN(x)     ((x)&0x80)
391 #define ISIS_MASK_TLV_EXTD_IP_SUBTLV(x)     ((x)&0x40)
392
393 #define ISIS_MASK_TLV_EXTD_IP6_IE(x)        ((x)&0x40)
394 #define ISIS_MASK_TLV_EXTD_IP6_SUBTLV(x)    ((x)&0x20)
395
396 #define ISIS_LSP_TLV_METRIC_SUPPORTED(x)   ((x)&0x80)
397 #define ISIS_LSP_TLV_METRIC_IE(x)          ((x)&0x40)
398 #define ISIS_LSP_TLV_METRIC_UPDOWN(x)      ((x)&0x80)
399 #define ISIS_LSP_TLV_METRIC_VALUE(x)       ((x)&0x3f)
400
401 #define ISIS_MASK_TLV_SHARED_RISK_GROUP(x) ((x)&0x1)
402
403 static struct tok isis_mt_values[] = {
404     { 0,    "IPv4 unicast"},
405     { 1,    "In-Band Management"},
406     { 2,    "IPv6 unicast"},
407     { 3,    "Multicast"},
408     { 4095, "Development, Experimental or Proprietary"},
409     { 0, NULL }
410 };
411
412 static struct tok isis_iih_circuit_type_values[] = {
413     { 1,    "Level 1 only"},
414     { 2,    "Level 2 only"},
415     { 3,    "Level 1, Level 2"},
416     { 0, NULL}
417 };
418
419 #define ISIS_LSP_TYPE_UNUSED0   0
420 #define ISIS_LSP_TYPE_LEVEL_1   1
421 #define ISIS_LSP_TYPE_UNUSED2   2
422 #define ISIS_LSP_TYPE_LEVEL_2   3
423
424 static struct tok isis_lsp_istype_values[] = {
425     { ISIS_LSP_TYPE_UNUSED0,    "Unused 0x0 (invalid)"},
426     { ISIS_LSP_TYPE_LEVEL_1,    "L1 IS"},
427     { ISIS_LSP_TYPE_UNUSED2,    "Unused 0x2 (invalid)"},
428     { ISIS_LSP_TYPE_LEVEL_2,    "L1L2 IS"},
429     { 0, NULL }
430 };
431
432 /*
433  * Katz's point to point adjacency TLV uses codes to tell us the state of
434  * the remote adjacency.  Enumerate them.
435  */
436
437 #define ISIS_PTP_ADJ_UP   0
438 #define ISIS_PTP_ADJ_INIT 1
439 #define ISIS_PTP_ADJ_DOWN 2
440
441 static struct tok isis_ptp_adjancey_values[] = {
442     { ISIS_PTP_ADJ_UP,    "Up" },
443     { ISIS_PTP_ADJ_INIT,  "Initializing" },
444     { ISIS_PTP_ADJ_DOWN,  "Down" },
445     { 0, NULL}
446 };
447
448 struct isis_tlv_ptp_adj {
449     u_int8_t adjacency_state;
450     u_int8_t extd_local_circuit_id[4];
451     u_int8_t neighbor_sysid[SYSTEM_ID_LEN];
452     u_int8_t neighbor_extd_local_circuit_id[4];
453 };
454
455 static int osi_cksum(const u_int8_t *, u_int);
456 static int clnp_print(const u_int8_t *, u_int);
457 static void esis_print(const u_int8_t *, u_int);
458 static int isis_print(const u_int8_t *, u_int);
459
460 struct isis_metric_block {
461     u_int8_t metric_default;
462     u_int8_t metric_delay;
463     u_int8_t metric_expense;
464     u_int8_t metric_error;
465 };
466
467 struct isis_tlv_is_reach {
468     struct isis_metric_block isis_metric_block;
469     u_int8_t neighbor_nodeid[NODE_ID_LEN];
470 };
471
472 struct isis_tlv_es_reach {
473     struct isis_metric_block isis_metric_block;
474     u_int8_t neighbor_sysid[SYSTEM_ID_LEN];
475 };
476
477 struct isis_tlv_ip_reach {
478     struct isis_metric_block isis_metric_block;
479     u_int8_t prefix[4];
480     u_int8_t mask[4];
481 };
482
483 static struct tok isis_is_reach_virtual_values[] = {
484     { 0,    "IsNotVirtual"},
485     { 1,    "IsVirtual"},
486     { 0, NULL }
487 };
488
489 static struct tok isis_restart_flag_values[] = {
490     { 0x1,  "Restart Request"},
491     { 0x2,  "Restart Acknowledgement"},
492     { 0, NULL }
493 };
494
495 struct isis_common_header {
496     u_int8_t nlpid;
497     u_int8_t fixed_len;
498     u_int8_t version;                   /* Protocol version */
499     u_int8_t id_length;
500     u_int8_t pdu_type;                  /* 3 MSbits are reserved */
501     u_int8_t pdu_version;               /* Packet format version */
502     u_int8_t reserved;
503     u_int8_t max_area;
504 };
505
506 struct isis_iih_lan_header {
507     u_int8_t circuit_type;
508     u_int8_t source_id[SYSTEM_ID_LEN];
509     u_int8_t holding_time[2];
510     u_int8_t pdu_len[2];
511     u_int8_t priority;
512     u_int8_t lan_id[NODE_ID_LEN];
513 };
514
515 struct isis_iih_ptp_header {
516     u_int8_t circuit_type;
517     u_int8_t source_id[SYSTEM_ID_LEN];
518     u_int8_t holding_time[2];
519     u_int8_t pdu_len[2];
520     u_int8_t circuit_id;
521 };
522
523 struct isis_lsp_header {
524     u_int8_t pdu_len[2];
525     u_int8_t remaining_lifetime[2];
526     u_int8_t lsp_id[LSP_ID_LEN];
527     u_int8_t sequence_number[4];
528     u_int8_t checksum[2];
529     u_int8_t typeblock;
530 };
531
532 struct isis_csnp_header {
533     u_int8_t pdu_len[2];
534     u_int8_t source_id[NODE_ID_LEN];
535     u_int8_t start_lsp_id[LSP_ID_LEN];
536     u_int8_t end_lsp_id[LSP_ID_LEN];
537 };
538
539 struct isis_psnp_header {
540     u_int8_t pdu_len[2];
541     u_int8_t source_id[NODE_ID_LEN];
542 };
543
544 struct isis_tlv_lsp {
545     u_int8_t remaining_lifetime[2];
546     u_int8_t lsp_id[LSP_ID_LEN];
547     u_int8_t sequence_number[4];
548     u_int8_t checksum[2];
549 };
550
551 #define ISIS_COMMON_HEADER_SIZE (sizeof(struct isis_common_header))
552 #define ISIS_IIH_LAN_HEADER_SIZE (sizeof(struct isis_iih_lan_header))
553 #define ISIS_IIH_PTP_HEADER_SIZE (sizeof(struct isis_iih_ptp_header))
554 #define ISIS_LSP_HEADER_SIZE (sizeof(struct isis_lsp_header))
555 #define ISIS_CSNP_HEADER_SIZE (sizeof(struct isis_csnp_header))
556 #define ISIS_PSNP_HEADER_SIZE (sizeof(struct isis_psnp_header))
557
558 void isoclns_print(const u_int8_t *p, u_int length, u_int caplen)
559 {
560         const struct isis_common_header *header;
561
562         header = (const struct isis_common_header *)p;
563
564         if (caplen <= 1) { /* enough bytes on the wire ? */
565             printf("|OSI");
566             return;
567         }
568
569         if (eflag)
570             printf("OSI NLPID %s (0x%02x): ",
571                    tok2str(nlpid_values,"Unknown",*p),
572                    *p);
573         
574         switch (*p) {
575
576         case NLPID_CLNP:
577                 if (!clnp_print(p, length))
578                         print_unknown_data(p,"\n\t",caplen);
579                 break;
580
581         case NLPID_ESIS:
582                 esis_print(p, length);
583                 return;
584
585         case NLPID_ISIS:
586                 if (!isis_print(p, length))
587                         print_unknown_data(p,"\n\t",caplen);
588                 break;
589
590         case NLPID_NULLNS:
591                 (void)printf(", length: %u", length);
592                 break;
593
594         case NLPID_Q933:
595                 q933_print(p+1, length-1);
596                 break;
597
598         case NLPID_IP:
599                 ip_print(gndo, p+1, length-1);
600                 break;
601
602 #ifdef INET6
603         case NLPID_IP6:
604                 ip6_print(p+1, length-1);
605                 break;
606 #endif
607
608         case NLPID_PPP:
609                 ppp_print(p+1, length-1);
610                 break;
611
612         default:
613                 if (!eflag)
614                     printf("OSI NLPID 0x%02x unknown",*p);
615                 (void)printf(", length: %u", length);
616                 if (caplen > 1)
617                         print_unknown_data(p,"\n\t",caplen);
618                 break;
619         }
620 }
621
622 #define CLNP_PDU_ER      1
623 #define CLNP_PDU_DT     28
624 #define CLNP_PDU_MD     29
625 #define CLNP_PDU_ERQ    30
626 #define CLNP_PDU_ERP    31
627
628 static struct tok clnp_pdu_values[] = {
629     { CLNP_PDU_ER,  "Error Report"},
630     { CLNP_PDU_MD,  "MD"},
631     { CLNP_PDU_DT,  "Data"},
632     { CLNP_PDU_ERQ, "Echo Request"},
633     { CLNP_PDU_ERP, "Echo Response"},
634     { 0, NULL }
635 };
636
637 struct clnp_header_t {
638     u_int8_t nlpid;
639     u_int8_t length_indicator;
640     u_int8_t version;
641     u_int8_t lifetime; /* units of 500ms */
642     u_int8_t type;
643     u_int8_t segment_length[2];
644     u_int8_t cksum[2];
645 };
646
647 struct clnp_segment_header_t {
648     u_int8_t data_unit_id[2];
649     u_int8_t segment_offset[2];
650     u_int8_t total_length[2];
651 };
652
653 /*
654  * clnp_print
655  * Decode CLNP packets.  Return 0 on error.
656  */
657
658 static int clnp_print (const u_int8_t *pptr, u_int length)
659 {
660         const u_int8_t *optr,*source_address,*dest_address;
661         u_int li,source_address_length,dest_address_length, clnp_pdu_type, clnp_flags;
662         const struct clnp_header_t *clnp_header;
663         const struct clnp_segment_header_t *clnp_segment_header;
664         u_int8_t rfd_error_major,rfd_error_minor;
665
666         clnp_header = (const struct clnp_header_t *) pptr;
667         TCHECK(*clnp_header);
668
669         li = clnp_header->length_indicator;
670         optr = pptr;
671
672         if (!eflag)
673             printf("CLNP");
674
675         /*
676          * Sanity checking of the header.
677          */
678
679         if (clnp_header->version != CLNP_VERSION) {
680             printf("version %d packet not supported", clnp_header->version);
681             return (0);
682         }
683
684         /* FIXME further header sanity checking */
685
686         clnp_pdu_type = clnp_header->type & CLNP_PDU_TYPE_MASK;
687         clnp_flags = clnp_header->type & CLNP_FLAG_MASK;
688
689         pptr += sizeof(struct clnp_header_t);
690         li -= sizeof(struct clnp_header_t);
691         dest_address_length = *pptr;
692         dest_address = pptr + 1;
693
694         pptr += (1 + dest_address_length);
695         li -= (1 + dest_address_length);
696         source_address_length = *pptr;
697         source_address = pptr +1;
698
699         pptr += (1 + source_address_length);
700         li -= (1 + source_address_length);
701
702         if (vflag < 1) {
703             printf("%s%s > %s, %s, length %u",
704                    eflag ? "" : ", ",
705                    isonsap_string(source_address, source_address_length),
706                    isonsap_string(dest_address, dest_address_length),
707                    tok2str(clnp_pdu_values,"unknown (%u)",clnp_pdu_type),
708                    length);
709             return (1);
710         }
711         printf("%slength %u",eflag ? "" : ", ",length);
712
713         printf("\n\t%s PDU, hlen: %u, v: %u, lifetime: %u.%us, Segment PDU length: %u, checksum: 0x%04x ",
714                tok2str(clnp_pdu_values, "unknown (%u)",clnp_pdu_type),
715                clnp_header->length_indicator,
716                clnp_header->version,
717                clnp_header->lifetime/2,
718                (clnp_header->lifetime%2)*5,
719                EXTRACT_16BITS(clnp_header->segment_length),
720                EXTRACT_16BITS(clnp_header->cksum));
721
722         /* do not attempt to verify the checksum if it is zero */
723         if (EXTRACT_16BITS(clnp_header->cksum) == 0)
724                 printf("(unverified)");
725             else printf("(%s)", osi_cksum(optr, clnp_header->length_indicator) ? "incorrect" : "correct");
726
727         printf("\n\tFlags [%s]",
728                bittok2str(clnp_flag_values,"none",clnp_flags));
729
730         printf("\n\tsource address (length %u): %s\n\tdest   address (length %u): %s",
731                source_address_length,
732                isonsap_string(source_address, source_address_length),
733                dest_address_length,
734                isonsap_string(dest_address,dest_address_length));
735
736         if (clnp_flags & CLNP_SEGMENT_PART) {
737                 clnp_segment_header = (const struct clnp_segment_header_t *) pptr;
738                 printf("\n\tData Unit ID: 0x%04x, Segment Offset: %u, Total PDU Length: %u",
739                        EXTRACT_16BITS(clnp_segment_header->data_unit_id),
740                        EXTRACT_16BITS(clnp_segment_header->segment_offset),
741                        EXTRACT_16BITS(clnp_segment_header->total_length));
742                 pptr+=sizeof(const struct clnp_segment_header_t);
743                 li-=sizeof(const struct clnp_segment_header_t);
744         }
745
746         /* now walk the options */
747         while (li >= 2) {
748             u_int op, opli;
749             const u_int8_t *tptr;
750             
751             if (snapend - pptr < 2)
752                 return (0);
753             if (li < 2) {
754                 printf(", bad opts/li");
755                 return (0);
756             }
757             op = *pptr++;
758             opli = *pptr++;
759             li -= 2;
760             if (opli > li) {
761                 printf(", opt (%d) too long", op);
762                 return (0);
763             }
764             li -= opli;
765             tptr = pptr;
766             
767             if (snapend < pptr)
768                 return(0);
769             
770             printf("\n\t  %s Option #%u, length %u, value: ",
771                    tok2str(clnp_option_values,"Unknown",op),
772                    op,
773                    opli);
774
775             switch (op) {
776
777             case CLNP_OPTION_PRIORITY:
778                 printf("%u", *tptr);
779                 break;
780
781             case CLNP_OPTION_DISCARD_REASON:
782                 rfd_error_major = (*tptr&0xf0) >> 4;
783                 rfd_error_minor = *tptr&0x0f;
784                 printf("\n\t    Class: %s Error (0x%01x), %s (0x%01x)",
785                        tok2str(clnp_option_rfd_class_values,"Unknown",rfd_error_major),
786                        rfd_error_major,
787                        tok2str(clnp_option_rfd_error_class[rfd_error_major],"Unknown",rfd_error_minor),
788                        rfd_error_minor);
789                 break;
790
791                 /*
792                  * FIXME those are the defined Options that lack a decoder
793                  * you are welcome to contribute code ;-)
794                  */
795
796             default:
797                 print_unknown_data(tptr,"\n\t  ",opli);
798                 break;
799             }
800             if (vflag > 1)
801                 print_unknown_data(pptr,"\n\t  ",opli);
802             pptr += opli;
803         }
804
805         switch (clnp_pdu_type) {
806
807         case    CLNP_PDU_ER: /* fall through */
808         case    CLNP_PDU_ERP:
809             if (*(pptr) == NLPID_CLNP) {
810                 printf("\n\t-----original packet-----\n\t");
811                 /* FIXME recursion protection */
812                 clnp_print(pptr, length-clnp_header->length_indicator);
813                 break;
814             } 
815
816         case    CLNP_PDU_DT:
817         case    CLNP_PDU_MD:
818         case    CLNP_PDU_ERQ:
819             
820         default:
821             /* dump the PDU specific data */
822             if (length-(pptr-optr) > 0) {
823                 printf("\n\t  undecoded non-header data, length %u",length-clnp_header->length_indicator);
824                 print_unknown_data(pptr,"\n\t  ",length-(pptr-optr));
825             }
826         }
827
828         return (1);
829
830  trunc:
831     fputs("[|clnp]", stdout);
832     return (1);
833
834 }
835
836
837 #define ESIS_PDU_REDIRECT       6
838 #define ESIS_PDU_ESH            2
839 #define ESIS_PDU_ISH            4
840
841 static struct tok esis_pdu_values[] = {
842     { ESIS_PDU_REDIRECT, "redirect"},
843     { ESIS_PDU_ESH,      "ESH"},
844     { ESIS_PDU_ISH,      "ISH"},
845     { 0, NULL }
846 };
847
848 struct esis_header_t {
849         u_int8_t nlpid;
850         u_int8_t length_indicator;
851         u_int8_t version;
852         u_int8_t reserved;
853         u_int8_t type;
854         u_int8_t holdtime[2];
855         u_int8_t cksum[2];
856 };
857
858 static void
859 esis_print(const u_int8_t *pptr, u_int length)
860 {
861         const u_int8_t *optr;
862         u_int li,esis_pdu_type,source_address_length, source_address_number;
863         const struct esis_header_t *esis_header;
864
865         if (!eflag)
866             printf("ES-IS");
867
868         if (length <= 2) {
869                 if (qflag)
870                         printf("bad pkt!");
871                 else
872                         printf("no header at all!");
873                 return;
874         }
875
876         esis_header = (const struct esis_header_t *) pptr;
877         li = esis_header->length_indicator;
878         optr = pptr;
879
880         /*
881          * Sanity checking of the header.
882          */
883
884         if (esis_header->nlpid != NLPID_ESIS) {
885             printf(" nlpid 0x%02x packet not supported", esis_header->nlpid);
886             return;
887         }
888
889         if (esis_header->version != ESIS_VERSION) {
890             printf(" version %d packet not supported", esis_header->version);
891             return;
892         }
893                 
894         if (li > length) {
895             printf(" length indicator(%d) > PDU size (%d)!", li, length);
896             return;
897         }
898
899         if (li < sizeof(struct esis_header_t) + 2) {
900             printf(" length indicator < min PDU size %d:", li);
901             while (--length != 0)
902                 printf("%02X", *pptr++);
903             return;
904         }
905
906         esis_pdu_type = esis_header->type & ESIS_PDU_TYPE_MASK;
907
908         if (vflag < 1) {
909             printf("%s%s, length %u",
910                    eflag ? "" : ", ",
911                    tok2str(esis_pdu_values,"unknown type (%u)",esis_pdu_type),
912                    length);
913             return;
914         } else
915             printf("%slength %u\n\t%s (%u)",
916                    eflag ? "" : ", ",
917                    length,
918                    tok2str(esis_pdu_values,"unknown type: %u", esis_pdu_type),
919                    esis_pdu_type);
920
921         printf(", v: %u%s", esis_header->version, esis_header->version == ESIS_VERSION ? "" : "unsupported" );
922         printf(", checksum: 0x%04x ", EXTRACT_16BITS(esis_header->cksum));
923         /* do not attempt to verify the checksum if it is zero */
924         if (EXTRACT_16BITS(esis_header->cksum) == 0)
925                 printf("(unverified)");
926             else printf("(%s)", osi_cksum(pptr, li) ? "incorrect" : "correct");
927
928         printf(", holding time: %us, length indicator: %u",EXTRACT_16BITS(esis_header->holdtime),li);
929
930         if (vflag > 1)
931             print_unknown_data(optr,"\n\t",sizeof(struct esis_header_t));
932
933         pptr += sizeof(struct esis_header_t);
934         li -= sizeof(struct esis_header_t);
935
936         switch (esis_pdu_type) {
937         case ESIS_PDU_REDIRECT: {
938                 const u_int8_t *dst, *snpa, *tptr;
939
940                 dst = pptr; pptr += *pptr + 1;
941                 if (pptr > snapend)
942                         return;
943                 printf("\n\t  %s", isonsap_string(dst+1,*dst));
944                 snpa = pptr; pptr += *pptr + 1;
945                 tptr = pptr;   pptr += *pptr + 1;
946                 if (pptr > snapend)
947                         return;
948
949                 if (tptr[0] == 0)
950                         printf("\n\t  %s", etheraddr_string(&snpa[1]));
951                 else
952                         printf("\n\t  %s", isonsap_string(tptr+1,*tptr));
953                 break;
954         }
955
956         case ESIS_PDU_ESH:
957             source_address_number = *pptr;
958             pptr++;
959             li--;
960
961             printf("\n\t  Number of Source Addresses: %u", source_address_number);
962            
963             while (source_address_number > 0) {
964                 source_address_length = *pptr;
965                 printf("\n\t  NET (length: %u): %s",
966                        source_address_length,
967                        isonsap_string(pptr+1,source_address_length));
968
969                 pptr += source_address_length+1;
970                 li -= source_address_length+1;
971                 source_address_number--;
972             }
973
974             break;
975
976         case ESIS_PDU_ISH: {
977             source_address_length = *pptr;
978             printf("\n\t  NET (length: %u): %s", source_address_length, isonsap_string(pptr+1, source_address_length));
979             pptr += source_address_length+1;
980             li -= source_address_length +1;
981             break;
982         }
983
984         default:
985             if (vflag <= 1) {
986                     if (pptr < snapend) 
987                             print_unknown_data(pptr,"\n\t  ",snapend-pptr);
988             }
989             return;
990         }
991
992         /* now walk the options */
993         while (li >= 2) {
994             u_int op, opli;
995             const u_int8_t *tptr;
996             
997             if (snapend - pptr < 2)
998                 return;
999             if (li < 2) {
1000                 printf(", bad opts/li");
1001                 return;
1002             }
1003             op = *pptr++;
1004             opli = *pptr++;
1005             li -= 2;
1006             if (opli > li) {
1007                 printf(", opt (%d) too long", op);
1008                 return;
1009             }
1010             li -= opli;
1011             tptr = pptr;
1012             
1013             if (snapend < pptr)
1014                 return;
1015             
1016             printf("\n\t  %s Option #%u, length %u, value: ",
1017                    tok2str(esis_option_values,"Unknown",op),
1018                    op,
1019                    opli);
1020
1021             switch (op) {
1022
1023             case ESIS_OPTION_ES_CONF_TIME:
1024                 printf("%us", EXTRACT_16BITS(tptr));
1025                 break;
1026                 
1027
1028             case ESIS_OPTION_PROTOCOLS:
1029                 while (opli>0) {
1030                     printf("%s (0x%02x)",
1031                            tok2str(nlpid_values,
1032                                    "unknown",
1033                                    *tptr),
1034                            *tptr);
1035                     if (opli>1) /* further NPLIDs ? - put comma */
1036                         printf(", ");
1037                     tptr++;
1038                     opli--;
1039                 }
1040                 break;
1041
1042                 /*
1043                  * FIXME those are the defined Options that lack a decoder
1044                  * you are welcome to contribute code ;-)
1045                  */
1046
1047             case ESIS_OPTION_QOS_MAINTENANCE:
1048             case ESIS_OPTION_SECURITY:
1049             case ESIS_OPTION_PRIORITY:
1050             case ESIS_OPTION_ADDRESS_MASK:
1051             case ESIS_OPTION_SNPA_MASK:
1052
1053             default:
1054                 print_unknown_data(tptr,"\n\t  ",opli);
1055                 break;
1056             }
1057             if (vflag > 1)
1058                 print_unknown_data(pptr,"\n\t  ",opli);
1059             pptr += opli;
1060         }
1061 }   
1062
1063 /* shared routine for printing system, node and lsp-ids */
1064 static char *
1065 isis_print_id(const u_int8_t *cp, int id_len)
1066 {
1067     int i;
1068     static char id[sizeof("xxxx.xxxx.xxxx.yy-zz")];
1069     char *pos = id;
1070
1071     for (i = 1; i <= SYSTEM_ID_LEN; i++) {
1072         snprintf(pos, sizeof(id) - (pos - id), "%02x", *cp++);
1073         pos += strlen(pos);
1074         if (i == 2 || i == 4)
1075             *pos++ = '.';
1076         }
1077     if (id_len >= NODE_ID_LEN) {
1078         snprintf(pos, sizeof(id) - (pos - id), ".%02x", *cp++);
1079         pos += strlen(pos);
1080     }
1081     if (id_len == LSP_ID_LEN)
1082         snprintf(pos, sizeof(id) - (pos - id), "-%02x", *cp);
1083     return (id);
1084 }
1085
1086 /* print the 4-byte metric block which is common found in the old-style TLVs */
1087 static int
1088 isis_print_metric_block (const struct isis_metric_block *isis_metric_block)
1089 {
1090     printf(", Default Metric: %d, %s",
1091            ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_default),
1092            ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_default) ? "External" : "Internal");
1093     if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_delay))
1094         printf("\n\t\t  Delay Metric: %d, %s",
1095                ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_delay),
1096                ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_delay) ? "External" : "Internal");
1097     if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_expense))
1098         printf("\n\t\t  Expense Metric: %d, %s",
1099                ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_expense),
1100                ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_expense) ? "External" : "Internal");
1101     if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_error))
1102         printf("\n\t\t  Error Metric: %d, %s",
1103                ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_error),
1104                ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_error) ? "External" : "Internal");
1105
1106     return(1); /* everything is ok */
1107 }
1108
1109 static int
1110 isis_print_tlv_ip_reach (const u_int8_t *cp, const char *ident, int length)
1111 {
1112         int prefix_len;
1113         const struct isis_tlv_ip_reach *tlv_ip_reach;
1114
1115         tlv_ip_reach = (const struct isis_tlv_ip_reach *)cp;
1116
1117         while (length > 0) {
1118                 if ((size_t)length < sizeof(*tlv_ip_reach)) {
1119                         printf("short IPv4 Reachability (%d vs %lu)",
1120                                length,
1121                                (unsigned long)sizeof(*tlv_ip_reach));
1122                         return (0);
1123                 }
1124
1125                 if (!TTEST(*tlv_ip_reach))
1126                     return (0);
1127
1128                 prefix_len = mask2plen(EXTRACT_32BITS(tlv_ip_reach->mask));
1129
1130                 if (prefix_len == -1)
1131                         printf("%sIPv4 prefix: %s mask %s",
1132                                ident,
1133                                ipaddr_string((tlv_ip_reach->prefix)),
1134                                ipaddr_string((tlv_ip_reach->mask)));
1135                 else
1136                         printf("%sIPv4 prefix: %15s/%u",
1137                                ident,
1138                                ipaddr_string((tlv_ip_reach->prefix)),
1139                                prefix_len);
1140
1141                 printf(", Distribution: %s, Metric: %u, %s",
1142                        ISIS_LSP_TLV_METRIC_UPDOWN(tlv_ip_reach->isis_metric_block.metric_default) ? "down" : "up",
1143                        ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_default),
1144                        ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_default) ? "External" : "Internal");
1145
1146                 if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_delay))
1147                     printf("%s  Delay Metric: %u, %s",
1148                            ident,
1149                            ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_delay),
1150                            ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_delay) ? "External" : "Internal");
1151                 
1152                 if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_expense))
1153                     printf("%s  Expense Metric: %u, %s",
1154                            ident,
1155                            ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_expense),
1156                            ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_expense) ? "External" : "Internal");
1157                 
1158                 if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_error))
1159                     printf("%s  Error Metric: %u, %s",
1160                            ident,
1161                            ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_error),
1162                            ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_error) ? "External" : "Internal");
1163
1164                 length -= sizeof(struct isis_tlv_ip_reach);
1165                 tlv_ip_reach++;
1166         }
1167         return (1);
1168 }
1169
1170 /*
1171  * this is the common IP-REACH subTLV decoder it is called
1172  * from various EXTD-IP REACH TLVs (135,235,236,237)
1173  */
1174
1175 static int
1176 isis_print_ip_reach_subtlv (const u_int8_t *tptr,int subt,int subl,const char *ident) {
1177
1178         /* first lets see if we know the subTLVs name*/
1179         printf("%s%s subTLV #%u, length: %u",
1180                ident,
1181                tok2str(isis_ext_ip_reach_subtlv_values,
1182                        "unknown",
1183                        subt),
1184                subt,
1185                subl);
1186
1187         if (!TTEST2(*tptr,subl))
1188             goto trunctlv;
1189
1190     switch(subt) {
1191     case ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR: /* fall through */
1192     case ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32:
1193         while (subl >= 4) {
1194             printf(", 0x%08x (=%u)",
1195                    EXTRACT_32BITS(tptr),
1196                    EXTRACT_32BITS(tptr));
1197             tptr+=4;
1198             subl-=4;
1199         }
1200         break;
1201     case ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64:
1202         while (subl >= 8) {
1203             printf(", 0x%08x%08x",
1204                    EXTRACT_32BITS(tptr),
1205                    EXTRACT_32BITS(tptr+4));
1206             tptr+=8;
1207             subl-=8;
1208         }
1209         break;
1210     default:
1211         if(!print_unknown_data(tptr,"\n\t\t    ",
1212                                subl))
1213           return(0);
1214         break;
1215     }
1216     return(1);
1217         
1218 trunctlv:
1219     printf("%spacket exceeded snapshot",ident);
1220     return(0);
1221 }
1222
1223 /*
1224  * this is the common IS-REACH subTLV decoder it is called
1225  * from isis_print_ext_is_reach()
1226  */
1227
1228 static int
1229 isis_print_is_reach_subtlv (const u_int8_t *tptr,int subt,int subl,const char *ident) {
1230
1231         int priority_level,bandwidth_constraint;
1232         union { /* int to float conversion buffer for several subTLVs */
1233             float f; 
1234             u_int32_t i;
1235         } bw;
1236
1237         /* first lets see if we know the subTLVs name*/
1238         printf("%s%s subTLV #%u, length: %u",
1239                ident,
1240                tok2str(isis_ext_is_reach_subtlv_values,
1241                        "unknown",
1242                        subt),
1243                subt,
1244                subl);
1245
1246         if (!TTEST2(*tptr,subl))
1247             goto trunctlv;
1248
1249         switch(subt) {
1250         case ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP:      
1251         case ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID:
1252         case ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID:
1253             if (subl >= 4) {
1254               printf(", 0x%08x", EXTRACT_32BITS(tptr));
1255               if (subl == 8) /* draft-ietf-isis-gmpls-extensions */
1256                 printf(", 0x%08x", EXTRACT_32BITS(tptr+4));
1257             }
1258             break;
1259         case ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR:
1260         case ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR:
1261             if (subl >= 4)
1262               printf(", %s", ipaddr_string(tptr));
1263             break;
1264         case ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW :
1265         case ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW:  
1266             if (subl >= 4) {
1267               bw.i = EXTRACT_32BITS(tptr);
1268               printf(", %.3f Mbps", bw.f*8/1000000 );
1269             }
1270             break;
1271         case ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW :
1272             if (subl >= 32) {
1273               for (priority_level = 0; priority_level < 8; priority_level++) {
1274                 bw.i = EXTRACT_32BITS(tptr);
1275                 printf("%s  priority level %d: %.3f Mbps",
1276                        ident,
1277                        priority_level,
1278                        bw.f*8/1000000 );
1279                 tptr+=4;
1280               }
1281             }
1282             break;
1283         case ISIS_SUBTLV_EXT_IS_REACH_DIFFSERV_TE:
1284             printf("%sBandwidth Constraints Model ID: %s (%u)",
1285                    ident,
1286                    tok2str(diffserv_te_bc_values, "unknown", *tptr),
1287                    *tptr);
1288             tptr++;
1289             /* decode BCs until the subTLV ends */
1290             for (bandwidth_constraint = 0; bandwidth_constraint < (subl-1)/4; bandwidth_constraint++) {
1291                 bw.i = EXTRACT_32BITS(tptr);
1292                 printf("%s  Bandwidth constraint %d: %.3f Mbps",
1293                        ident,
1294                        bandwidth_constraint,
1295                        bw.f*8/1000000 );
1296                 tptr+=4;
1297             }
1298             break;
1299         case ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC:
1300             if (subl >= 3)
1301               printf(", %u", EXTRACT_24BITS(tptr));
1302             break;
1303         case ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE:
1304             if (subl >= 2) {
1305               printf(", %s, Priority %u",
1306                    bittok2str(gmpls_link_prot_values, "none", *tptr),
1307                    *(tptr+1));
1308             }
1309             break;
1310         case ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR:
1311             if (subl >= 36) {
1312               printf("%s  Interface Switching Capability:%s",
1313                    ident,
1314                    tok2str(gmpls_switch_cap_values, "Unknown", *(tptr)));
1315               printf(", LSP Encoding: %s",
1316                    tok2str(gmpls_encoding_values, "Unknown", *(tptr+1)));
1317               tptr+=4;
1318               printf("%s  Max LSP Bandwidth:",ident);
1319               for (priority_level = 0; priority_level < 8; priority_level++) {
1320                 bw.i = EXTRACT_32BITS(tptr);
1321                 printf("%s    priority level %d: %.3f Mbps",
1322                        ident,
1323                        priority_level,
1324                        bw.f*8/1000000 );
1325                 tptr+=4;
1326               }
1327               subl-=36;
1328               /* there is some optional stuff left to decode but this is as of yet
1329                  not specified so just lets hexdump what is left */
1330               if(subl>0){
1331                 if(!print_unknown_data(tptr,"\n\t\t    ",
1332                                        subl-36))
1333                     return(0);
1334               }
1335             }
1336             break;
1337         default:
1338             if(!print_unknown_data(tptr,"\n\t\t    ",
1339                                    subl))
1340                 return(0);
1341             break;
1342         }
1343         return(1);
1344
1345 trunctlv:
1346     printf("%spacket exceeded snapshot",ident);
1347     return(0);
1348 }
1349
1350
1351 /*
1352  * this is the common IS-REACH decoder it is called
1353  * from various EXTD-IS REACH style TLVs (22,24,222)
1354  */
1355
1356 static int
1357 isis_print_ext_is_reach (const u_int8_t *tptr,const char *ident, int tlv_type) {
1358
1359     char ident_buffer[20];
1360     int subtlv_type,subtlv_len,subtlv_sum_len;
1361     int proc_bytes = 0; /* how many bytes did we process ? */
1362     
1363     if (!TTEST2(*tptr, NODE_ID_LEN))
1364         return(0);
1365
1366     printf("%sIS Neighbor: %s", ident, isis_print_id(tptr, NODE_ID_LEN));
1367     tptr+=(NODE_ID_LEN);
1368
1369     if (tlv_type != ISIS_TLV_IS_ALIAS_ID) { /* the Alias TLV Metric field is implicit 0 */
1370         if (!TTEST2(*tptr, 3))    /* and is therefore skipped */
1371             return(0);
1372         printf(", Metric: %d",EXTRACT_24BITS(tptr));
1373         tptr+=3;
1374     }
1375         
1376     if (!TTEST2(*tptr, 1))
1377         return(0);
1378     subtlv_sum_len=*(tptr++); /* read out subTLV length */
1379     proc_bytes=NODE_ID_LEN+3+1;
1380     printf(", %ssub-TLVs present",subtlv_sum_len ? "" : "no ");
1381     if (subtlv_sum_len) {
1382         printf(" (%u)",subtlv_sum_len);
1383         while (subtlv_sum_len>0) {
1384             if (!TTEST2(*tptr,2))
1385                 return(0);
1386             subtlv_type=*(tptr++);
1387             subtlv_len=*(tptr++);
1388             /* prepend the ident string */
1389             snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
1390             if(!isis_print_is_reach_subtlv(tptr,subtlv_type,subtlv_len,ident_buffer))
1391                 return(0);
1392             tptr+=subtlv_len;
1393             subtlv_sum_len-=(subtlv_len+2);
1394             proc_bytes+=(subtlv_len+2);
1395         }
1396     }
1397     return(proc_bytes);
1398 }
1399
1400 /*
1401  * this is the common Multi Topology ID decoder
1402  * it is called from various MT-TLVs (222,229,235,237)
1403  */
1404
1405 static int
1406 isis_print_mtid (const u_int8_t *tptr,const char *ident) {
1407     
1408     if (!TTEST2(*tptr, 2))
1409         return(0);
1410
1411     printf("%s%s",
1412            ident,
1413            tok2str(isis_mt_values,
1414                    "Reserved for IETF Consensus",
1415                    ISIS_MASK_MTID(EXTRACT_16BITS(tptr))));
1416
1417     printf(" Topology (0x%03x), Flags: [%s]",
1418            ISIS_MASK_MTID(EXTRACT_16BITS(tptr)),
1419            bittok2str(isis_mt_flag_values, "none",ISIS_MASK_MTFLAGS(EXTRACT_16BITS(tptr))));
1420
1421     return(2);
1422 }
1423
1424 /*
1425  * this is the common extended IP reach decoder
1426  * it is called from TLVs (135,235,236,237)
1427  * we process the TLV and optional subTLVs and return
1428  * the amount of processed bytes
1429  */
1430
1431 static int
1432 isis_print_extd_ip_reach (const u_int8_t *tptr, const char *ident, u_int16_t afi) {
1433
1434     char ident_buffer[20];
1435     u_int8_t prefix[16]; /* shared copy buffer for IPv4 and IPv6 prefixes */
1436     u_int metric, status_byte, bit_length, byte_length, sublen, processed, subtlvtype, subtlvlen;
1437
1438     if (!TTEST2(*tptr, 4))
1439         return (0);
1440     metric = EXTRACT_32BITS(tptr);
1441     processed=4;
1442     tptr+=4;
1443     
1444     if (afi == IPV4) {
1445         if (!TTEST2(*tptr, 1)) /* fetch status byte */
1446             return (0);
1447         status_byte=*(tptr++);
1448         bit_length = status_byte&0x3f;
1449         processed++;
1450 #ifdef INET6
1451     } else if (afi == IPV6) {
1452         if (!TTEST2(*tptr, 1)) /* fetch status & prefix_len byte */
1453             return (0);
1454         status_byte=*(tptr++);
1455         bit_length=*(tptr++);
1456         processed+=2;
1457 #endif
1458     } else
1459         return (0); /* somebody is fooling us */
1460
1461     byte_length = (bit_length + 7) / 8; /* prefix has variable length encoding */
1462    
1463     if (!TTEST2(*tptr, byte_length))
1464         return (0);
1465     memset(prefix, 0, 16);              /* clear the copy buffer */
1466     memcpy(prefix,tptr,byte_length);    /* copy as much as is stored in the TLV */
1467     tptr+=byte_length;
1468     processed+=byte_length;
1469
1470     if (afi == IPV4)
1471         printf("%sIPv4 prefix: %15s/%u",
1472                ident,
1473                ipaddr_string(prefix),
1474                bit_length);
1475 #ifdef INET6
1476     if (afi == IPV6)
1477         printf("%sIPv6 prefix: %s/%u",
1478                ident,
1479                ip6addr_string(prefix),
1480                bit_length);
1481 #endif 
1482    
1483     printf(", Distribution: %s, Metric: %u",
1484            ISIS_MASK_TLV_EXTD_IP_UPDOWN(status_byte) ? "down" : "up",
1485            metric);
1486
1487     if (afi == IPV4 && ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte))
1488         printf(", sub-TLVs present");
1489 #ifdef INET6
1490     if (afi == IPV6)
1491         printf(", %s%s",
1492                ISIS_MASK_TLV_EXTD_IP6_IE(status_byte) ? "External" : "Internal",
1493                ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte) ? ", sub-TLVs present" : "");
1494 #endif
1495     
1496     if ((ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte)  && afi == IPV4) ||
1497         (ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte) && afi == IPV6)) {
1498         /* assume that one prefix can hold more
1499            than one subTLV - therefore the first byte must reflect
1500            the aggregate bytecount of the subTLVs for this prefix
1501         */
1502         if (!TTEST2(*tptr, 1))
1503             return (0);
1504         sublen=*(tptr++);
1505         processed+=sublen+1;
1506         printf(" (%u)",sublen);   /* print out subTLV length */
1507         
1508         while (sublen>0) {
1509             if (!TTEST2(*tptr,2))
1510                 return (0);
1511             subtlvtype=*(tptr++);
1512             subtlvlen=*(tptr++);
1513             /* prepend the ident string */
1514             snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
1515             if(!isis_print_ip_reach_subtlv(tptr,subtlvtype,subtlvlen,ident_buffer))
1516                 return(0);
1517             tptr+=subtlvlen;
1518             sublen-=(subtlvlen+2);
1519         }
1520     }
1521     return (processed);
1522 }
1523
1524 /*
1525  * isis_print
1526  * Decode IS-IS packets.  Return 0 on error.
1527  */
1528
1529 static int isis_print (const u_int8_t *p, u_int length)
1530 {
1531     const struct isis_common_header *isis_header;
1532
1533     const struct isis_iih_lan_header *header_iih_lan;
1534     const struct isis_iih_ptp_header *header_iih_ptp;
1535     const struct isis_lsp_header *header_lsp;
1536     const struct isis_csnp_header *header_csnp;
1537     const struct isis_psnp_header *header_psnp;
1538
1539     const struct isis_tlv_lsp *tlv_lsp;
1540     const struct isis_tlv_ptp_adj *tlv_ptp_adj;
1541     const struct isis_tlv_is_reach *tlv_is_reach;
1542     const struct isis_tlv_es_reach *tlv_es_reach;
1543
1544     u_int8_t pdu_type, max_area, id_length, tlv_type, tlv_len, tmp, alen, lan_alen, prefix_len;
1545     u_int8_t ext_is_len, ext_ip_len, mt_len;
1546     const u_int8_t *optr, *pptr, *tptr;
1547     u_short packet_len,pdu_len;
1548     u_int i,vendor_id;
1549
1550     packet_len=length;
1551     optr = p; /* initialize the _o_riginal pointer to the packet start -
1552                  need it for parsing the checksum TLV */
1553     isis_header = (const struct isis_common_header *)p;
1554     TCHECK(*isis_header);
1555     pptr = p+(ISIS_COMMON_HEADER_SIZE);
1556     header_iih_lan = (const struct isis_iih_lan_header *)pptr;
1557     header_iih_ptp = (const struct isis_iih_ptp_header *)pptr;
1558     header_lsp = (const struct isis_lsp_header *)pptr;
1559     header_csnp = (const struct isis_csnp_header *)pptr;
1560     header_psnp = (const struct isis_psnp_header *)pptr;
1561
1562     if (!eflag)
1563         printf("IS-IS");
1564
1565     /*
1566      * Sanity checking of the header.
1567      */
1568
1569     if (isis_header->version != ISIS_VERSION) {
1570         printf("version %d packet not supported", isis_header->version);
1571         return (0);
1572     }
1573
1574     if ((isis_header->id_length != SYSTEM_ID_LEN) && (isis_header->id_length != 0)) {
1575         printf("system ID length of %d is not supported",
1576                isis_header->id_length);
1577         return (0);
1578     }
1579
1580     if (isis_header->pdu_version != ISIS_VERSION) {
1581         printf("version %d packet not supported", isis_header->pdu_version);
1582         return (0);
1583     }
1584
1585     max_area = isis_header->max_area;
1586     switch(max_area) {
1587     case 0:
1588         max_area = 3;    /* silly shit */
1589         break;
1590     case 255:
1591         printf("bad packet -- 255 areas");
1592         return (0);
1593     default:
1594         break;
1595     }
1596
1597     id_length = isis_header->id_length;
1598     switch(id_length) {
1599     case 0:
1600         id_length = 6;   /* silly shit again */
1601         break;
1602     case 1:              /* 1-8 are valid sys-ID lenghts */
1603     case 2:
1604     case 3:
1605     case 4:
1606     case 5:
1607     case 6:
1608     case 7:
1609     case 8:
1610         break;
1611     case 255:
1612         id_length = 0;   /* entirely useless */
1613         break;
1614     default:
1615         break;
1616     }
1617
1618     /* toss any non 6-byte sys-ID len PDUs */
1619     if (id_length != 6 ) { 
1620         printf("bad packet -- illegal sys-ID length (%u)", id_length);
1621         return (0);
1622     }
1623
1624     pdu_type=isis_header->pdu_type;
1625
1626     /* in non-verbose mode print the basic PDU Type plus PDU specific brief information*/
1627     if (vflag < 1) {
1628         printf("%s%s",
1629                eflag ? "" : ", ",
1630                tok2str(isis_pdu_values,"unknown PDU-Type %u",pdu_type));
1631
1632         switch (pdu_type) {
1633
1634         case ISIS_PDU_L1_LAN_IIH:
1635         case ISIS_PDU_L2_LAN_IIH:
1636             printf(", src-id %s",
1637                    isis_print_id(header_iih_lan->source_id,SYSTEM_ID_LEN));
1638             printf(", lan-id %s, prio %u",
1639                    isis_print_id(header_iih_lan->lan_id,NODE_ID_LEN),
1640                    header_iih_lan->priority);
1641             break;
1642         case ISIS_PDU_PTP_IIH:
1643             printf(", src-id %s", isis_print_id(header_iih_ptp->source_id,SYSTEM_ID_LEN));
1644             break;
1645         case ISIS_PDU_L1_LSP:
1646         case ISIS_PDU_L2_LSP:
1647             printf(", lsp-id %s, seq 0x%08x, lifetime %5us",
1648                    isis_print_id(header_lsp->lsp_id, LSP_ID_LEN),
1649                    EXTRACT_32BITS(header_lsp->sequence_number),
1650                    EXTRACT_16BITS(header_lsp->remaining_lifetime));
1651             break;
1652         case ISIS_PDU_L1_CSNP:
1653         case ISIS_PDU_L2_CSNP:
1654             printf(", src-id %s", isis_print_id(header_csnp->source_id,NODE_ID_LEN));
1655             break;
1656         case ISIS_PDU_L1_PSNP:
1657         case ISIS_PDU_L2_PSNP:
1658             printf(", src-id %s", isis_print_id(header_psnp->source_id,NODE_ID_LEN));
1659             break;
1660
1661         }
1662         printf(", length %u", length);
1663
1664         return(1);
1665     }
1666
1667     /* ok they seem to want to know everything - lets fully decode it */
1668     printf("%slength %u", eflag ? "" : ", ",length);
1669
1670     printf("\n\t%s, hlen: %u, v: %u, pdu-v: %u, sys-id-len: %u (%u), max-area: %u (%u)",
1671            tok2str(isis_pdu_values,
1672                    "unknown, type %u",
1673                    pdu_type),
1674            isis_header->fixed_len,
1675            isis_header->version,
1676            isis_header->pdu_version,
1677            id_length,
1678            isis_header->id_length,
1679            max_area,
1680            isis_header->max_area);
1681
1682     if (vflag > 1) {
1683         if(!print_unknown_data(optr,"\n\t",8)) /* provide the _o_riginal pointer */
1684             return(0);                         /* for optionally debugging the common header */
1685     }
1686
1687     switch (pdu_type) {
1688
1689     case ISIS_PDU_L1_LAN_IIH:
1690     case ISIS_PDU_L2_LAN_IIH:
1691         if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE)) {
1692             printf(", bogus fixed header length %u should be %lu",
1693                    isis_header->fixed_len, (unsigned long)ISIS_IIH_LAN_HEADER_SIZE);
1694             return (0);
1695         }
1696
1697         pdu_len=EXTRACT_16BITS(header_iih_lan->pdu_len);
1698         if (packet_len>pdu_len) {
1699             packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1700             length=pdu_len;
1701         }
1702
1703         TCHECK(*header_iih_lan);
1704         printf("\n\t  source-id: %s,  holding time: %us, Flags: [%s]",
1705                isis_print_id(header_iih_lan->source_id,SYSTEM_ID_LEN),
1706                EXTRACT_16BITS(header_iih_lan->holding_time),
1707                tok2str(isis_iih_circuit_type_values,
1708                        "unknown circuit type 0x%02x",
1709                        header_iih_lan->circuit_type));
1710
1711         printf("\n\t  lan-id:    %s, Priority: %u, PDU length: %u",
1712                isis_print_id(header_iih_lan->lan_id, NODE_ID_LEN),
1713                (header_iih_lan->priority) & ISIS_LAN_PRIORITY_MASK,
1714                pdu_len);
1715
1716         if (vflag > 1) {
1717             if(!print_unknown_data(pptr,"\n\t  ",ISIS_IIH_LAN_HEADER_SIZE))
1718                 return(0);
1719         }
1720
1721         packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
1722         pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
1723         break;
1724
1725     case ISIS_PDU_PTP_IIH:
1726         if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE)) {
1727             printf(", bogus fixed header length %u should be %lu",
1728                    isis_header->fixed_len, (unsigned long)ISIS_IIH_PTP_HEADER_SIZE);
1729             return (0);
1730         }
1731
1732         pdu_len=EXTRACT_16BITS(header_iih_ptp->pdu_len);
1733         if (packet_len>pdu_len) {
1734             packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1735             length=pdu_len;
1736         }
1737
1738         TCHECK(*header_iih_ptp);
1739         printf("\n\t  source-id: %s, holding time: %us, Flags: [%s]",
1740                isis_print_id(header_iih_ptp->source_id,SYSTEM_ID_LEN),
1741                EXTRACT_16BITS(header_iih_ptp->holding_time),
1742                tok2str(isis_iih_circuit_type_values,
1743                        "unknown circuit type 0x%02x",
1744                        header_iih_ptp->circuit_type));
1745
1746         printf("\n\t  circuit-id: 0x%02x, PDU length: %u",
1747                header_iih_ptp->circuit_id,
1748                pdu_len);
1749
1750         if (vflag > 1) {
1751             if(!print_unknown_data(pptr,"\n\t  ",ISIS_IIH_PTP_HEADER_SIZE))
1752                 return(0);
1753         }
1754
1755         packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
1756         pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
1757         break;
1758
1759     case ISIS_PDU_L1_LSP:
1760     case ISIS_PDU_L2_LSP:
1761         if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE)) {
1762             printf(", bogus fixed header length %u should be %lu",
1763                    isis_header->fixed_len, (unsigned long)ISIS_LSP_HEADER_SIZE);
1764             return (0);
1765         }
1766
1767         pdu_len=EXTRACT_16BITS(header_lsp->pdu_len);
1768         if (packet_len>pdu_len) {
1769             packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1770             length=pdu_len;
1771         }
1772
1773         TCHECK(*header_lsp);
1774         printf("\n\t  lsp-id: %s, seq: 0x%08x, lifetime: %5us\n\t  chksum: 0x%04x",
1775                isis_print_id(header_lsp->lsp_id, LSP_ID_LEN),
1776                EXTRACT_32BITS(header_lsp->sequence_number),
1777                EXTRACT_16BITS(header_lsp->remaining_lifetime),
1778                EXTRACT_16BITS(header_lsp->checksum));
1779
1780         /* if this is a purge do not attempt to verify the checksum */
1781         if ( EXTRACT_16BITS(header_lsp->remaining_lifetime) == 0 &&
1782              EXTRACT_16BITS(header_lsp->checksum) == 0)
1783             printf(" (purged)");
1784         else
1785             /* verify the checksum -
1786              * checking starts at the lsp-id field at byte position [12]
1787              * hence the length needs to be reduced by 12 bytes */
1788             printf(" (%s)", (osi_cksum((u_int8_t *)header_lsp->lsp_id, length-12)) ? "incorrect" : "correct");
1789
1790         printf(", PDU length: %u, Flags: [ %s",
1791                pdu_len,
1792                ISIS_MASK_LSP_OL_BIT(header_lsp->typeblock) ? "Overload bit set, " : "");
1793
1794         if (ISIS_MASK_LSP_ATT_BITS(header_lsp->typeblock)) {
1795             printf("%s", ISIS_MASK_LSP_ATT_DEFAULT_BIT(header_lsp->typeblock) ? "default " : "");
1796             printf("%s", ISIS_MASK_LSP_ATT_DELAY_BIT(header_lsp->typeblock) ? "delay " : "");
1797             printf("%s", ISIS_MASK_LSP_ATT_EXPENSE_BIT(header_lsp->typeblock) ? "expense " : "");
1798             printf("%s", ISIS_MASK_LSP_ATT_ERROR_BIT(header_lsp->typeblock) ? "error " : "");
1799             printf("ATT bit set, ");
1800         }
1801         printf("%s", ISIS_MASK_LSP_PARTITION_BIT(header_lsp->typeblock) ? "P bit set, " : "");
1802         printf("%s ]", tok2str(isis_lsp_istype_values,"Unknown(0x%x)",ISIS_MASK_LSP_ISTYPE_BITS(header_lsp->typeblock)));
1803
1804         if (vflag > 1) {
1805             if(!print_unknown_data(pptr,"\n\t  ",ISIS_LSP_HEADER_SIZE))
1806                 return(0);
1807         }
1808
1809         packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
1810         pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
1811         break;
1812
1813     case ISIS_PDU_L1_CSNP:
1814     case ISIS_PDU_L2_CSNP:
1815         if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE)) {
1816             printf(", bogus fixed header length %u should be %lu",
1817                    isis_header->fixed_len, (unsigned long)ISIS_CSNP_HEADER_SIZE);
1818             return (0);
1819         }
1820
1821         pdu_len=EXTRACT_16BITS(header_csnp->pdu_len);
1822         if (packet_len>pdu_len) {
1823             packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1824             length=pdu_len;
1825         }
1826
1827         TCHECK(*header_csnp);
1828         printf("\n\t  source-id:    %s, PDU length: %u",
1829                isis_print_id(header_csnp->source_id, NODE_ID_LEN),
1830                pdu_len);
1831         printf("\n\t  start lsp-id: %s",
1832                isis_print_id(header_csnp->start_lsp_id, LSP_ID_LEN));
1833         printf("\n\t  end lsp-id:   %s",
1834                isis_print_id(header_csnp->end_lsp_id, LSP_ID_LEN));
1835
1836         if (vflag > 1) {
1837             if(!print_unknown_data(pptr,"\n\t  ",ISIS_CSNP_HEADER_SIZE))
1838                 return(0);
1839         }
1840
1841         packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
1842         pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
1843         break;
1844
1845     case ISIS_PDU_L1_PSNP:
1846     case ISIS_PDU_L2_PSNP:
1847         if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE)) {
1848             printf("- bogus fixed header length %u should be %lu",
1849                    isis_header->fixed_len, (unsigned long)ISIS_PSNP_HEADER_SIZE);
1850             return (0);
1851         }
1852
1853         pdu_len=EXTRACT_16BITS(header_psnp->pdu_len);
1854         if (packet_len>pdu_len) {
1855             packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1856             length=pdu_len;
1857         }
1858
1859         TCHECK(*header_psnp);
1860         printf("\n\t  source-id:    %s, PDU length: %u",
1861                isis_print_id(header_psnp->source_id, NODE_ID_LEN),
1862                pdu_len);
1863
1864         if (vflag > 1) {
1865             if(!print_unknown_data(pptr,"\n\t  ",ISIS_PSNP_HEADER_SIZE))
1866                 return(0);
1867         }
1868
1869         packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
1870         pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
1871         break;
1872
1873     default:
1874         if(!print_unknown_data(pptr,"\n\t  ",length))
1875             return(0);
1876         return (0);
1877     }
1878
1879     /*
1880      * Now print the TLV's.
1881      */
1882
1883     while (packet_len >= 2) {
1884         if (pptr == snapend) {
1885             return (1);
1886         }
1887
1888         if (!TTEST2(*pptr, 2)) {
1889             printf("\n\t\t packet exceeded snapshot (%ld) bytes",
1890                    (long)(pptr-snapend));
1891             return (1);
1892         }
1893         tlv_type = *pptr++;
1894         tlv_len = *pptr++;
1895         tmp =tlv_len; /* copy temporary len & pointer to packet data */
1896         tptr = pptr;
1897         packet_len -= 2;
1898         if (tlv_len > packet_len) {
1899             break;
1900         }
1901
1902         /* first lets see if we know the TLVs name*/
1903         printf("\n\t    %s TLV #%u, length: %u",
1904                tok2str(isis_tlv_values,
1905                        "unknown",
1906                        tlv_type),
1907                tlv_type,
1908                tlv_len);
1909
1910         /* now check if we have a decoder otherwise do a hexdump at the end*/
1911         switch (tlv_type) {
1912         case ISIS_TLV_AREA_ADDR:
1913             if (!TTEST2(*tptr, 1))
1914                 goto trunctlv;
1915             alen = *tptr++;
1916             while (tmp && alen < tmp) {
1917                 printf("\n\t      Area address (length: %u): %s",
1918                        alen,
1919                        isonsap_string(tptr,alen));
1920                 tptr += alen;
1921                 tmp -= alen + 1;
1922                 if (tmp==0) /* if this is the last area address do not attemt a boundary check */
1923                     break;
1924                 if (!TTEST2(*tptr, 1))
1925                     goto trunctlv;
1926                 alen = *tptr++;
1927             }
1928             break;
1929         case ISIS_TLV_ISNEIGH:
1930             while (tmp >= ETHER_ADDR_LEN) {
1931                 if (!TTEST2(*tptr, ETHER_ADDR_LEN))
1932                     goto trunctlv;
1933                 printf("\n\t      SNPA: %s",isis_print_id(tptr,ETHER_ADDR_LEN));
1934                 tmp -= ETHER_ADDR_LEN;
1935                 tptr += ETHER_ADDR_LEN;
1936             }
1937             break;
1938
1939         case ISIS_TLV_ISNEIGH_VARLEN:
1940             if (!TTEST2(*tptr, 1))
1941                 goto trunctlv;
1942             lan_alen = *tptr++; /* LAN adress length */
1943             tmp --;
1944             printf("\n\t      LAN address length %u bytes ",lan_alen);
1945             while (tmp >= lan_alen) {
1946                 if (!TTEST2(*tptr, lan_alen))
1947                     goto trunctlv;
1948                 printf("\n\t\tIS Neighbor: %s",isis_print_id(tptr,lan_alen));
1949                 tmp -= lan_alen;
1950                 tptr +=lan_alen;
1951             }
1952             break;
1953
1954         case ISIS_TLV_PADDING:
1955             break;
1956
1957         case ISIS_TLV_MT_IS_REACH:
1958             while (tmp >= 2+NODE_ID_LEN+3+1) {
1959                 mt_len = isis_print_mtid(tptr, "\n\t      ");
1960                 if (mt_len == 0) /* did something go wrong ? */
1961                     goto trunctlv;
1962                 tptr+=mt_len;
1963                 tmp-=mt_len;
1964
1965                 ext_is_len = isis_print_ext_is_reach(tptr,"\n\t      ",tlv_type);
1966                 if (ext_is_len == 0) /* did something go wrong ? */
1967                     goto trunctlv;
1968                    
1969                 tmp-=ext_is_len;
1970                 tptr+=ext_is_len;
1971             }
1972             break;
1973
1974         case ISIS_TLV_IS_ALIAS_ID:
1975             while (tmp >= NODE_ID_LEN+1) { /* is it worth attempting a decode ? */
1976                 ext_is_len = isis_print_ext_is_reach(tptr,"\n\t      ",tlv_type);
1977                 if (ext_is_len == 0) /* did something go wrong ? */
1978                     goto trunctlv;
1979                 tmp-=ext_is_len;
1980                 tptr+=ext_is_len;
1981             }
1982             break;
1983
1984         case ISIS_TLV_EXT_IS_REACH:
1985             while (tmp >= NODE_ID_LEN+3+1) { /* is it worth attempting a decode ? */
1986                 ext_is_len = isis_print_ext_is_reach(tptr,"\n\t      ",tlv_type);
1987                 if (ext_is_len == 0) /* did something go wrong ? */
1988                     goto trunctlv;                   
1989                 tmp-=ext_is_len;
1990                 tptr+=ext_is_len;
1991             }
1992             break;
1993         case ISIS_TLV_IS_REACH:
1994             if (!TTEST2(*tptr,1))  /* check if there is one byte left to read out the virtual flag */
1995                 goto trunctlv;
1996             printf("\n\t      %s",
1997                    tok2str(isis_is_reach_virtual_values,
1998                            "bogus virtual flag 0x%02x",
1999                            *tptr++));
2000             tlv_is_reach = (const struct isis_tlv_is_reach *)tptr;
2001             while (tmp >= sizeof(struct isis_tlv_is_reach)) {
2002                 if (!TTEST(*tlv_is_reach))
2003                     goto trunctlv;
2004                 printf("\n\t      IS Neighbor: %s",
2005                        isis_print_id(tlv_is_reach->neighbor_nodeid, NODE_ID_LEN));
2006                 isis_print_metric_block(&tlv_is_reach->isis_metric_block);
2007                 tmp -= sizeof(struct isis_tlv_is_reach);
2008                 tlv_is_reach++;
2009             }
2010             break;
2011
2012         case ISIS_TLV_ESNEIGH:
2013             tlv_es_reach = (const struct isis_tlv_es_reach *)tptr;
2014             while (tmp >= sizeof(struct isis_tlv_es_reach)) {
2015                 if (!TTEST(*tlv_es_reach))
2016                     goto trunctlv;
2017                 printf("\n\t      ES Neighbor: %s",
2018                        isis_print_id(tlv_es_reach->neighbor_sysid,SYSTEM_ID_LEN));
2019                 isis_print_metric_block(&tlv_es_reach->isis_metric_block);
2020                 tmp -= sizeof(struct isis_tlv_es_reach);
2021                 tlv_es_reach++;
2022             }
2023             break;
2024
2025             /* those two TLVs share the same format */
2026         case ISIS_TLV_INT_IP_REACH:
2027         case ISIS_TLV_EXT_IP_REACH:
2028             if (!isis_print_tlv_ip_reach(pptr, "\n\t      ", tlv_len))
2029                 return (1);
2030             break;
2031
2032         case ISIS_TLV_EXTD_IP_REACH:
2033             while (tmp>0) {
2034                 ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", IPV4);
2035                 if (ext_ip_len == 0) /* did something go wrong ? */
2036                     goto trunctlv;
2037                 tptr+=ext_ip_len;
2038                 tmp-=ext_ip_len;
2039             }
2040             break;
2041
2042         case ISIS_TLV_MT_IP_REACH:
2043             while (tmp>0) {
2044                 mt_len = isis_print_mtid(tptr, "\n\t      ");
2045                 if (mt_len == 0) /* did something go wrong ? */
2046                     goto trunctlv;
2047                 tptr+=mt_len;
2048                 tmp-=mt_len;
2049
2050                 ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", IPV4);
2051                 if (ext_ip_len == 0) /* did something go wrong ? */
2052                     goto trunctlv;
2053                 tptr+=ext_ip_len;
2054                 tmp-=ext_ip_len;
2055             }
2056             break;
2057
2058 #ifdef INET6
2059         case ISIS_TLV_IP6_REACH:
2060             while (tmp>0) {
2061                 ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", IPV6);
2062                 if (ext_ip_len == 0) /* did something go wrong ? */
2063                     goto trunctlv;
2064                 tptr+=ext_ip_len;
2065                 tmp-=ext_ip_len;
2066             }
2067             break;
2068
2069         case ISIS_TLV_MT_IP6_REACH:
2070             while (tmp>0) {
2071                 mt_len = isis_print_mtid(tptr, "\n\t      ");
2072                 if (mt_len == 0) /* did something go wrong ? */
2073                     goto trunctlv;
2074                 tptr+=mt_len;
2075                 tmp-=mt_len;
2076
2077                 ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", IPV6);
2078                 if (ext_ip_len == 0) /* did something go wrong ? */
2079                     goto trunctlv;
2080                 tptr+=ext_ip_len;
2081                 tmp-=ext_ip_len;
2082             }
2083             break;
2084
2085         case ISIS_TLV_IP6ADDR:
2086             while (tmp>0) {
2087                 if (!TTEST2(*tptr, 16))
2088                     goto trunctlv;
2089
2090                 printf("\n\t      IPv6 interface address: %s",
2091                        ip6addr_string(tptr));
2092
2093                 tptr += 16;
2094                 tmp -= 16;
2095             }
2096             break;
2097 #endif
2098         case ISIS_TLV_AUTH:
2099             if (!TTEST2(*tptr, 1))
2100                 goto trunctlv;
2101
2102             printf("\n\t      %s: ",
2103                    tok2str(isis_subtlv_auth_values,
2104                            "unknown Authentication type 0x%02x",
2105                            *tptr));
2106
2107             switch (*tptr) {
2108             case ISIS_SUBTLV_AUTH_SIMPLE:
2109                 for(i=1;i<tlv_len;i++) {
2110                     if (!TTEST2(*(tptr+i), 1))
2111                         goto trunctlv;
2112                     printf("%c",*(tptr+i));
2113                 }
2114                 break;
2115             case ISIS_SUBTLV_AUTH_MD5:
2116                 for(i=1;i<tlv_len;i++) {
2117                     if (!TTEST2(*(tptr+i), 1))
2118                         goto trunctlv;
2119                     printf("%02x",*(tptr+i));
2120                 }
2121                 if (tlv_len != ISIS_SUBTLV_AUTH_MD5_LEN+1)
2122                     printf(", (malformed subTLV) ");
2123                 break;
2124             case ISIS_SUBTLV_AUTH_PRIVATE:
2125             default:
2126                 if(!print_unknown_data(tptr+1,"\n\t\t  ",tlv_len-1))
2127                     return(0);
2128                 break;
2129             }
2130             break;
2131
2132         case ISIS_TLV_PTP_ADJ:
2133             tlv_ptp_adj = (const struct isis_tlv_ptp_adj *)tptr;
2134             if(tmp>=1) {
2135                 if (!TTEST2(*tptr, 1))
2136                     goto trunctlv;
2137                 printf("\n\t      Adjacency State: %s (%u)",
2138                        tok2str(isis_ptp_adjancey_values, "unknown", *tptr),
2139                         *tptr);
2140                 tmp--;
2141             }
2142             if(tmp>sizeof(tlv_ptp_adj->extd_local_circuit_id)) {
2143                 if (!TTEST2(tlv_ptp_adj->extd_local_circuit_id,
2144                             sizeof(tlv_ptp_adj->extd_local_circuit_id)))
2145                     goto trunctlv;
2146                 printf("\n\t      Extended Local circuit-ID: 0x%08x",
2147                        EXTRACT_32BITS(tlv_ptp_adj->extd_local_circuit_id));
2148                 tmp-=sizeof(tlv_ptp_adj->extd_local_circuit_id);
2149             }
2150             if(tmp>=SYSTEM_ID_LEN) {
2151                 if (!TTEST2(tlv_ptp_adj->neighbor_sysid, SYSTEM_ID_LEN))
2152                     goto trunctlv;
2153                 printf("\n\t      Neighbor System-ID: %s",
2154                        isis_print_id(tlv_ptp_adj->neighbor_sysid,SYSTEM_ID_LEN));
2155                 tmp-=SYSTEM_ID_LEN;
2156             }
2157             if(tmp>=sizeof(tlv_ptp_adj->neighbor_extd_local_circuit_id)) {
2158                 if (!TTEST2(tlv_ptp_adj->neighbor_extd_local_circuit_id,
2159                             sizeof(tlv_ptp_adj->neighbor_extd_local_circuit_id)))
2160                     goto trunctlv;
2161                 printf("\n\t      Neighbor Extended Local circuit-ID: 0x%08x",
2162                        EXTRACT_32BITS(tlv_ptp_adj->neighbor_extd_local_circuit_id));
2163             }
2164             break;
2165
2166         case ISIS_TLV_PROTOCOLS:
2167             printf("\n\t      NLPID(s): ");
2168             while (tmp>0) {
2169                 if (!TTEST2(*(tptr), 1))
2170                     goto trunctlv;
2171                 printf("%s (0x%02x)",
2172                        tok2str(nlpid_values,
2173                                "unknown",
2174                                *tptr),
2175                        *tptr);
2176                 if (tmp>1) /* further NPLIDs ? - put comma */
2177                     printf(", ");
2178                 tptr++;
2179                 tmp--;
2180             }
2181             break;
2182
2183         case ISIS_TLV_TE_ROUTER_ID:
2184             if (!TTEST2(*pptr, 4))
2185                 goto trunctlv;
2186             printf("\n\t      Traffic Engineering Router ID: %s", ipaddr_string(pptr));
2187             break;
2188
2189         case ISIS_TLV_IPADDR:
2190             while (tmp>0) {
2191                 if (!TTEST2(*tptr, 4))
2192                     goto trunctlv;
2193                 printf("\n\t      IPv4 interface address: %s", ipaddr_string(tptr));
2194                 tptr += 4;
2195                 tmp -= 4;
2196             }
2197             break;
2198
2199         case ISIS_TLV_HOSTNAME:
2200             printf("\n\t      Hostname: ");
2201             while (tmp>0) {
2202                 if (!TTEST2(*tptr, 1))
2203                     goto trunctlv;
2204                 printf("%c",*tptr++);
2205                 tmp--;
2206             }
2207             break;
2208
2209         case ISIS_TLV_SHARED_RISK_GROUP:
2210             if (!TTEST2(*tptr, NODE_ID_LEN))
2211                 goto trunctlv;
2212             printf("\n\t      IS Neighbor: %s", isis_print_id(tptr, NODE_ID_LEN));
2213             tptr+=(NODE_ID_LEN);
2214             tmp-=(NODE_ID_LEN);
2215
2216             if (!TTEST2(*tptr, 1))
2217                 goto trunctlv;
2218             printf(", Flags: [%s]", ISIS_MASK_TLV_SHARED_RISK_GROUP(*tptr++) ? "numbered" : "unnumbered");
2219             tmp--;
2220
2221             if (!TTEST2(*tptr,4))
2222                 goto trunctlv;
2223             printf("\n\t      IPv4 interface address: %s", ipaddr_string(tptr));
2224             tptr+=4;
2225             tmp-=4;
2226
2227             if (!TTEST2(*tptr,4))
2228                 goto trunctlv;
2229             printf("\n\t      IPv4 neighbor address: %s", ipaddr_string(tptr));
2230             tptr+=4;
2231             tmp-=4;
2232
2233             while (tmp>0) {
2234                 if (!TTEST2(*tptr, 4))
2235                     goto trunctlv;
2236                 printf("\n\t      Link-ID: 0x%08x", EXTRACT_32BITS(tptr));
2237                 tptr+=4;
2238                 tmp-=4;
2239             }
2240             break;
2241
2242         case ISIS_TLV_LSP:
2243             tlv_lsp = (const struct isis_tlv_lsp *)tptr;
2244             while(tmp>0) {
2245                 if (!TTEST((tlv_lsp->lsp_id)[LSP_ID_LEN-1]))
2246                     goto trunctlv;
2247                 printf("\n\t      lsp-id: %s",
2248                        isis_print_id(tlv_lsp->lsp_id, LSP_ID_LEN));
2249                 if (!TTEST2(tlv_lsp->sequence_number, 4))
2250                     goto trunctlv;
2251                 printf(", seq: 0x%08x",EXTRACT_32BITS(tlv_lsp->sequence_number));
2252                 if (!TTEST2(tlv_lsp->remaining_lifetime, 2))
2253                     goto trunctlv;
2254                 printf(", lifetime: %5ds",EXTRACT_16BITS(tlv_lsp->remaining_lifetime));
2255                 if (!TTEST2(tlv_lsp->checksum, 2))
2256                     goto trunctlv;
2257                 printf(", chksum: 0x%04x",EXTRACT_16BITS(tlv_lsp->checksum));
2258                 tmp-=sizeof(struct isis_tlv_lsp);
2259                 tlv_lsp++;
2260             }
2261             break;
2262
2263         case ISIS_TLV_CHECKSUM:
2264             if (!TTEST2(*tptr, 2))
2265                 goto trunctlv;
2266             printf("\n\t      checksum: 0x%04x ", EXTRACT_16BITS(tptr));
2267             /* do not attempt to verify the checksum if it is zero
2268              * most likely a HMAC-MD5 TLV is also present and
2269              * to avoid conflicts the checksum TLV is zeroed.
2270              * see rfc3358 for details
2271              */
2272             if (EXTRACT_16BITS(tptr) == 0)
2273                 printf("(unverified)");
2274             else printf("(%s)", osi_cksum(optr, length) ? "incorrect" : "correct");
2275             break;
2276
2277         case ISIS_TLV_MT_SUPPORTED:
2278             while (tmp>1) {
2279                 /* length can only be a multiple of 2, otherwise there is
2280                    something broken -> so decode down until length is 1 */
2281                 if (tmp!=1) {
2282                     mt_len = isis_print_mtid(tptr, "\n\t      ");
2283                     if (mt_len == 0) /* did something go wrong ? */
2284                         goto trunctlv;
2285                     tptr+=mt_len;
2286                     tmp-=mt_len;
2287                 } else {
2288                     printf("\n\t      malformed MT-ID");
2289                     break;
2290                 }
2291             }
2292             break;
2293
2294         case ISIS_TLV_RESTART_SIGNALING:
2295             if (!TTEST2(*tptr, 3))
2296                 goto trunctlv;
2297             printf("\n\t      Flags [%s], Remaining holding time %us",
2298                    bittok2str(isis_restart_flag_values, "none", *tptr),
2299                    EXTRACT_16BITS(tptr+1));
2300             tptr+=3;
2301             break;
2302
2303         case ISIS_TLV_IDRP_INFO:
2304             if (!TTEST2(*tptr, 1))
2305                 goto trunctlv;
2306             printf("\n\t      Inter-Domain Information Type: %s",
2307                    tok2str(isis_subtlv_idrp_values,
2308                            "Unknown (0x%02x)",
2309                            *tptr));
2310             switch (*tptr++) {
2311             case ISIS_SUBTLV_IDRP_ASN:
2312                 if (!TTEST2(*tptr, 2)) /* fetch AS number */
2313                     goto trunctlv;
2314                 printf("AS Number: %u",EXTRACT_16BITS(tptr));
2315                 break;
2316             case ISIS_SUBTLV_IDRP_LOCAL:
2317             case ISIS_SUBTLV_IDRP_RES:
2318             default:
2319                 if(!print_unknown_data(tptr,"\n\t      ",tlv_len-1))
2320                     return(0);
2321                 break;
2322             }
2323             break;
2324
2325         case ISIS_TLV_LSP_BUFFERSIZE:
2326             if (!TTEST2(*tptr, 2))
2327                 goto trunctlv;
2328             printf("\n\t      LSP Buffersize: %u",EXTRACT_16BITS(tptr));
2329             break;
2330
2331         case ISIS_TLV_PART_DIS:
2332             while (tmp >= SYSTEM_ID_LEN) {
2333                 if (!TTEST2(*tptr, SYSTEM_ID_LEN))
2334                     goto trunctlv;
2335                 printf("\n\t      %s",isis_print_id(tptr,SYSTEM_ID_LEN));
2336                 tptr+=SYSTEM_ID_LEN;
2337                 tmp-=SYSTEM_ID_LEN;
2338             }
2339             break;
2340
2341         case ISIS_TLV_PREFIX_NEIGH:
2342             if (!TTEST2(*tptr, sizeof(struct isis_metric_block)))
2343                 goto trunctlv;
2344             printf("\n\t      Metric Block");
2345             isis_print_metric_block((const struct isis_metric_block *)tptr);
2346             tptr+=sizeof(struct isis_metric_block);
2347             tmp-=sizeof(struct isis_metric_block);
2348
2349             while(tmp>0) {
2350                 if (!TTEST2(*tptr, 1))
2351                     goto trunctlv;
2352                 prefix_len=*tptr++; /* read out prefix length in semioctets*/
2353                 tmp--;
2354                 if (!TTEST2(*tptr, prefix_len/2))
2355                     goto trunctlv;
2356                 printf("\n\t\tAddress: %s/%u",
2357                        isonsap_string(tptr,prefix_len/2),
2358                        prefix_len*4);
2359                 tptr+=prefix_len/2;
2360                 tmp-=prefix_len/2;
2361             }
2362             break;
2363
2364         case ISIS_TLV_IIH_SEQNR:
2365             if (!TTEST2(*tptr, 4)) /* check if four bytes are on the wire */
2366                 goto trunctlv;
2367             printf("\n\t      Sequence number: %u", EXTRACT_32BITS(tptr) );
2368             break;
2369
2370         case ISIS_TLV_VENDOR_PRIVATE:
2371             if (!TTEST2(*tptr, 3)) /* check if enough byte for a full oui */
2372                 goto trunctlv;
2373             vendor_id = EXTRACT_24BITS(tptr);
2374             printf("\n\t      Vendor: %s (%u)",
2375                    tok2str(oui_values,"Unknown",vendor_id),
2376                    vendor_id);
2377             tptr+=3;
2378             tmp-=3;
2379             if (tmp > 0) /* hexdump the rest */
2380                 if(!print_unknown_data(tptr,"\n\t\t",tmp))
2381                     return(0);
2382             break;
2383             /*
2384              * FIXME those are the defined TLVs that lack a decoder
2385              * you are welcome to contribute code ;-)
2386              */
2387
2388         case ISIS_TLV_DECNET_PHASE4:
2389         case ISIS_TLV_LUCENT_PRIVATE:
2390         case ISIS_TLV_IPAUTH:
2391         case ISIS_TLV_NORTEL_PRIVATE1:
2392         case ISIS_TLV_NORTEL_PRIVATE2:
2393
2394         default:
2395             if (vflag <= 1) {
2396                 if(!print_unknown_data(pptr,"\n\t\t",tlv_len))
2397                     return(0);
2398             }
2399             break;
2400         }
2401         /* do we want to see an additionally hexdump ? */
2402         if (vflag> 1) {
2403             if(!print_unknown_data(pptr,"\n\t      ",tlv_len))
2404                 return(0);
2405         }
2406
2407         pptr += tlv_len;
2408         packet_len -= tlv_len;
2409     }
2410
2411     if (packet_len != 0) {
2412         printf("\n\t      %u straggler bytes", packet_len);
2413     }
2414     return (1);
2415
2416  trunc:
2417     fputs("[|isis]", stdout);
2418     return (1);
2419
2420  trunctlv:
2421     printf("\n\t\t packet exceeded snapshot");
2422     return(1);
2423 }
2424
2425 /*
2426  * Verify the checksum.  See 8473-1, Appendix C, section C.4.
2427  */
2428
2429 static int
2430 osi_cksum(const u_int8_t *tptr, u_int len)
2431 {
2432         int32_t c0 = 0, c1 = 0;
2433
2434         while ((int)--len >= 0) {
2435                 c0 += *tptr++;
2436                 c0 %= 255;
2437                 c1 += c0;
2438                 c1 %= 255;
2439         }
2440         return (c0 | c1);
2441 }
2442
2443
2444 /*
2445  * Local Variables:
2446  * c-style: whitesmith
2447  * c-basic-offset: 8
2448  * End:
2449  */