xref: /netbsd-src/external/bsd/tcpdump/dist/print-isoclns.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
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 
27 #include <sys/cdefs.h>
28 #ifndef lint
29 #if 0
30 static const char rcsid[] _U_ =
31     "@(#) Header: /tcpdump/master/tcpdump/print-isoclns.c,v 1.165 2008-08-16 13:38:15 hannes Exp  (LBL)";
32 #else
33 __RCSID("$NetBSD: print-isoclns.c,v 1.4 2013/12/31 17:33:31 christos Exp $");
34 #endif
35 #endif
36 
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
40 
41 #include <tcpdump-stdinc.h>
42 
43 #include <stdio.h>
44 #include <string.h>
45 
46 #include "interface.h"
47 #include "addrtoname.h"
48 #include "ethertype.h"
49 #include "ether.h"
50 #include "nlpid.h"
51 #include "extract.h"
52 #include "gmpls.h"
53 #include "oui.h"
54 #include "signature.h"
55 
56 /*
57  * IS-IS is defined in ISO 10589.  Look there for protocol definitions.
58  */
59 
60 #define SYSTEM_ID_LEN	ETHER_ADDR_LEN
61 #define NODE_ID_LEN     SYSTEM_ID_LEN+1
62 #define LSP_ID_LEN      SYSTEM_ID_LEN+2
63 
64 #define ISIS_VERSION	1
65 #define ESIS_VERSION	1
66 #define CLNP_VERSION	1
67 
68 #define ISIS_PDU_TYPE_MASK      0x1F
69 #define ESIS_PDU_TYPE_MASK      0x1F
70 #define CLNP_PDU_TYPE_MASK      0x1F
71 #define CLNP_FLAG_MASK          0xE0
72 #define ISIS_LAN_PRIORITY_MASK  0x7F
73 
74 #define ISIS_PDU_L1_LAN_IIH	15
75 #define ISIS_PDU_L2_LAN_IIH	16
76 #define ISIS_PDU_PTP_IIH	17
77 #define ISIS_PDU_L1_LSP       	18
78 #define ISIS_PDU_L2_LSP       	20
79 #define ISIS_PDU_L1_CSNP  	24
80 #define ISIS_PDU_L2_CSNP  	25
81 #define ISIS_PDU_L1_PSNP        26
82 #define ISIS_PDU_L2_PSNP        27
83 
84 static const struct tok isis_pdu_values[] = {
85     { ISIS_PDU_L1_LAN_IIH,       "L1 Lan IIH"},
86     { ISIS_PDU_L2_LAN_IIH,       "L2 Lan IIH"},
87     { ISIS_PDU_PTP_IIH,          "p2p IIH"},
88     { ISIS_PDU_L1_LSP,           "L1 LSP"},
89     { ISIS_PDU_L2_LSP,           "L2 LSP"},
90     { ISIS_PDU_L1_CSNP,          "L1 CSNP"},
91     { ISIS_PDU_L2_CSNP,          "L2 CSNP"},
92     { ISIS_PDU_L1_PSNP,          "L1 PSNP"},
93     { ISIS_PDU_L2_PSNP,          "L2 PSNP"},
94     { 0, NULL}
95 };
96 
97 /*
98  * A TLV is a tuple of a type, length and a value and is normally used for
99  * encoding information in all sorts of places.  This is an enumeration of
100  * the well known types.
101  *
102  * list taken from rfc3359 plus some memory from veterans ;-)
103  */
104 
105 #define ISIS_TLV_AREA_ADDR           1   /* iso10589 */
106 #define ISIS_TLV_IS_REACH            2   /* iso10589 */
107 #define ISIS_TLV_ESNEIGH             3   /* iso10589 */
108 #define ISIS_TLV_PART_DIS            4   /* iso10589 */
109 #define ISIS_TLV_PREFIX_NEIGH        5   /* iso10589 */
110 #define ISIS_TLV_ISNEIGH             6   /* iso10589 */
111 #define ISIS_TLV_ISNEIGH_VARLEN      7   /* iso10589 */
112 #define ISIS_TLV_PADDING             8   /* iso10589 */
113 #define ISIS_TLV_LSP                 9   /* iso10589 */
114 #define ISIS_TLV_AUTH                10  /* iso10589, rfc3567 */
115 #define ISIS_TLV_CHECKSUM            12  /* rfc3358 */
116 #define ISIS_TLV_CHECKSUM_MINLEN 2
117 #define ISIS_TLV_LSP_BUFFERSIZE      14  /* iso10589 rev2 */
118 #define ISIS_TLV_LSP_BUFFERSIZE_MINLEN 2
119 #define ISIS_TLV_EXT_IS_REACH        22  /* draft-ietf-isis-traffic-05 */
120 #define ISIS_TLV_IS_ALIAS_ID         24  /* draft-ietf-isis-ext-lsp-frags-02 */
121 #define ISIS_TLV_DECNET_PHASE4       42
122 #define ISIS_TLV_LUCENT_PRIVATE      66
123 #define ISIS_TLV_INT_IP_REACH        128 /* rfc1195, rfc2966 */
124 #define ISIS_TLV_PROTOCOLS           129 /* rfc1195 */
125 #define ISIS_TLV_EXT_IP_REACH        130 /* rfc1195, rfc2966 */
126 #define ISIS_TLV_IDRP_INFO           131 /* rfc1195 */
127 #define ISIS_TLV_IDRP_INFO_MINLEN      1
128 #define ISIS_TLV_IPADDR              132 /* rfc1195 */
129 #define ISIS_TLV_IPAUTH              133 /* rfc1195 */
130 #define ISIS_TLV_TE_ROUTER_ID        134 /* draft-ietf-isis-traffic-05 */
131 #define ISIS_TLV_EXTD_IP_REACH       135 /* draft-ietf-isis-traffic-05 */
132 #define ISIS_TLV_HOSTNAME            137 /* rfc2763 */
133 #define ISIS_TLV_SHARED_RISK_GROUP   138 /* draft-ietf-isis-gmpls-extensions */
134 #define ISIS_TLV_MT_PORT_CAP         143 /* rfc6165 */
135 #define ISIS_TLV_MT_CAPABILITY       144 /* rfc6329 */
136 #define ISIS_TLV_NORTEL_PRIVATE1     176
137 #define ISIS_TLV_NORTEL_PRIVATE2     177
138 #define ISIS_TLV_RESTART_SIGNALING   211 /* rfc3847 */
139 #define ISIS_TLV_RESTART_SIGNALING_FLAGLEN 1
140 #define ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN 2
141 #define ISIS_TLV_MT_IS_REACH         222 /* draft-ietf-isis-wg-multi-topology-05 */
142 #define ISIS_TLV_MT_SUPPORTED        229 /* draft-ietf-isis-wg-multi-topology-05 */
143 #define ISIS_TLV_MT_SUPPORTED_MINLEN 2
144 #define ISIS_TLV_IP6ADDR             232 /* draft-ietf-isis-ipv6-02 */
145 #define ISIS_TLV_MT_IP_REACH         235 /* draft-ietf-isis-wg-multi-topology-05 */
146 #define ISIS_TLV_IP6_REACH           236 /* draft-ietf-isis-ipv6-02 */
147 #define ISIS_TLV_MT_IP6_REACH        237 /* draft-ietf-isis-wg-multi-topology-05 */
148 #define ISIS_TLV_PTP_ADJ             240 /* rfc3373 */
149 #define ISIS_TLV_IIH_SEQNR           241 /* draft-shen-isis-iih-sequence-00 */
150 #define ISIS_TLV_IIH_SEQNR_MINLEN 4
151 #define ISIS_TLV_VENDOR_PRIVATE      250 /* draft-ietf-isis-experimental-tlv-01 */
152 #define ISIS_TLV_VENDOR_PRIVATE_MINLEN 3
153 
154 static const struct tok isis_tlv_values[] = {
155     { ISIS_TLV_AREA_ADDR,	   "Area address(es)"},
156     { ISIS_TLV_IS_REACH,           "IS Reachability"},
157     { ISIS_TLV_ESNEIGH,            "ES Neighbor(s)"},
158     { ISIS_TLV_PART_DIS,           "Partition DIS"},
159     { ISIS_TLV_PREFIX_NEIGH,       "Prefix Neighbors"},
160     { ISIS_TLV_ISNEIGH,            "IS Neighbor(s)"},
161     { ISIS_TLV_ISNEIGH_VARLEN,     "IS Neighbor(s) (variable length)"},
162     { ISIS_TLV_PADDING,            "Padding"},
163     { ISIS_TLV_LSP,                "LSP entries"},
164     { ISIS_TLV_AUTH,               "Authentication"},
165     { ISIS_TLV_CHECKSUM,           "Checksum"},
166     { ISIS_TLV_LSP_BUFFERSIZE,     "LSP Buffersize"},
167     { ISIS_TLV_EXT_IS_REACH,       "Extended IS Reachability"},
168     { ISIS_TLV_IS_ALIAS_ID,        "IS Alias ID"},
169     { ISIS_TLV_DECNET_PHASE4,      "DECnet Phase IV"},
170     { ISIS_TLV_LUCENT_PRIVATE,     "Lucent Proprietary"},
171     { ISIS_TLV_INT_IP_REACH,       "IPv4 Internal Reachability"},
172     { ISIS_TLV_PROTOCOLS,          "Protocols supported"},
173     { ISIS_TLV_EXT_IP_REACH,       "IPv4 External Reachability"},
174     { ISIS_TLV_IDRP_INFO,          "Inter-Domain Information Type"},
175     { ISIS_TLV_IPADDR,             "IPv4 Interface address(es)"},
176     { ISIS_TLV_IPAUTH,             "IPv4 authentication (deprecated)"},
177     { ISIS_TLV_TE_ROUTER_ID,       "Traffic Engineering Router ID"},
178     { ISIS_TLV_EXTD_IP_REACH,      "Extended IPv4 Reachability"},
179     { ISIS_TLV_SHARED_RISK_GROUP,  "Shared Risk Link Group"},
180     { ISIS_TLV_MT_PORT_CAP,        "Multi-Topology-Aware Port Capability"},
181     { ISIS_TLV_MT_CAPABILITY,      "Multi-Topology Capability"},
182     { ISIS_TLV_NORTEL_PRIVATE1,    "Nortel Proprietary"},
183     { ISIS_TLV_NORTEL_PRIVATE2,    "Nortel Proprietary"},
184     { ISIS_TLV_HOSTNAME,           "Hostname"},
185     { ISIS_TLV_RESTART_SIGNALING,  "Restart Signaling"},
186     { ISIS_TLV_MT_IS_REACH,        "Multi Topology IS Reachability"},
187     { ISIS_TLV_MT_SUPPORTED,       "Multi Topology"},
188     { ISIS_TLV_IP6ADDR,            "IPv6 Interface address(es)"},
189     { ISIS_TLV_MT_IP_REACH,        "Multi-Topology IPv4 Reachability"},
190     { ISIS_TLV_IP6_REACH,          "IPv6 reachability"},
191     { ISIS_TLV_MT_IP6_REACH,       "Multi-Topology IP6 Reachability"},
192     { ISIS_TLV_PTP_ADJ,            "Point-to-point Adjacency State"},
193     { ISIS_TLV_IIH_SEQNR,          "Hello PDU Sequence Number"},
194     { ISIS_TLV_VENDOR_PRIVATE,     "Vendor Private"},
195     { 0, NULL }
196 };
197 
198 #define ESIS_OPTION_PROTOCOLS        129
199 #define ESIS_OPTION_QOS_MAINTENANCE  195 /* iso9542 */
200 #define ESIS_OPTION_SECURITY         197 /* iso9542 */
201 #define ESIS_OPTION_ES_CONF_TIME     198 /* iso9542 */
202 #define ESIS_OPTION_PRIORITY         205 /* iso9542 */
203 #define ESIS_OPTION_ADDRESS_MASK     225 /* iso9542 */
204 #define ESIS_OPTION_SNPA_MASK        226 /* iso9542 */
205 
206 static const struct tok esis_option_values[] = {
207     { ESIS_OPTION_PROTOCOLS,       "Protocols supported"},
208     { ESIS_OPTION_QOS_MAINTENANCE, "QoS Maintenance" },
209     { ESIS_OPTION_SECURITY,        "Security" },
210     { ESIS_OPTION_ES_CONF_TIME,    "ES Configuration Time" },
211     { ESIS_OPTION_PRIORITY,        "Priority" },
212     { ESIS_OPTION_ADDRESS_MASK,    "Addressk Mask" },
213     { ESIS_OPTION_SNPA_MASK,       "SNPA Mask" },
214     { 0, NULL }
215 };
216 
217 #define CLNP_OPTION_DISCARD_REASON   193
218 #define CLNP_OPTION_QOS_MAINTENANCE  195 /* iso8473 */
219 #define CLNP_OPTION_SECURITY         197 /* iso8473 */
220 #define CLNP_OPTION_SOURCE_ROUTING   200 /* iso8473 */
221 #define CLNP_OPTION_ROUTE_RECORDING  203 /* iso8473 */
222 #define CLNP_OPTION_PADDING          204 /* iso8473 */
223 #define CLNP_OPTION_PRIORITY         205 /* iso8473 */
224 
225 static const struct tok clnp_option_values[] = {
226     { CLNP_OPTION_DISCARD_REASON,  "Discard Reason"},
227     { CLNP_OPTION_PRIORITY,        "Priority"},
228     { CLNP_OPTION_QOS_MAINTENANCE, "QoS Maintenance"},
229     { CLNP_OPTION_SECURITY, "Security"},
230     { CLNP_OPTION_SOURCE_ROUTING, "Source Routing"},
231     { CLNP_OPTION_ROUTE_RECORDING, "Route Recording"},
232     { CLNP_OPTION_PADDING, "Padding"},
233     { 0, NULL }
234 };
235 
236 static const struct tok clnp_option_rfd_class_values[] = {
237     { 0x0, "General"},
238     { 0x8, "Address"},
239     { 0x9, "Source Routeing"},
240     { 0xa, "Lifetime"},
241     { 0xb, "PDU Discarded"},
242     { 0xc, "Reassembly"},
243     { 0, NULL }
244 };
245 
246 static const struct tok clnp_option_rfd_general_values[] = {
247     { 0x0, "Reason not specified"},
248     { 0x1, "Protocol procedure error"},
249     { 0x2, "Incorrect checksum"},
250     { 0x3, "PDU discarded due to congestion"},
251     { 0x4, "Header syntax error (cannot be parsed)"},
252     { 0x5, "Segmentation needed but not permitted"},
253     { 0x6, "Incomplete PDU received"},
254     { 0x7, "Duplicate option"},
255     { 0, NULL }
256 };
257 
258 static const struct tok clnp_option_rfd_address_values[] = {
259     { 0x0, "Destination address unreachable"},
260     { 0x1, "Destination address unknown"},
261     { 0, NULL }
262 };
263 
264 static const struct tok clnp_option_rfd_source_routeing_values[] = {
265     { 0x0, "Unspecified source routeing error"},
266     { 0x1, "Syntax error in source routeing field"},
267     { 0x2, "Unknown address in source routeing field"},
268     { 0x3, "Path not acceptable"},
269     { 0, NULL }
270 };
271 
272 static const struct tok clnp_option_rfd_lifetime_values[] = {
273     { 0x0, "Lifetime expired while data unit in transit"},
274     { 0x1, "Lifetime expired during reassembly"},
275     { 0, NULL }
276 };
277 
278 static const struct tok clnp_option_rfd_pdu_discard_values[] = {
279     { 0x0, "Unsupported option not specified"},
280     { 0x1, "Unsupported protocol version"},
281     { 0x2, "Unsupported security option"},
282     { 0x3, "Unsupported source routeing option"},
283     { 0x4, "Unsupported recording of route option"},
284     { 0, NULL }
285 };
286 
287 static const struct tok clnp_option_rfd_reassembly_values[] = {
288     { 0x0, "Reassembly interference"},
289     { 0, NULL }
290 };
291 
292 /* array of 16 error-classes */
293 static const struct tok *clnp_option_rfd_error_class[] = {
294     clnp_option_rfd_general_values,
295     NULL,
296     NULL,
297     NULL,
298     NULL,
299     NULL,
300     NULL,
301     NULL,
302     clnp_option_rfd_address_values,
303     clnp_option_rfd_source_routeing_values,
304     clnp_option_rfd_lifetime_values,
305     clnp_option_rfd_pdu_discard_values,
306     clnp_option_rfd_reassembly_values,
307     NULL,
308     NULL,
309     NULL
310 };
311 
312 #define CLNP_OPTION_OPTION_QOS_MASK 0x3f
313 #define CLNP_OPTION_SCOPE_MASK      0xc0
314 #define CLNP_OPTION_SCOPE_SA_SPEC   0x40
315 #define CLNP_OPTION_SCOPE_DA_SPEC   0x80
316 #define CLNP_OPTION_SCOPE_GLOBAL    0xc0
317 
318 static const struct tok clnp_option_scope_values[] = {
319     { CLNP_OPTION_SCOPE_SA_SPEC, "Source Address Specific"},
320     { CLNP_OPTION_SCOPE_DA_SPEC, "Destination Address Specific"},
321     { CLNP_OPTION_SCOPE_GLOBAL, "Globally unique"},
322     { 0, NULL }
323 };
324 
325 static const struct tok clnp_option_sr_rr_values[] = {
326     { 0x0, "partial"},
327     { 0x1, "complete"},
328     { 0, NULL }
329 };
330 
331 static const struct tok clnp_option_sr_rr_string_values[] = {
332     { CLNP_OPTION_SOURCE_ROUTING, "source routing"},
333     { CLNP_OPTION_ROUTE_RECORDING, "recording of route in progress"},
334     { 0, NULL }
335 };
336 
337 static const struct tok clnp_option_qos_global_values[] = {
338     { 0x20, "reserved"},
339     { 0x10, "sequencing vs. delay"},
340     { 0x08, "congested"},
341     { 0x04, "delay vs. cost"},
342     { 0x02, "error vs. delay"},
343     { 0x01, "error vs. cost"},
344     { 0, NULL }
345 };
346 
347 #define ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP           3 /* draft-ietf-isis-traffic-05 */
348 #define ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID  4 /* rfc4205 */
349 #define ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID        5 /* draft-ietf-isis-traffic-05 */
350 #define ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR        6 /* draft-ietf-isis-traffic-05 */
351 #define ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR    8 /* draft-ietf-isis-traffic-05 */
352 #define ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW           9 /* draft-ietf-isis-traffic-05 */
353 #define ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW        10 /* draft-ietf-isis-traffic-05 */
354 #define ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW        11 /* rfc4124 */
355 #define ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS_OLD   12 /* draft-ietf-tewg-diff-te-proto-06 */
356 #define ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC            18 /* draft-ietf-isis-traffic-05 */
357 #define ISIS_SUBTLV_EXT_IS_REACH_LINK_ATTRIBUTE       19 /* draft-ietf-isis-link-attr-01 */
358 #define ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE 20 /* rfc4205 */
359 #define ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR    21 /* rfc4205 */
360 #define ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS       22 /* rfc4124 */
361 
362 #define ISIS_SUBTLV_SPB_METRIC                        29 /* rfc6329 */
363 
364 static const struct tok isis_ext_is_reach_subtlv_values[] = {
365     { ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP,            "Administrative groups" },
366     { ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID,   "Link Local/Remote Identifier" },
367     { ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID,         "Link Remote Identifier" },
368     { ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR,         "IPv4 interface address" },
369     { ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR,     "IPv4 neighbor address" },
370     { ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW,            "Maximum link bandwidth" },
371     { ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW,          "Reservable link bandwidth" },
372     { ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW,          "Unreserved bandwidth" },
373     { ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC,              "Traffic Engineering Metric" },
374     { ISIS_SUBTLV_EXT_IS_REACH_LINK_ATTRIBUTE,         "Link Attribute" },
375     { ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE,   "Link Protection Type" },
376     { ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR,      "Interface Switching Capability" },
377     { ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS_OLD,     "Bandwidth Constraints (old)" },
378     { ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS,         "Bandwidth Constraints" },
379     { ISIS_SUBTLV_SPB_METRIC,                          "SPB Metric" },
380     { 250,                                             "Reserved for cisco specific extensions" },
381     { 251,                                             "Reserved for cisco specific extensions" },
382     { 252,                                             "Reserved for cisco specific extensions" },
383     { 253,                                             "Reserved for cisco specific extensions" },
384     { 254,                                             "Reserved for cisco specific extensions" },
385     { 255,                                             "Reserved for future expansion" },
386     { 0, NULL }
387 };
388 
389 #define ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32          1 /* draft-ietf-isis-admin-tags-01 */
390 #define ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64          2 /* draft-ietf-isis-admin-tags-01 */
391 #define ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR  117 /* draft-ietf-isis-wg-multi-topology-05 */
392 
393 static const struct tok isis_ext_ip_reach_subtlv_values[] = {
394     { ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32,           "32-Bit Administrative tag" },
395     { ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64,           "64-Bit Administrative tag" },
396     { ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR,     "Management Prefix Color" },
397     { 0, NULL }
398 };
399 
400 static const struct tok isis_subtlv_link_attribute_values[] = {
401     { 0x01, "Local Protection Available" },
402     { 0x02, "Link excluded from local protection path" },
403     { 0x04, "Local maintenance required"},
404     { 0, NULL }
405 };
406 
407 #define ISIS_SUBTLV_AUTH_SIMPLE        1
408 #define ISIS_SUBTLV_AUTH_GENERIC       3 /* rfc 5310 */
409 #define ISIS_SUBTLV_AUTH_MD5          54
410 #define ISIS_SUBTLV_AUTH_MD5_LEN      16
411 #define ISIS_SUBTLV_AUTH_PRIVATE     255
412 
413 static const struct tok isis_subtlv_auth_values[] = {
414     { ISIS_SUBTLV_AUTH_SIMPLE,	"simple text password"},
415     { ISIS_SUBTLV_AUTH_GENERIC, "Generic Crypto key-id"},
416     { ISIS_SUBTLV_AUTH_MD5,	"HMAC-MD5 password"},
417     { ISIS_SUBTLV_AUTH_PRIVATE,	"Routing Domain private password"},
418     { 0, NULL }
419 };
420 
421 #define ISIS_SUBTLV_IDRP_RES           0
422 #define ISIS_SUBTLV_IDRP_LOCAL         1
423 #define ISIS_SUBTLV_IDRP_ASN           2
424 
425 static const struct tok isis_subtlv_idrp_values[] = {
426     { ISIS_SUBTLV_IDRP_RES,         "Reserved"},
427     { ISIS_SUBTLV_IDRP_LOCAL,       "Routing-Domain Specific"},
428     { ISIS_SUBTLV_IDRP_ASN,         "AS Number Tag"},
429     { 0, NULL}
430 };
431 
432 #define ISIS_SUBTLV_SPB_MCID          4
433 #define ISIS_SUBTLV_SPB_DIGEST        5
434 #define ISIS_SUBTLV_SPB_BVID          6
435 
436 #define ISIS_SUBTLV_SPB_INSTANCE      1
437 #define ISIS_SUBTLV_SPBM_SI           3
438 
439 #define ISIS_SPB_MCID_LEN                         51
440 #define ISIS_SUBTLV_SPB_MCID_MIN_LEN              102
441 #define ISIS_SUBTLV_SPB_DIGEST_MIN_LEN            33
442 #define ISIS_SUBTLV_SPB_BVID_MIN_LEN              6
443 #define ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN          19
444 #define ISIS_SUBTLV_SPB_INSTANCE_VLAN_TUPLE_LEN   8
445 
446 static const struct tok isis_mt_port_cap_subtlv_values[] = {
447     { ISIS_SUBTLV_SPB_MCID,           "SPB MCID" },
448     { ISIS_SUBTLV_SPB_DIGEST,         "SPB Digest" },
449     { ISIS_SUBTLV_SPB_BVID,           "SPB BVID" },
450     { 0, NULL }
451 };
452 
453 static const struct tok isis_mt_capability_subtlv_values[] = {
454     { ISIS_SUBTLV_SPB_INSTANCE,      "SPB Instance" },
455     { ISIS_SUBTLV_SPBM_SI,      "SPBM Service Identifier and Unicast Address" },
456     { 0, NULL }
457 };
458 
459 struct isis_spb_mcid {
460   u_int8_t  format_id;
461   u_int8_t  name[32];
462   u_int8_t  revision_lvl[2];
463   u_int8_t  digest[16];
464 };
465 
466 struct isis_subtlv_spb_mcid {
467   struct isis_spb_mcid mcid;
468   struct isis_spb_mcid aux_mcid;
469 };
470 
471 struct isis_subtlv_spb_instance {
472   u_int8_t cist_root_id[8];
473   u_int8_t cist_external_root_path_cost[4];
474   u_int8_t bridge_priority[2];
475   u_int8_t spsourceid[4];
476   u_int8_t no_of_trees;
477 };
478 
479 #define CLNP_SEGMENT_PART  0x80
480 #define CLNP_MORE_SEGMENTS 0x40
481 #define CLNP_REQUEST_ER    0x20
482 
483 static const struct tok clnp_flag_values[] = {
484     { CLNP_SEGMENT_PART, "Segmentation permitted"},
485     { CLNP_MORE_SEGMENTS, "more Segments"},
486     { CLNP_REQUEST_ER, "request Error Report"},
487     { 0, NULL}
488 };
489 
490 #define ISIS_MASK_LSP_OL_BIT(x)            ((x)&0x4)
491 #define ISIS_MASK_LSP_ISTYPE_BITS(x)       ((x)&0x3)
492 #define ISIS_MASK_LSP_PARTITION_BIT(x)     ((x)&0x80)
493 #define ISIS_MASK_LSP_ATT_BITS(x)          ((x)&0x78)
494 #define ISIS_MASK_LSP_ATT_ERROR_BIT(x)     ((x)&0x40)
495 #define ISIS_MASK_LSP_ATT_EXPENSE_BIT(x)   ((x)&0x20)
496 #define ISIS_MASK_LSP_ATT_DELAY_BIT(x)     ((x)&0x10)
497 #define ISIS_MASK_LSP_ATT_DEFAULT_BIT(x)   ((x)&0x8)
498 
499 #define ISIS_MASK_MTID(x)                  ((x)&0x0fff)
500 #define ISIS_MASK_MTFLAGS(x)               ((x)&0xf000)
501 
502 static const struct tok isis_mt_flag_values[] = {
503     { 0x4000,                  "ATT bit set"},
504     { 0x8000,                  "Overload bit set"},
505     { 0, NULL}
506 };
507 
508 #define ISIS_MASK_TLV_EXTD_IP_UPDOWN(x)     ((x)&0x80)
509 #define ISIS_MASK_TLV_EXTD_IP_SUBTLV(x)     ((x)&0x40)
510 
511 #define ISIS_MASK_TLV_EXTD_IP6_IE(x)        ((x)&0x40)
512 #define ISIS_MASK_TLV_EXTD_IP6_SUBTLV(x)    ((x)&0x20)
513 
514 #define ISIS_LSP_TLV_METRIC_SUPPORTED(x)   ((x)&0x80)
515 #define ISIS_LSP_TLV_METRIC_IE(x)          ((x)&0x40)
516 #define ISIS_LSP_TLV_METRIC_UPDOWN(x)      ((x)&0x80)
517 #define ISIS_LSP_TLV_METRIC_VALUE(x)	   ((x)&0x3f)
518 
519 #define ISIS_MASK_TLV_SHARED_RISK_GROUP(x) ((x)&0x1)
520 
521 static const struct tok isis_mt_values[] = {
522     { 0,    "IPv4 unicast"},
523     { 1,    "In-Band Management"},
524     { 2,    "IPv6 unicast"},
525     { 3,    "Multicast"},
526     { 4095, "Development, Experimental or Proprietary"},
527     { 0, NULL }
528 };
529 
530 static const struct tok isis_iih_circuit_type_values[] = {
531     { 1,    "Level 1 only"},
532     { 2,    "Level 2 only"},
533     { 3,    "Level 1, Level 2"},
534     { 0, NULL}
535 };
536 
537 #define ISIS_LSP_TYPE_UNUSED0   0
538 #define ISIS_LSP_TYPE_LEVEL_1   1
539 #define ISIS_LSP_TYPE_UNUSED2   2
540 #define ISIS_LSP_TYPE_LEVEL_2   3
541 
542 static const struct tok isis_lsp_istype_values[] = {
543     { ISIS_LSP_TYPE_UNUSED0,	"Unused 0x0 (invalid)"},
544     { ISIS_LSP_TYPE_LEVEL_1,	"L1 IS"},
545     { ISIS_LSP_TYPE_UNUSED2,	"Unused 0x2 (invalid)"},
546     { ISIS_LSP_TYPE_LEVEL_2,	"L2 IS"},
547     { 0, NULL }
548 };
549 
550 /*
551  * Katz's point to point adjacency TLV uses codes to tell us the state of
552  * the remote adjacency.  Enumerate them.
553  */
554 
555 #define ISIS_PTP_ADJ_UP   0
556 #define ISIS_PTP_ADJ_INIT 1
557 #define ISIS_PTP_ADJ_DOWN 2
558 
559 static const struct tok isis_ptp_adjancey_values[] = {
560     { ISIS_PTP_ADJ_UP,    "Up" },
561     { ISIS_PTP_ADJ_INIT,  "Initializing" },
562     { ISIS_PTP_ADJ_DOWN,  "Down" },
563     { 0, NULL}
564 };
565 
566 struct isis_tlv_ptp_adj {
567     u_int8_t adjacency_state;
568     u_int8_t extd_local_circuit_id[4];
569     u_int8_t neighbor_sysid[SYSTEM_ID_LEN];
570     u_int8_t neighbor_extd_local_circuit_id[4];
571 };
572 
573 static void osi_print_cksum(const u_int8_t *pptr, u_int16_t checksum,
574                             u_int checksum_offset, u_int length);
575 static int clnp_print(const u_int8_t *, u_int);
576 static void esis_print(const u_int8_t *, u_int);
577 static int isis_print(const u_int8_t *, u_int);
578 
579 struct isis_metric_block {
580     u_int8_t metric_default;
581     u_int8_t metric_delay;
582     u_int8_t metric_expense;
583     u_int8_t metric_error;
584 };
585 
586 struct isis_tlv_is_reach {
587     struct isis_metric_block isis_metric_block;
588     u_int8_t neighbor_nodeid[NODE_ID_LEN];
589 };
590 
591 struct isis_tlv_es_reach {
592     struct isis_metric_block isis_metric_block;
593     u_int8_t neighbor_sysid[SYSTEM_ID_LEN];
594 };
595 
596 struct isis_tlv_ip_reach {
597     struct isis_metric_block isis_metric_block;
598     u_int8_t prefix[4];
599     u_int8_t mask[4];
600 };
601 
602 static const struct tok isis_is_reach_virtual_values[] = {
603     { 0,    "IsNotVirtual"},
604     { 1,    "IsVirtual"},
605     { 0, NULL }
606 };
607 
608 static const struct tok isis_restart_flag_values[] = {
609     { 0x1,  "Restart Request"},
610     { 0x2,  "Restart Acknowledgement"},
611     { 0x4,  "Suppress adjacency advertisement"},
612     { 0, NULL }
613 };
614 
615 struct isis_common_header {
616     u_int8_t nlpid;
617     u_int8_t fixed_len;
618     u_int8_t version;			/* Protocol version */
619     u_int8_t id_length;
620     u_int8_t pdu_type;		        /* 3 MSbits are reserved */
621     u_int8_t pdu_version;		/* Packet format version */
622     u_int8_t reserved;
623     u_int8_t max_area;
624 };
625 
626 struct isis_iih_lan_header {
627     u_int8_t circuit_type;
628     u_int8_t source_id[SYSTEM_ID_LEN];
629     u_int8_t holding_time[2];
630     u_int8_t pdu_len[2];
631     u_int8_t priority;
632     u_int8_t lan_id[NODE_ID_LEN];
633 };
634 
635 struct isis_iih_ptp_header {
636     u_int8_t circuit_type;
637     u_int8_t source_id[SYSTEM_ID_LEN];
638     u_int8_t holding_time[2];
639     u_int8_t pdu_len[2];
640     u_int8_t circuit_id;
641 };
642 
643 struct isis_lsp_header {
644     u_int8_t pdu_len[2];
645     u_int8_t remaining_lifetime[2];
646     u_int8_t lsp_id[LSP_ID_LEN];
647     u_int8_t sequence_number[4];
648     u_int8_t checksum[2];
649     u_int8_t typeblock;
650 };
651 
652 struct isis_csnp_header {
653     u_int8_t pdu_len[2];
654     u_int8_t source_id[NODE_ID_LEN];
655     u_int8_t start_lsp_id[LSP_ID_LEN];
656     u_int8_t end_lsp_id[LSP_ID_LEN];
657 };
658 
659 struct isis_psnp_header {
660     u_int8_t pdu_len[2];
661     u_int8_t source_id[NODE_ID_LEN];
662 };
663 
664 struct isis_tlv_lsp {
665     u_int8_t remaining_lifetime[2];
666     u_int8_t lsp_id[LSP_ID_LEN];
667     u_int8_t sequence_number[4];
668     u_int8_t checksum[2];
669 };
670 
671 #define ISIS_COMMON_HEADER_SIZE (sizeof(struct isis_common_header))
672 #define ISIS_IIH_LAN_HEADER_SIZE (sizeof(struct isis_iih_lan_header))
673 #define ISIS_IIH_PTP_HEADER_SIZE (sizeof(struct isis_iih_ptp_header))
674 #define ISIS_LSP_HEADER_SIZE (sizeof(struct isis_lsp_header))
675 #define ISIS_CSNP_HEADER_SIZE (sizeof(struct isis_csnp_header))
676 #define ISIS_PSNP_HEADER_SIZE (sizeof(struct isis_psnp_header))
677 
678 void isoclns_print(const u_int8_t *p, u_int length, u_int caplen)
679 {
680         if (caplen <= 1) { /* enough bytes on the wire ? */
681             printf("|OSI");
682             return;
683         }
684 
685         if (eflag)
686             printf("OSI NLPID %s (0x%02x): ",
687                    tok2str(nlpid_values,"Unknown",*p),
688                    *p);
689 
690 	switch (*p) {
691 
692 	case NLPID_CLNP:
693 		if (!clnp_print(p, length))
694                         print_unknown_data(p,"\n\t",caplen);
695 		break;
696 
697 	case NLPID_ESIS:
698 		esis_print(p, length);
699 		return;
700 
701 	case NLPID_ISIS:
702 		if (!isis_print(p, length))
703                         print_unknown_data(p,"\n\t",caplen);
704 		break;
705 
706 	case NLPID_NULLNS:
707 		(void)printf("%slength: %u",
708 		             eflag ? "" : ", ",
709                              length);
710 		break;
711 
712         case NLPID_Q933:
713                 q933_print(p+1, length-1);
714                 break;
715 
716         case NLPID_IP:
717 		ip_print(gndo, p+1, length-1);
718                 break;
719 
720 #ifdef INET6
721         case NLPID_IP6:
722                 ip6_print(gndo, p+1, length-1);
723                 break;
724 #endif
725 
726         case NLPID_PPP:
727                 ppp_print(p+1, length-1);
728                 break;
729 
730 	default:
731                 if (!eflag)
732                     printf("OSI NLPID 0x%02x unknown",*p);
733 		(void)printf("%slength: %u",
734 		             eflag ? "" : ", ",
735                              length);
736 		if (caplen > 1)
737                         print_unknown_data(p,"\n\t",caplen);
738 		break;
739 	}
740 }
741 
742 #define	CLNP_PDU_ER	 1
743 #define	CLNP_PDU_DT	28
744 #define	CLNP_PDU_MD	29
745 #define	CLNP_PDU_ERQ	30
746 #define	CLNP_PDU_ERP	31
747 
748 static const struct tok clnp_pdu_values[] = {
749     { CLNP_PDU_ER,  "Error Report"},
750     { CLNP_PDU_MD,  "MD"},
751     { CLNP_PDU_DT,  "Data"},
752     { CLNP_PDU_ERQ, "Echo Request"},
753     { CLNP_PDU_ERP, "Echo Response"},
754     { 0, NULL }
755 };
756 
757 struct clnp_header_t {
758     u_int8_t nlpid;
759     u_int8_t length_indicator;
760     u_int8_t version;
761     u_int8_t lifetime; /* units of 500ms */
762     u_int8_t type;
763     u_int8_t segment_length[2];
764     u_int8_t cksum[2];
765 };
766 
767 struct clnp_segment_header_t {
768     u_int8_t data_unit_id[2];
769     u_int8_t segment_offset[2];
770     u_int8_t total_length[2];
771 };
772 
773 /*
774  * clnp_print
775  * Decode CLNP packets.  Return 0 on error.
776  */
777 
778 static int clnp_print (const u_int8_t *pptr, u_int length)
779 {
780 	const u_int8_t *optr,*source_address,*dest_address;
781         u_int li,tlen,nsap_offset,source_address_length,dest_address_length, clnp_pdu_type, clnp_flags;
782 	const struct clnp_header_t *clnp_header;
783 	const struct clnp_segment_header_t *clnp_segment_header;
784         u_int8_t rfd_error_major,rfd_error_minor;
785 
786 	clnp_header = (const struct clnp_header_t *) pptr;
787         TCHECK(*clnp_header);
788 
789         li = clnp_header->length_indicator;
790         optr = pptr;
791 
792         if (!eflag)
793             printf("CLNP");
794 
795         /*
796          * Sanity checking of the header.
797          */
798 
799         if (clnp_header->version != CLNP_VERSION) {
800             printf("version %d packet not supported", clnp_header->version);
801             return (0);
802         }
803 
804         /* FIXME further header sanity checking */
805 
806         clnp_pdu_type = clnp_header->type & CLNP_PDU_TYPE_MASK;
807         clnp_flags = clnp_header->type & CLNP_FLAG_MASK;
808 
809         pptr += sizeof(struct clnp_header_t);
810         li -= sizeof(struct clnp_header_t);
811         dest_address_length = *pptr;
812         dest_address = pptr + 1;
813 
814         pptr += (1 + dest_address_length);
815         li -= (1 + dest_address_length);
816         source_address_length = *pptr;
817         source_address = pptr +1;
818 
819         pptr += (1 + source_address_length);
820         li -= (1 + source_address_length);
821 
822         if (vflag < 1) {
823             printf("%s%s > %s, %s, length %u",
824                    eflag ? "" : ", ",
825                    isonsap_string(source_address, source_address_length),
826                    isonsap_string(dest_address, dest_address_length),
827                    tok2str(clnp_pdu_values,"unknown (%u)",clnp_pdu_type),
828                    length);
829             return (1);
830         }
831         printf("%slength %u",eflag ? "" : ", ",length);
832 
833         printf("\n\t%s PDU, hlen: %u, v: %u, lifetime: %u.%us, Segment PDU length: %u, checksum: 0x%04x",
834                tok2str(clnp_pdu_values, "unknown (%u)",clnp_pdu_type),
835                clnp_header->length_indicator,
836                clnp_header->version,
837                clnp_header->lifetime/2,
838                (clnp_header->lifetime%2)*5,
839                EXTRACT_16BITS(clnp_header->segment_length),
840                EXTRACT_16BITS(clnp_header->cksum));
841 
842         osi_print_cksum(optr, EXTRACT_16BITS(clnp_header->cksum), 7,
843                         clnp_header->length_indicator);
844 
845         printf("\n\tFlags [%s]",
846                bittok2str(clnp_flag_values,"none",clnp_flags));
847 
848         printf("\n\tsource address (length %u): %s\n\tdest   address (length %u): %s",
849                source_address_length,
850                isonsap_string(source_address, source_address_length),
851                dest_address_length,
852                isonsap_string(dest_address,dest_address_length));
853 
854         if (clnp_flags & CLNP_SEGMENT_PART) {
855             	clnp_segment_header = (const struct clnp_segment_header_t *) pptr;
856                 TCHECK(*clnp_segment_header);
857                 printf("\n\tData Unit ID: 0x%04x, Segment Offset: %u, Total PDU Length: %u",
858                        EXTRACT_16BITS(clnp_segment_header->data_unit_id),
859                        EXTRACT_16BITS(clnp_segment_header->segment_offset),
860                        EXTRACT_16BITS(clnp_segment_header->total_length));
861                 pptr+=sizeof(const struct clnp_segment_header_t);
862                 li-=sizeof(const struct clnp_segment_header_t);
863         }
864 
865         /* now walk the options */
866         while (li >= 2) {
867             u_int op, opli;
868             const u_int8_t *tptr;
869 
870             TCHECK2(*pptr, 2);
871             if (li < 2) {
872                 printf(", bad opts/li");
873                 return (0);
874             }
875             op = *pptr++;
876             opli = *pptr++;
877             li -= 2;
878             TCHECK2(*pptr, opli);
879             if (opli > li) {
880                 printf(", opt (%d) too long", op);
881                 return (0);
882             }
883             li -= opli;
884             tptr = pptr;
885             tlen = opli;
886 
887             printf("\n\t  %s Option #%u, length %u, value: ",
888                    tok2str(clnp_option_values,"Unknown",op),
889                    op,
890                    opli);
891 
892             switch (op) {
893 
894 
895             case CLNP_OPTION_ROUTE_RECORDING: /* those two options share the format */
896             case CLNP_OPTION_SOURCE_ROUTING:
897                     printf("%s %s",
898                            tok2str(clnp_option_sr_rr_values,"Unknown",*tptr),
899                            tok2str(clnp_option_sr_rr_string_values,"Unknown Option %u",op));
900                     nsap_offset=*(tptr+1);
901                     if (nsap_offset == 0) {
902                             printf(" Bad NSAP offset (0)");
903                             break;
904                     }
905                     nsap_offset-=1; /* offset to nsap list */
906                     if (nsap_offset > tlen) {
907                             printf(" Bad NSAP offset (past end of option)");
908                             break;
909                     }
910                     tptr+=nsap_offset;
911                     tlen-=nsap_offset;
912                     while (tlen > 0) {
913                             source_address_length=*tptr;
914                             if (tlen < source_address_length+1) {
915                                     printf("\n\t    NSAP address goes past end of option");
916                                     break;
917                             }
918                             if (source_address_length > 0) {
919                                     source_address=(tptr+1);
920                                     TCHECK2(*source_address, source_address_length);
921                                     printf("\n\t    NSAP address (length %u): %s",
922                                            source_address_length,
923                                            isonsap_string(source_address, source_address_length));
924                             }
925                             tlen-=source_address_length+1;
926                     }
927                     break;
928 
929             case CLNP_OPTION_PRIORITY:
930                     printf("0x%1x", *tptr&0x0f);
931                     break;
932 
933             case CLNP_OPTION_QOS_MAINTENANCE:
934                     printf("\n\t    Format Code: %s",
935                            tok2str(clnp_option_scope_values,"Reserved",*tptr&CLNP_OPTION_SCOPE_MASK));
936 
937                     if ((*tptr&CLNP_OPTION_SCOPE_MASK) == CLNP_OPTION_SCOPE_GLOBAL)
938                             printf("\n\t    QoS Flags [%s]",
939                                    bittok2str(clnp_option_qos_global_values,
940                                               "none",
941                                               *tptr&CLNP_OPTION_OPTION_QOS_MASK));
942                     break;
943 
944             case CLNP_OPTION_SECURITY:
945                     printf("\n\t    Format Code: %s, Security-Level %u",
946                            tok2str(clnp_option_scope_values,"Reserved",*tptr&CLNP_OPTION_SCOPE_MASK),
947                            *(tptr+1));
948                     break;
949 
950             case CLNP_OPTION_DISCARD_REASON:
951                 rfd_error_major = (*tptr&0xf0) >> 4;
952                 rfd_error_minor = *tptr&0x0f;
953                 printf("\n\t    Class: %s Error (0x%01x), %s (0x%01x)",
954                        tok2str(clnp_option_rfd_class_values,"Unknown",rfd_error_major),
955                        rfd_error_major,
956                        tok2str(clnp_option_rfd_error_class[rfd_error_major],"Unknown",rfd_error_minor),
957                        rfd_error_minor);
958                 break;
959 
960             case CLNP_OPTION_PADDING:
961                     printf("padding data");
962                 break;
963 
964                 /*
965                  * FIXME those are the defined Options that lack a decoder
966                  * you are welcome to contribute code ;-)
967                  */
968 
969             default:
970                 print_unknown_data(tptr,"\n\t  ",opli);
971                 break;
972             }
973             if (vflag > 1)
974                 print_unknown_data(pptr,"\n\t  ",opli);
975             pptr += opli;
976         }
977 
978         switch (clnp_pdu_type) {
979 
980         case    CLNP_PDU_ER: /* fall through */
981         case 	CLNP_PDU_ERP:
982             TCHECK(*pptr);
983             if (*(pptr) == NLPID_CLNP) {
984                 printf("\n\t-----original packet-----\n\t");
985                 /* FIXME recursion protection */
986                 clnp_print(pptr, length-clnp_header->length_indicator);
987                 break;
988             }
989 
990         case 	CLNP_PDU_DT:
991         case 	CLNP_PDU_MD:
992         case 	CLNP_PDU_ERQ:
993 
994         default:
995             /* dump the PDU specific data */
996             if (length-(pptr-optr) > 0) {
997                 printf("\n\t  undecoded non-header data, length %u",length-clnp_header->length_indicator);
998                 print_unknown_data(pptr,"\n\t  ",length-(pptr-optr));
999             }
1000         }
1001 
1002         return (1);
1003 
1004  trunc:
1005     fputs("[|clnp]", stdout);
1006     return (1);
1007 
1008 }
1009 
1010 
1011 #define	ESIS_PDU_REDIRECT	6
1012 #define	ESIS_PDU_ESH	        2
1013 #define	ESIS_PDU_ISH	        4
1014 
1015 static const struct tok esis_pdu_values[] = {
1016     { ESIS_PDU_REDIRECT, "redirect"},
1017     { ESIS_PDU_ESH,      "ESH"},
1018     { ESIS_PDU_ISH,      "ISH"},
1019     { 0, NULL }
1020 };
1021 
1022 struct esis_header_t {
1023 	u_int8_t nlpid;
1024 	u_int8_t length_indicator;
1025 	u_int8_t version;
1026 	u_int8_t reserved;
1027 	u_int8_t type;
1028 	u_int8_t holdtime[2];
1029 	u_int8_t cksum[2];
1030 };
1031 
1032 static void
1033 esis_print(const u_int8_t *pptr, u_int length)
1034 {
1035 	const u_int8_t *optr;
1036 	u_int li,esis_pdu_type,source_address_length, source_address_number;
1037 	const struct esis_header_t *esis_header;
1038 
1039         if (!eflag)
1040             printf("ES-IS");
1041 
1042 	if (length <= 2) {
1043 		if (qflag)
1044 			printf("bad pkt!");
1045 		else
1046 			printf("no header at all!");
1047 		return;
1048 	}
1049 
1050 	esis_header = (const struct esis_header_t *) pptr;
1051         TCHECK(*esis_header);
1052         li = esis_header->length_indicator;
1053         optr = pptr;
1054 
1055         /*
1056          * Sanity checking of the header.
1057          */
1058 
1059         if (esis_header->nlpid != NLPID_ESIS) {
1060             printf(" nlpid 0x%02x packet not supported", esis_header->nlpid);
1061             return;
1062         }
1063 
1064         if (esis_header->version != ESIS_VERSION) {
1065             printf(" version %d packet not supported", esis_header->version);
1066             return;
1067         }
1068 
1069 	if (li > length) {
1070             printf(" length indicator(%d) > PDU size (%d)!", li, length);
1071             return;
1072 	}
1073 
1074 	if (li < sizeof(struct esis_header_t) + 2) {
1075             printf(" length indicator < min PDU size %d:", li);
1076             while (--length != 0)
1077                 printf("%02X", *pptr++);
1078             return;
1079 	}
1080 
1081         esis_pdu_type = esis_header->type & ESIS_PDU_TYPE_MASK;
1082 
1083         if (vflag < 1) {
1084             printf("%s%s, length %u",
1085                    eflag ? "" : ", ",
1086                    tok2str(esis_pdu_values,"unknown type (%u)",esis_pdu_type),
1087                    length);
1088             return;
1089         } else
1090             printf("%slength %u\n\t%s (%u)",
1091                    eflag ? "" : ", ",
1092                    length,
1093                    tok2str(esis_pdu_values,"unknown type: %u", esis_pdu_type),
1094                    esis_pdu_type);
1095 
1096         printf(", v: %u%s", esis_header->version, esis_header->version == ESIS_VERSION ? "" : "unsupported" );
1097         printf(", checksum: 0x%04x", EXTRACT_16BITS(esis_header->cksum));
1098 
1099         osi_print_cksum(pptr, EXTRACT_16BITS(esis_header->cksum), 7, li);
1100 
1101         printf(", holding time: %us, length indicator: %u",EXTRACT_16BITS(esis_header->holdtime),li);
1102 
1103         if (vflag > 1)
1104             print_unknown_data(optr,"\n\t",sizeof(struct esis_header_t));
1105 
1106 	pptr += sizeof(struct esis_header_t);
1107 	li -= sizeof(struct esis_header_t);
1108 
1109 	switch (esis_pdu_type) {
1110 	case ESIS_PDU_REDIRECT: {
1111 		const u_int8_t *dst, *snpa, *neta;
1112 		u_int dstl, snpal, netal;
1113 
1114 		TCHECK(*pptr);
1115 		if (li < 1) {
1116 			printf(", bad redirect/li");
1117 			return;
1118 		}
1119 		dstl = *pptr;
1120 		pptr++;
1121 		li--;
1122 		TCHECK2(*pptr, dstl);
1123 		if (li < dstl) {
1124 			printf(", bad redirect/li");
1125 			return;
1126 		}
1127 		dst = pptr;
1128 		pptr += dstl;
1129                 li -= dstl;
1130 		printf("\n\t  %s", isonsap_string(dst,dstl));
1131 
1132 		TCHECK(*pptr);
1133 		if (li < 1) {
1134 			printf(", bad redirect/li");
1135 			return;
1136 		}
1137 		snpal = *pptr;
1138 		pptr++;
1139 		li--;
1140 		TCHECK2(*pptr, snpal);
1141 		if (li < snpal) {
1142 			printf(", bad redirect/li");
1143 			return;
1144 		}
1145 		snpa = pptr;
1146 		pptr += snpal;
1147                 li -= snpal;
1148 		TCHECK(*pptr);
1149 		if (li < 1) {
1150 			printf(", bad redirect/li");
1151 			return;
1152 		}
1153 		netal = *pptr;
1154 		pptr++;
1155 		TCHECK2(*pptr, netal);
1156 		if (li < netal) {
1157 			printf(", bad redirect/li");
1158 			return;
1159 		}
1160 		neta = pptr;
1161 		pptr += netal;
1162                 li -= netal;
1163 
1164 		if (netal == 0)
1165 			printf("\n\t  %s", etheraddr_string(snpa));
1166 		else
1167 			printf("\n\t  %s", isonsap_string(neta,netal));
1168 		break;
1169 	}
1170 
1171 	case ESIS_PDU_ESH:
1172             TCHECK(*pptr);
1173             if (li < 1) {
1174                 printf(", bad esh/li");
1175                 return;
1176             }
1177             source_address_number = *pptr;
1178             pptr++;
1179             li--;
1180 
1181             printf("\n\t  Number of Source Addresses: %u", source_address_number);
1182 
1183             while (source_address_number > 0) {
1184                 TCHECK(*pptr);
1185             	if (li < 1) {
1186                     printf(", bad esh/li");
1187             	    return;
1188             	}
1189                 source_address_length = *pptr;
1190                 pptr++;
1191             	li--;
1192 
1193                 TCHECK2(*pptr, source_address_length);
1194             	if (li < source_address_length) {
1195                     printf(", bad esh/li");
1196             	    return;
1197             	}
1198                 printf("\n\t  NET (length: %u): %s",
1199                        source_address_length,
1200                        isonsap_string(pptr,source_address_length));
1201                 pptr += source_address_length;
1202                 li -= source_address_length;
1203                 source_address_number--;
1204             }
1205 
1206             break;
1207 
1208 	case ESIS_PDU_ISH: {
1209             TCHECK(*pptr);
1210             if (li < 1) {
1211                 printf(", bad ish/li");
1212                 return;
1213             }
1214             source_address_length = *pptr;
1215             pptr++;
1216             li--;
1217             TCHECK2(*pptr, source_address_length);
1218             if (li < source_address_length) {
1219                 printf(", bad ish/li");
1220                 return;
1221             }
1222             printf("\n\t  NET (length: %u): %s", source_address_length, isonsap_string(pptr, source_address_length));
1223             pptr += source_address_length;
1224             li -= source_address_length;
1225             break;
1226 	}
1227 
1228 	default:
1229             if (vflag <= 1) {
1230 		    if (pptr < snapend)
1231                             print_unknown_data(pptr,"\n\t  ",snapend-pptr);
1232             }
1233             return;
1234 	}
1235 
1236         /* now walk the options */
1237         while (li != 0) {
1238             u_int op, opli;
1239             const u_int8_t *tptr;
1240 
1241             if (li < 2) {
1242                 printf(", bad opts/li");
1243                 return;
1244             }
1245             TCHECK2(*pptr, 2);
1246             op = *pptr++;
1247             opli = *pptr++;
1248             li -= 2;
1249             if (opli > li) {
1250                 printf(", opt (%d) too long", op);
1251                 return;
1252             }
1253             li -= opli;
1254             tptr = pptr;
1255 
1256             printf("\n\t  %s Option #%u, length %u, value: ",
1257                    tok2str(esis_option_values,"Unknown",op),
1258                    op,
1259                    opli);
1260 
1261             switch (op) {
1262 
1263             case ESIS_OPTION_ES_CONF_TIME:
1264                 if (opli == 2) {
1265                     TCHECK2(*pptr, 2);
1266                     printf("%us", EXTRACT_16BITS(tptr));
1267                 } else
1268                     printf("(bad length)");
1269                 break;
1270 
1271             case ESIS_OPTION_PROTOCOLS:
1272                 while (opli>0) {
1273                     TCHECK(*pptr);
1274                     printf("%s (0x%02x)",
1275                            tok2str(nlpid_values,
1276                                    "unknown",
1277                                    *tptr),
1278                            *tptr);
1279                     if (opli>1) /* further NPLIDs ? - put comma */
1280                         printf(", ");
1281                     tptr++;
1282                     opli--;
1283                 }
1284                 break;
1285 
1286                 /*
1287                  * FIXME those are the defined Options that lack a decoder
1288                  * you are welcome to contribute code ;-)
1289                  */
1290 
1291             case ESIS_OPTION_QOS_MAINTENANCE:
1292             case ESIS_OPTION_SECURITY:
1293             case ESIS_OPTION_PRIORITY:
1294             case ESIS_OPTION_ADDRESS_MASK:
1295             case ESIS_OPTION_SNPA_MASK:
1296 
1297             default:
1298                 print_unknown_data(tptr,"\n\t  ",opli);
1299                 break;
1300             }
1301             if (vflag > 1)
1302                 print_unknown_data(pptr,"\n\t  ",opli);
1303             pptr += opli;
1304         }
1305 trunc:
1306 	return;
1307 }
1308 
1309 
1310 static void
1311 isis_print_mcid (const struct isis_spb_mcid *mcid)
1312 {
1313   int i;
1314 
1315   printf( "ID: %d, Name: ", mcid->format_id);
1316 
1317   for(i=0; i<32; i++)
1318   {
1319     printf("%c", mcid->name[i]);
1320     if(mcid->name[i] == '\0')
1321         break;
1322   }
1323 
1324   printf("\n\t              Lvl: %d",
1325           EXTRACT_16BITS(mcid->revision_lvl));
1326 
1327   printf( ", Digest: ");
1328 
1329   for(i=0;i<16;i++)
1330     printf("%.2x ",mcid->digest[i]);
1331 }
1332 
1333 static int
1334 isis_print_mt_port_cap_subtlv (const u_int8_t *tptr, int len)
1335 {
1336   int stlv_type, stlv_len;
1337   const struct isis_subtlv_spb_mcid *subtlv_spb_mcid;
1338   int i;
1339 
1340   while (len > 0)
1341   {
1342     stlv_type = *(tptr++);
1343     stlv_len  = *(tptr++);
1344 
1345     /* first lets see if we know the subTLVs name*/
1346     printf("\n\t       %s subTLV #%u, length: %u",
1347                tok2str(isis_mt_port_cap_subtlv_values, "unknown", stlv_type),
1348                stlv_type,
1349                stlv_len);
1350 
1351     /*len -= TLV_TYPE_LEN_OFFSET;*/
1352     len = len -2;
1353 
1354     switch (stlv_type)
1355     {
1356       case ISIS_SUBTLV_SPB_MCID:
1357       {
1358         if (!TTEST2(*(tptr), ISIS_SUBTLV_SPB_MCID_MIN_LEN))
1359           goto trunctlv;
1360 
1361         subtlv_spb_mcid = (struct isis_subtlv_spb_mcid *)tptr;
1362 
1363         printf( "\n\t         MCID: ");
1364         isis_print_mcid (&(subtlv_spb_mcid->mcid));
1365 
1366           /*tptr += SPB_MCID_MIN_LEN;
1367             len -= SPB_MCID_MIN_LEN; */
1368 
1369         printf( "\n\t         AUX-MCID: ");
1370         isis_print_mcid (&(subtlv_spb_mcid->aux_mcid));
1371 
1372           /*tptr += SPB_MCID_MIN_LEN;
1373             len -= SPB_MCID_MIN_LEN; */
1374         tptr = tptr + sizeof(struct isis_subtlv_spb_mcid);
1375         len = len - sizeof(struct isis_subtlv_spb_mcid);
1376 
1377         break;
1378       }
1379 
1380       case ISIS_SUBTLV_SPB_DIGEST:
1381       {
1382         if (!TTEST2(*(tptr), ISIS_SUBTLV_SPB_DIGEST_MIN_LEN))
1383           goto trunctlv;
1384 
1385         printf ("\n\t        RES: %d V: %d A: %d D: %d",
1386                         (*(tptr) >> 5), (((*tptr)>> 4) & 0x01),
1387                         ((*(tptr) >> 2) & 0x03), ((*tptr) & 0x03));
1388 
1389         tptr++;
1390 
1391         printf( "\n\t         Digest: ");
1392 
1393         for(i=1;i<=8; i++)
1394         {
1395             printf("%08x ", EXTRACT_32BITS(tptr));
1396             if (i%4 == 0 && i != 8)
1397               printf("\n\t                 ");
1398             tptr = tptr + 4;
1399         }
1400 
1401         len = len - ISIS_SUBTLV_SPB_DIGEST_MIN_LEN;
1402 
1403         break;
1404       }
1405 
1406       case ISIS_SUBTLV_SPB_BVID:
1407       {
1408         if (!TTEST2(*(tptr), stlv_len))
1409           goto trunctlv;
1410 
1411         while (len)
1412         {
1413           if (!TTEST2(*(tptr), ISIS_SUBTLV_SPB_BVID_MIN_LEN))
1414             goto trunctlv;
1415 
1416           printf("\n\t           ECT: %08x",
1417                       EXTRACT_32BITS(tptr));
1418 
1419           tptr = tptr+4;
1420 
1421           printf(" BVID: %d, U:%01x M:%01x ",
1422                      (EXTRACT_16BITS (tptr) >> 4) ,
1423                      (EXTRACT_16BITS (tptr) >> 3) & 0x01,
1424                      (EXTRACT_16BITS (tptr) >> 2) & 0x01);
1425 
1426           tptr = tptr + 2;
1427           len = len - ISIS_SUBTLV_SPB_BVID_MIN_LEN;
1428         }
1429 
1430         break;
1431       }
1432 
1433       default:
1434           break;
1435     }
1436   }
1437 
1438   return 0;
1439 
1440   trunctlv:
1441     printf("\n\t\t packet exceeded snapshot");
1442     return(1);
1443 }
1444 
1445 static int
1446 isis_print_mt_capability_subtlv (const u_int8_t *tptr, int len)
1447 {
1448   int stlv_type, stlv_len, tmp;
1449 
1450   while (len > 0)
1451   {
1452     stlv_type = *(tptr++);
1453     stlv_len  = *(tptr++);
1454 
1455     /* first lets see if we know the subTLVs name*/
1456     printf("\n\t      %s subTLV #%u, length: %u",
1457                tok2str(isis_mt_capability_subtlv_values, "unknown", stlv_type),
1458                stlv_type,
1459                stlv_len);
1460 
1461     len = len - 2;
1462 
1463     switch (stlv_type)
1464     {
1465       case ISIS_SUBTLV_SPB_INSTANCE:
1466 
1467           if (!TTEST2(*(tptr), ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN))
1468             goto trunctlv;
1469 
1470           printf("\n\t        CIST Root-ID: %08x", EXTRACT_32BITS(tptr));
1471           tptr = tptr+4;
1472           printf(" %08x", EXTRACT_32BITS(tptr));
1473           tptr = tptr+4;
1474           printf(", Path Cost: %08x", EXTRACT_32BITS(tptr));
1475           tptr = tptr+4;
1476           printf(", Prio: %d", EXTRACT_16BITS(tptr));
1477           tptr = tptr + 2;
1478           printf("\n\t        RES: %d",
1479                     EXTRACT_16BITS(tptr) >> 5);
1480           printf(", V: %d",
1481                     (EXTRACT_16BITS(tptr) >> 4) & 0x0001);
1482           printf(", SPSource-ID: %d",
1483                     (EXTRACT_32BITS(tptr) & 0x000fffff));
1484           tptr = tptr+4;
1485           printf(", No of Trees: %x", *(tptr));
1486 
1487           tmp = *(tptr++);
1488 
1489           len = len - ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN;
1490 
1491           while (tmp)
1492           {
1493             if (!TTEST2(*(tptr), ISIS_SUBTLV_SPB_INSTANCE_VLAN_TUPLE_LEN))
1494               goto trunctlv;
1495 
1496             printf ("\n\t         U:%d, M:%d, A:%d, RES:%d",
1497                       *(tptr) >> 7, (*(tptr) >> 6) & 0x01,
1498                       (*(tptr) >> 5) & 0x01, (*(tptr) & 0x1f));
1499 
1500             tptr++;
1501 
1502             printf (", ECT: %08x", EXTRACT_32BITS(tptr));
1503 
1504             tptr = tptr + 4;
1505 
1506             printf (", BVID: %d, SPVID: %d",
1507                       (EXTRACT_24BITS(tptr) >> 12) & 0x000fff,
1508                       EXTRACT_24BITS(tptr) & 0x000fff);
1509 
1510             tptr = tptr + 3;
1511             len = len - ISIS_SUBTLV_SPB_INSTANCE_VLAN_TUPLE_LEN;
1512             tmp--;
1513           }
1514 
1515           break;
1516 
1517       case ISIS_SUBTLV_SPBM_SI:
1518 
1519           if (!TTEST2(*(tptr), 6))
1520             goto trunctlv;
1521 
1522           printf("\n\t        BMAC: %08x", EXTRACT_32BITS(tptr));
1523           tptr = tptr+4;
1524           printf("%04x", EXTRACT_16BITS(tptr));
1525           tptr = tptr+2;
1526 
1527           printf (", RES: %d, VID: %d", EXTRACT_16BITS(tptr) >> 12,
1528                     (EXTRACT_16BITS(tptr)) & 0x0fff);
1529 
1530           tptr = tptr+2;
1531           len = len - 8;
1532           stlv_len = stlv_len - 8;
1533 
1534           while (stlv_len)
1535           {
1536             printf("\n\t        T: %d, R: %d, RES: %d, ISID: %d",
1537                     (EXTRACT_32BITS(tptr) >> 31),
1538                     (EXTRACT_32BITS(tptr) >> 30) & 0x01,
1539                     (EXTRACT_32BITS(tptr) >> 24) & 0x03f,
1540                     (EXTRACT_32BITS(tptr)) & 0x0ffffff);
1541 
1542             tptr = tptr + 4;
1543             len = len - 4;
1544             stlv_len = stlv_len - 4;
1545           }
1546 
1547         break;
1548 
1549       default:
1550         break;
1551     }
1552   }
1553   return 0;
1554 
1555   trunctlv:
1556     printf("\n\t\t packet exceeded snapshot");
1557     return(1);
1558 }
1559 
1560 
1561 /* shared routine for printing system, node and lsp-ids */
1562 static char *
1563 isis_print_id(const u_int8_t *cp, int id_len)
1564 {
1565     int i;
1566     static char id[sizeof("xxxx.xxxx.xxxx.yy-zz")];
1567     char *pos = id;
1568 
1569     for (i = 1; i <= SYSTEM_ID_LEN; i++) {
1570         snprintf(pos, sizeof(id) - (pos - id), "%02x", *cp++);
1571 	pos += strlen(pos);
1572 	if (i == 2 || i == 4)
1573 	    *pos++ = '.';
1574 	}
1575     if (id_len >= NODE_ID_LEN) {
1576         snprintf(pos, sizeof(id) - (pos - id), ".%02x", *cp++);
1577 	pos += strlen(pos);
1578     }
1579     if (id_len == LSP_ID_LEN)
1580         snprintf(pos, sizeof(id) - (pos - id), "-%02x", *cp);
1581     return (id);
1582 }
1583 
1584 /* print the 4-byte metric block which is common found in the old-style TLVs */
1585 static int
1586 isis_print_metric_block (const struct isis_metric_block *isis_metric_block)
1587 {
1588     printf(", Default Metric: %d, %s",
1589            ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_default),
1590            ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_default) ? "External" : "Internal");
1591     if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_delay))
1592         printf("\n\t\t  Delay Metric: %d, %s",
1593                ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_delay),
1594                ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_delay) ? "External" : "Internal");
1595     if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_expense))
1596         printf("\n\t\t  Expense Metric: %d, %s",
1597                ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_expense),
1598                ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_expense) ? "External" : "Internal");
1599     if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_error))
1600         printf("\n\t\t  Error Metric: %d, %s",
1601                ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_error),
1602                ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_error) ? "External" : "Internal");
1603 
1604     return(1); /* everything is ok */
1605 }
1606 
1607 static int
1608 isis_print_tlv_ip_reach (const u_int8_t *cp, const char *ident, int length)
1609 {
1610 	int prefix_len;
1611 	const struct isis_tlv_ip_reach *tlv_ip_reach;
1612 
1613 	tlv_ip_reach = (const struct isis_tlv_ip_reach *)cp;
1614 
1615 	while (length > 0) {
1616 		if ((size_t)length < sizeof(*tlv_ip_reach)) {
1617 			printf("short IPv4 Reachability (%d vs %lu)",
1618                                length,
1619                                (unsigned long)sizeof(*tlv_ip_reach));
1620 			return (0);
1621 		}
1622 
1623 		if (!TTEST(*tlv_ip_reach))
1624 		    return (0);
1625 
1626 		prefix_len = mask2plen(EXTRACT_32BITS(tlv_ip_reach->mask));
1627 
1628 		if (prefix_len == -1)
1629 			printf("%sIPv4 prefix: %s mask %s",
1630                                ident,
1631 			       ipaddr_string((tlv_ip_reach->prefix)),
1632 			       ipaddr_string((tlv_ip_reach->mask)));
1633 		else
1634 			printf("%sIPv4 prefix: %15s/%u",
1635                                ident,
1636 			       ipaddr_string((tlv_ip_reach->prefix)),
1637 			       prefix_len);
1638 
1639 		printf(", Distribution: %s, Metric: %u, %s",
1640                        ISIS_LSP_TLV_METRIC_UPDOWN(tlv_ip_reach->isis_metric_block.metric_default) ? "down" : "up",
1641                        ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_default),
1642                        ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_default) ? "External" : "Internal");
1643 
1644 		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_delay))
1645                     printf("%s  Delay Metric: %u, %s",
1646                            ident,
1647                            ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_delay),
1648                            ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_delay) ? "External" : "Internal");
1649 
1650 		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_expense))
1651                     printf("%s  Expense Metric: %u, %s",
1652                            ident,
1653                            ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_expense),
1654                            ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_expense) ? "External" : "Internal");
1655 
1656 		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_error))
1657                     printf("%s  Error Metric: %u, %s",
1658                            ident,
1659                            ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_error),
1660                            ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_error) ? "External" : "Internal");
1661 
1662 		length -= sizeof(struct isis_tlv_ip_reach);
1663 		tlv_ip_reach++;
1664 	}
1665 	return (1);
1666 }
1667 
1668 /*
1669  * this is the common IP-REACH subTLV decoder it is called
1670  * from various EXTD-IP REACH TLVs (135,235,236,237)
1671  */
1672 
1673 static int
1674 isis_print_ip_reach_subtlv (const u_int8_t *tptr,int subt,int subl,const char *ident) {
1675 
1676         /* first lets see if we know the subTLVs name*/
1677 	printf("%s%s subTLV #%u, length: %u",
1678 	       ident,
1679                tok2str(isis_ext_ip_reach_subtlv_values,
1680                        "unknown",
1681                        subt),
1682                subt,
1683                subl);
1684 
1685 	if (!TTEST2(*tptr,subl))
1686 	    goto trunctlv;
1687 
1688     switch(subt) {
1689     case ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR: /* fall through */
1690     case ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32:
1691         while (subl >= 4) {
1692 	    printf(", 0x%08x (=%u)",
1693 		   EXTRACT_32BITS(tptr),
1694 		   EXTRACT_32BITS(tptr));
1695 	    tptr+=4;
1696 	    subl-=4;
1697 	}
1698 	break;
1699     case ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64:
1700         while (subl >= 8) {
1701 	    printf(", 0x%08x%08x",
1702 		   EXTRACT_32BITS(tptr),
1703 		   EXTRACT_32BITS(tptr+4));
1704 	    tptr+=8;
1705 	    subl-=8;
1706 	}
1707 	break;
1708     default:
1709 	if(!print_unknown_data(tptr,"\n\t\t    ",
1710 			       subl))
1711 	  return(0);
1712 	break;
1713     }
1714     return(1);
1715 
1716 trunctlv:
1717     printf("%spacket exceeded snapshot",ident);
1718     return(0);
1719 }
1720 
1721 /*
1722  * this is the common IS-REACH subTLV decoder it is called
1723  * from isis_print_ext_is_reach()
1724  */
1725 
1726 static int
1727 isis_print_is_reach_subtlv (const u_int8_t *tptr,u_int subt,u_int subl,const char *ident) {
1728 
1729         u_int te_class,priority_level,gmpls_switch_cap;
1730         union { /* int to float conversion buffer for several subTLVs */
1731             float f;
1732             u_int32_t i;
1733         } bw;
1734 
1735         /* first lets see if we know the subTLVs name*/
1736 	printf("%s%s subTLV #%u, length: %u",
1737 	       ident,
1738                tok2str(isis_ext_is_reach_subtlv_values,
1739                        "unknown",
1740                        subt),
1741                subt,
1742                subl);
1743 
1744 	if (!TTEST2(*tptr,subl))
1745 	    goto trunctlv;
1746 
1747         switch(subt) {
1748         case ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP:
1749         case ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID:
1750         case ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID:
1751 	    if (subl >= 4) {
1752 	      printf(", 0x%08x", EXTRACT_32BITS(tptr));
1753 	      if (subl == 8) /* rfc4205 */
1754 	        printf(", 0x%08x", EXTRACT_32BITS(tptr+4));
1755 	    }
1756 	    break;
1757         case ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR:
1758         case ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR:
1759             if (subl >= sizeof(struct in_addr))
1760               printf(", %s", ipaddr_string(tptr));
1761             break;
1762         case ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW :
1763 	case ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW:
1764             if (subl >= 4) {
1765               bw.i = EXTRACT_32BITS(tptr);
1766               printf(", %.3f Mbps", bw.f*8/1000000 );
1767             }
1768             break;
1769         case ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW :
1770             if (subl >= 32) {
1771               for (te_class = 0; te_class < 8; te_class++) {
1772                 bw.i = EXTRACT_32BITS(tptr);
1773                 printf("%s  TE-Class %u: %.3f Mbps",
1774                        ident,
1775                        te_class,
1776                        bw.f*8/1000000 );
1777 		tptr+=4;
1778 	      }
1779             }
1780             break;
1781         case ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS: /* fall through */
1782         case ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS_OLD:
1783             printf("%sBandwidth Constraints Model ID: %s (%u)",
1784                    ident,
1785                    tok2str(diffserv_te_bc_values, "unknown", *tptr),
1786                    *tptr);
1787             tptr++;
1788             /* decode BCs until the subTLV ends */
1789             for (te_class = 0; te_class < (subl-1)/4; te_class++) {
1790                 bw.i = EXTRACT_32BITS(tptr);
1791                 printf("%s  Bandwidth constraint CT%u: %.3f Mbps",
1792                        ident,
1793                        te_class,
1794                        bw.f*8/1000000 );
1795 		tptr+=4;
1796             }
1797             break;
1798         case ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC:
1799             if (subl >= 3)
1800               printf(", %u", EXTRACT_24BITS(tptr));
1801             break;
1802         case ISIS_SUBTLV_EXT_IS_REACH_LINK_ATTRIBUTE:
1803             if (subl == 2) {
1804                printf(", [ %s ] (0x%04x)",
1805                       bittok2str(isis_subtlv_link_attribute_values,
1806                                  "Unknown",
1807                                  EXTRACT_16BITS(tptr)),
1808                       EXTRACT_16BITS(tptr));
1809             }
1810             break;
1811         case ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE:
1812             if (subl >= 2) {
1813               printf(", %s, Priority %u",
1814 		   bittok2str(gmpls_link_prot_values, "none", *tptr),
1815                    *(tptr+1));
1816             }
1817             break;
1818         case ISIS_SUBTLV_SPB_METRIC:
1819             if (subl >= 6) {
1820               printf (", LM: %u", EXTRACT_24BITS(tptr));
1821               tptr=tptr+3;
1822               printf (", P: %u", *(tptr));
1823               printf (", P-ID: %u", EXTRACT_16BITS(++tptr));
1824             }
1825             break;
1826         case ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR:
1827             if (subl >= 36) {
1828               gmpls_switch_cap = *tptr;
1829               printf("%s  Interface Switching Capability:%s",
1830                    ident,
1831                    tok2str(gmpls_switch_cap_values, "Unknown", gmpls_switch_cap));
1832               printf(", LSP Encoding: %s",
1833                    tok2str(gmpls_encoding_values, "Unknown", *(tptr+1)));
1834 	      tptr+=4;
1835               printf("%s  Max LSP Bandwidth:",ident);
1836               for (priority_level = 0; priority_level < 8; priority_level++) {
1837                 bw.i = EXTRACT_32BITS(tptr);
1838                 printf("%s    priority level %d: %.3f Mbps",
1839                        ident,
1840                        priority_level,
1841                        bw.f*8/1000000 );
1842 		tptr+=4;
1843               }
1844               subl-=36;
1845               switch (gmpls_switch_cap) {
1846               case GMPLS_PSC1:
1847               case GMPLS_PSC2:
1848               case GMPLS_PSC3:
1849               case GMPLS_PSC4:
1850                 bw.i = EXTRACT_32BITS(tptr);
1851                 printf("%s  Min LSP Bandwidth: %.3f Mbps", ident, bw.f*8/1000000);
1852                 printf("%s  Interface MTU: %u", ident, EXTRACT_16BITS(tptr+4));
1853                 break;
1854               case GMPLS_TSC:
1855                 bw.i = EXTRACT_32BITS(tptr);
1856                 printf("%s  Min LSP Bandwidth: %.3f Mbps", ident, bw.f*8/1000000);
1857                 printf("%s  Indication %s", ident,
1858                        tok2str(gmpls_switch_cap_tsc_indication_values, "Unknown (%u)", *(tptr+4)));
1859                 break;
1860               default:
1861                 /* there is some optional stuff left to decode but this is as of yet
1862                    not specified so just lets hexdump what is left */
1863                 if(subl>0){
1864                   if(!print_unknown_data(tptr,"\n\t\t    ",
1865                                          subl))
1866                     return(0);
1867                 }
1868               }
1869             }
1870             break;
1871         default:
1872             if(!print_unknown_data(tptr,"\n\t\t    ",
1873 				   subl))
1874                 return(0);
1875             break;
1876         }
1877         return(1);
1878 
1879 trunctlv:
1880     printf("%spacket exceeded snapshot",ident);
1881     return(0);
1882 }
1883 
1884 
1885 /*
1886  * this is the common IS-REACH decoder it is called
1887  * from various EXTD-IS REACH style TLVs (22,24,222)
1888  */
1889 
1890 static int
1891 isis_print_ext_is_reach (const u_int8_t *tptr,const char *ident, int tlv_type) {
1892 
1893     char ident_buffer[20];
1894     int subtlv_type,subtlv_len,subtlv_sum_len;
1895     int proc_bytes = 0; /* how many bytes did we process ? */
1896 
1897     if (!TTEST2(*tptr, NODE_ID_LEN))
1898         return(0);
1899 
1900     printf("%sIS Neighbor: %s", ident, isis_print_id(tptr, NODE_ID_LEN));
1901     tptr+=(NODE_ID_LEN);
1902 
1903     if (tlv_type != ISIS_TLV_IS_ALIAS_ID) { /* the Alias TLV Metric field is implicit 0 */
1904         if (!TTEST2(*tptr, 3))    /* and is therefore skipped */
1905 	    return(0);
1906 	printf(", Metric: %d",EXTRACT_24BITS(tptr));
1907 	tptr+=3;
1908     }
1909 
1910     if (!TTEST2(*tptr, 1))
1911         return(0);
1912     subtlv_sum_len=*(tptr++); /* read out subTLV length */
1913     proc_bytes=NODE_ID_LEN+3+1;
1914     printf(", %ssub-TLVs present",subtlv_sum_len ? "" : "no ");
1915     if (subtlv_sum_len) {
1916         printf(" (%u)",subtlv_sum_len);
1917         while (subtlv_sum_len>0) {
1918             if (!TTEST2(*tptr,2))
1919                 return(0);
1920             subtlv_type=*(tptr++);
1921             subtlv_len=*(tptr++);
1922             /* prepend the ident string */
1923             snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
1924             if(!isis_print_is_reach_subtlv(tptr,subtlv_type,subtlv_len,ident_buffer))
1925                 return(0);
1926             tptr+=subtlv_len;
1927             subtlv_sum_len-=(subtlv_len+2);
1928             proc_bytes+=(subtlv_len+2);
1929         }
1930     }
1931     return(proc_bytes);
1932 }
1933 
1934 /*
1935  * this is the common Multi Topology ID decoder
1936  * it is called from various MT-TLVs (222,229,235,237)
1937  */
1938 
1939 static int
1940 isis_print_mtid (const u_int8_t *tptr,const char *ident) {
1941 
1942     if (!TTEST2(*tptr, 2))
1943         return(0);
1944 
1945     printf("%s%s",
1946            ident,
1947            tok2str(isis_mt_values,
1948                    "Reserved for IETF Consensus",
1949                    ISIS_MASK_MTID(EXTRACT_16BITS(tptr))));
1950 
1951     printf(" Topology (0x%03x), Flags: [%s]",
1952            ISIS_MASK_MTID(EXTRACT_16BITS(tptr)),
1953            bittok2str(isis_mt_flag_values, "none",ISIS_MASK_MTFLAGS(EXTRACT_16BITS(tptr))));
1954 
1955     return(2);
1956 }
1957 
1958 /*
1959  * this is the common extended IP reach decoder
1960  * it is called from TLVs (135,235,236,237)
1961  * we process the TLV and optional subTLVs and return
1962  * the amount of processed bytes
1963  */
1964 
1965 static int
1966 isis_print_extd_ip_reach (const u_int8_t *tptr, const char *ident, u_int16_t afi) {
1967 
1968     char ident_buffer[20];
1969 #ifdef INET6
1970     u_int8_t prefix[sizeof(struct in6_addr)]; /* shared copy buffer for IPv4 and IPv6 prefixes */
1971 #else
1972     u_int8_t prefix[sizeof(struct in_addr)]; /* shared copy buffer for IPv4 prefixes */
1973 #endif
1974     u_int metric, status_byte, bit_length, byte_length, sublen, processed, subtlvtype, subtlvlen;
1975 
1976     if (!TTEST2(*tptr, 4))
1977         return (0);
1978     metric = EXTRACT_32BITS(tptr);
1979     processed=4;
1980     tptr+=4;
1981 
1982     if (afi == AF_INET) {
1983         if (!TTEST2(*tptr, 1)) /* fetch status byte */
1984             return (0);
1985         status_byte=*(tptr++);
1986         bit_length = status_byte&0x3f;
1987         if (bit_length > 32) {
1988             printf("%sIPv4 prefix: bad bit length %u",
1989                    ident,
1990                    bit_length);
1991             return (0);
1992         }
1993         processed++;
1994 #ifdef INET6
1995     } else if (afi == AF_INET6) {
1996         if (!TTEST2(*tptr, 1)) /* fetch status & prefix_len byte */
1997             return (0);
1998         status_byte=*(tptr++);
1999         bit_length=*(tptr++);
2000         if (bit_length > 128) {
2001             printf("%sIPv6 prefix: bad bit length %u",
2002                    ident,
2003                    bit_length);
2004             return (0);
2005         }
2006         processed+=2;
2007 #endif
2008     } else
2009         return (0); /* somebody is fooling us */
2010 
2011     byte_length = (bit_length + 7) / 8; /* prefix has variable length encoding */
2012 
2013     if (!TTEST2(*tptr, byte_length))
2014         return (0);
2015     memset(prefix, 0, sizeof prefix);   /* clear the copy buffer */
2016     memcpy(prefix,tptr,byte_length);    /* copy as much as is stored in the TLV */
2017     tptr+=byte_length;
2018     processed+=byte_length;
2019 
2020     if (afi == AF_INET)
2021         printf("%sIPv4 prefix: %15s/%u",
2022                ident,
2023                ipaddr_string(prefix),
2024                bit_length);
2025 #ifdef INET6
2026     if (afi == AF_INET6)
2027         printf("%sIPv6 prefix: %s/%u",
2028                ident,
2029                ip6addr_string(prefix),
2030                bit_length);
2031 #endif
2032 
2033     printf(", Distribution: %s, Metric: %u",
2034            ISIS_MASK_TLV_EXTD_IP_UPDOWN(status_byte) ? "down" : "up",
2035            metric);
2036 
2037     if (afi == AF_INET && ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte))
2038         printf(", sub-TLVs present");
2039 #ifdef INET6
2040     if (afi == AF_INET6)
2041         printf(", %s%s",
2042                ISIS_MASK_TLV_EXTD_IP6_IE(status_byte) ? "External" : "Internal",
2043                ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte) ? ", sub-TLVs present" : "");
2044 #endif
2045 
2046     if ((afi == AF_INET  && ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte))
2047 #ifdef INET6
2048      || (afi == AF_INET6 && ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte))
2049 #endif
2050 	) {
2051         /* assume that one prefix can hold more
2052            than one subTLV - therefore the first byte must reflect
2053            the aggregate bytecount of the subTLVs for this prefix
2054         */
2055         if (!TTEST2(*tptr, 1))
2056             return (0);
2057         sublen=*(tptr++);
2058         processed+=sublen+1;
2059         printf(" (%u)",sublen);   /* print out subTLV length */
2060 
2061         while (sublen>0) {
2062             if (!TTEST2(*tptr,2))
2063                 return (0);
2064             subtlvtype=*(tptr++);
2065             subtlvlen=*(tptr++);
2066             /* prepend the ident string */
2067             snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
2068             if(!isis_print_ip_reach_subtlv(tptr,subtlvtype,subtlvlen,ident_buffer))
2069                 return(0);
2070             tptr+=subtlvlen;
2071             sublen-=(subtlvlen+2);
2072         }
2073     }
2074     return (processed);
2075 }
2076 
2077 /*
2078  * isis_print
2079  * Decode IS-IS packets.  Return 0 on error.
2080  */
2081 
2082 static int isis_print (const u_int8_t *p, u_int length)
2083 {
2084     const struct isis_common_header *isis_header;
2085 
2086     const struct isis_iih_lan_header *header_iih_lan;
2087     const struct isis_iih_ptp_header *header_iih_ptp;
2088     struct isis_lsp_header *header_lsp;
2089     const struct isis_csnp_header *header_csnp;
2090     const struct isis_psnp_header *header_psnp;
2091 
2092     const struct isis_tlv_lsp *tlv_lsp;
2093     const struct isis_tlv_ptp_adj *tlv_ptp_adj;
2094     const struct isis_tlv_is_reach *tlv_is_reach;
2095     const struct isis_tlv_es_reach *tlv_es_reach;
2096 
2097     u_int8_t pdu_type, max_area, id_length, tlv_type, tlv_len, tmp, alen, lan_alen, prefix_len;
2098     u_int8_t ext_is_len, ext_ip_len, mt_len;
2099     const u_int8_t *optr, *pptr, *tptr;
2100     u_short packet_len,pdu_len, key_id;
2101     u_int i,vendor_id;
2102     int sigcheck;
2103 
2104     packet_len=length;
2105     optr = p; /* initialize the _o_riginal pointer to the packet start -
2106                  need it for parsing the checksum TLV and authentication
2107                  TLV verification */
2108     isis_header = (const struct isis_common_header *)p;
2109     TCHECK(*isis_header);
2110     pptr = p+(ISIS_COMMON_HEADER_SIZE);
2111     header_iih_lan = (const struct isis_iih_lan_header *)pptr;
2112     header_iih_ptp = (const struct isis_iih_ptp_header *)pptr;
2113     header_lsp = (struct isis_lsp_header *)pptr;
2114     header_csnp = (const struct isis_csnp_header *)pptr;
2115     header_psnp = (const struct isis_psnp_header *)pptr;
2116 
2117     if (!eflag)
2118         printf("IS-IS");
2119 
2120     /*
2121      * Sanity checking of the header.
2122      */
2123 
2124     if (isis_header->version != ISIS_VERSION) {
2125 	printf("version %d packet not supported", isis_header->version);
2126 	return (0);
2127     }
2128 
2129     if ((isis_header->id_length != SYSTEM_ID_LEN) && (isis_header->id_length != 0)) {
2130 	printf("system ID length of %d is not supported",
2131 	       isis_header->id_length);
2132 	return (0);
2133     }
2134 
2135     if (isis_header->pdu_version != ISIS_VERSION) {
2136 	printf("version %d packet not supported", isis_header->pdu_version);
2137 	return (0);
2138     }
2139 
2140     max_area = isis_header->max_area;
2141     switch(max_area) {
2142     case 0:
2143 	max_area = 3;	 /* silly shit */
2144 	break;
2145     case 255:
2146 	printf("bad packet -- 255 areas");
2147 	return (0);
2148     default:
2149 	break;
2150     }
2151 
2152     id_length = isis_header->id_length;
2153     switch(id_length) {
2154     case 0:
2155         id_length = 6;	 /* silly shit again */
2156 	break;
2157     case 1:              /* 1-8 are valid sys-ID lenghts */
2158     case 2:
2159     case 3:
2160     case 4:
2161     case 5:
2162     case 6:
2163     case 7:
2164     case 8:
2165         break;
2166     case 255:
2167         id_length = 0;   /* entirely useless */
2168 	break;
2169     default:
2170         break;
2171     }
2172 
2173     /* toss any non 6-byte sys-ID len PDUs */
2174     if (id_length != 6 ) {
2175 	printf("bad packet -- illegal sys-ID length (%u)", id_length);
2176 	return (0);
2177     }
2178 
2179     pdu_type=isis_header->pdu_type;
2180 
2181     /* in non-verbose mode print the basic PDU Type plus PDU specific brief information*/
2182     if (vflag < 1) {
2183         printf("%s%s",
2184                eflag ? "" : ", ",
2185                tok2str(isis_pdu_values,"unknown PDU-Type %u",pdu_type));
2186 
2187 	switch (pdu_type) {
2188 
2189 	case ISIS_PDU_L1_LAN_IIH:
2190 	case ISIS_PDU_L2_LAN_IIH:
2191 	    printf(", src-id %s",
2192                    isis_print_id(header_iih_lan->source_id,SYSTEM_ID_LEN));
2193 	    printf(", lan-id %s, prio %u",
2194                    isis_print_id(header_iih_lan->lan_id,NODE_ID_LEN),
2195                    header_iih_lan->priority);
2196 	    break;
2197 	case ISIS_PDU_PTP_IIH:
2198 	    printf(", src-id %s", isis_print_id(header_iih_ptp->source_id,SYSTEM_ID_LEN));
2199 	    break;
2200 	case ISIS_PDU_L1_LSP:
2201 	case ISIS_PDU_L2_LSP:
2202 	    printf(", lsp-id %s, seq 0x%08x, lifetime %5us",
2203 		   isis_print_id(header_lsp->lsp_id, LSP_ID_LEN),
2204 		   EXTRACT_32BITS(header_lsp->sequence_number),
2205 		   EXTRACT_16BITS(header_lsp->remaining_lifetime));
2206 	    break;
2207 	case ISIS_PDU_L1_CSNP:
2208 	case ISIS_PDU_L2_CSNP:
2209 	    printf(", src-id %s", isis_print_id(header_csnp->source_id,NODE_ID_LEN));
2210 	    break;
2211 	case ISIS_PDU_L1_PSNP:
2212 	case ISIS_PDU_L2_PSNP:
2213 	    printf(", src-id %s", isis_print_id(header_psnp->source_id,NODE_ID_LEN));
2214 	    break;
2215 
2216 	}
2217 	printf(", length %u", length);
2218 
2219         return(1);
2220     }
2221 
2222     /* ok they seem to want to know everything - lets fully decode it */
2223     printf("%slength %u", eflag ? "" : ", ",length);
2224 
2225     printf("\n\t%s, hlen: %u, v: %u, pdu-v: %u, sys-id-len: %u (%u), max-area: %u (%u)",
2226            tok2str(isis_pdu_values,
2227                    "unknown, type %u",
2228                    pdu_type),
2229            isis_header->fixed_len,
2230            isis_header->version,
2231            isis_header->pdu_version,
2232 	   id_length,
2233 	   isis_header->id_length,
2234            max_area,
2235            isis_header->max_area);
2236 
2237     if (vflag > 1) {
2238         if(!print_unknown_data(optr,"\n\t",8)) /* provide the _o_riginal pointer */
2239             return(0);                         /* for optionally debugging the common header */
2240     }
2241 
2242     switch (pdu_type) {
2243 
2244     case ISIS_PDU_L1_LAN_IIH:
2245     case ISIS_PDU_L2_LAN_IIH:
2246 	if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE)) {
2247 	    printf(", bogus fixed header length %u should be %lu",
2248 		   isis_header->fixed_len, (unsigned long)ISIS_IIH_LAN_HEADER_SIZE);
2249 	    return (0);
2250 	}
2251 
2252 	pdu_len=EXTRACT_16BITS(header_iih_lan->pdu_len);
2253 	if (packet_len>pdu_len) {
2254             packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
2255             length=pdu_len;
2256 	}
2257 
2258 	TCHECK(*header_iih_lan);
2259 	printf("\n\t  source-id: %s,  holding time: %us, Flags: [%s]",
2260                isis_print_id(header_iih_lan->source_id,SYSTEM_ID_LEN),
2261                EXTRACT_16BITS(header_iih_lan->holding_time),
2262                tok2str(isis_iih_circuit_type_values,
2263                        "unknown circuit type 0x%02x",
2264                        header_iih_lan->circuit_type));
2265 
2266 	printf("\n\t  lan-id:    %s, Priority: %u, PDU length: %u",
2267                isis_print_id(header_iih_lan->lan_id, NODE_ID_LEN),
2268                (header_iih_lan->priority) & ISIS_LAN_PRIORITY_MASK,
2269                pdu_len);
2270 
2271         if (vflag > 1) {
2272             if(!print_unknown_data(pptr,"\n\t  ",ISIS_IIH_LAN_HEADER_SIZE))
2273                 return(0);
2274         }
2275 
2276 	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
2277 	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
2278 	break;
2279 
2280     case ISIS_PDU_PTP_IIH:
2281 	if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE)) {
2282 	    printf(", bogus fixed header length %u should be %lu",
2283 		   isis_header->fixed_len, (unsigned long)ISIS_IIH_PTP_HEADER_SIZE);
2284 	    return (0);
2285 	}
2286 
2287 	pdu_len=EXTRACT_16BITS(header_iih_ptp->pdu_len);
2288 	if (packet_len>pdu_len) {
2289             packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
2290             length=pdu_len;
2291 	}
2292 
2293 	TCHECK(*header_iih_ptp);
2294 	printf("\n\t  source-id: %s, holding time: %us, Flags: [%s]",
2295                isis_print_id(header_iih_ptp->source_id,SYSTEM_ID_LEN),
2296                EXTRACT_16BITS(header_iih_ptp->holding_time),
2297                tok2str(isis_iih_circuit_type_values,
2298                        "unknown circuit type 0x%02x",
2299                        header_iih_ptp->circuit_type));
2300 
2301 	printf("\n\t  circuit-id: 0x%02x, PDU length: %u",
2302                header_iih_ptp->circuit_id,
2303                pdu_len);
2304 
2305         if (vflag > 1) {
2306             if(!print_unknown_data(pptr,"\n\t  ",ISIS_IIH_PTP_HEADER_SIZE))
2307                 return(0);
2308         }
2309 
2310 	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
2311 	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
2312 	break;
2313 
2314     case ISIS_PDU_L1_LSP:
2315     case ISIS_PDU_L2_LSP:
2316 	if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE)) {
2317 	    printf(", bogus fixed header length %u should be %lu",
2318 		   isis_header->fixed_len, (unsigned long)ISIS_LSP_HEADER_SIZE);
2319 	    return (0);
2320 	}
2321 
2322 	pdu_len=EXTRACT_16BITS(header_lsp->pdu_len);
2323 	if (packet_len>pdu_len) {
2324             packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
2325             length=pdu_len;
2326 	}
2327 
2328 	TCHECK(*header_lsp);
2329 	printf("\n\t  lsp-id: %s, seq: 0x%08x, lifetime: %5us\n\t  chksum: 0x%04x",
2330                isis_print_id(header_lsp->lsp_id, LSP_ID_LEN),
2331                EXTRACT_32BITS(header_lsp->sequence_number),
2332                EXTRACT_16BITS(header_lsp->remaining_lifetime),
2333                EXTRACT_16BITS(header_lsp->checksum));
2334 
2335 
2336         osi_print_cksum((u_int8_t *)header_lsp->lsp_id,
2337                         EXTRACT_16BITS(header_lsp->checksum), 12, length-12);
2338 
2339         /*
2340          * Clear checksum and lifetime prior to signature verification.
2341          */
2342         header_lsp->checksum[0] = 0;
2343         header_lsp->checksum[1] = 0;
2344         header_lsp->remaining_lifetime[0] = 0;
2345         header_lsp->remaining_lifetime[1] = 0;
2346 
2347 
2348 	printf(", PDU length: %u, Flags: [ %s",
2349                pdu_len,
2350                ISIS_MASK_LSP_OL_BIT(header_lsp->typeblock) ? "Overload bit set, " : "");
2351 
2352 	if (ISIS_MASK_LSP_ATT_BITS(header_lsp->typeblock)) {
2353 	    printf("%s", ISIS_MASK_LSP_ATT_DEFAULT_BIT(header_lsp->typeblock) ? "default " : "");
2354 	    printf("%s", ISIS_MASK_LSP_ATT_DELAY_BIT(header_lsp->typeblock) ? "delay " : "");
2355 	    printf("%s", ISIS_MASK_LSP_ATT_EXPENSE_BIT(header_lsp->typeblock) ? "expense " : "");
2356 	    printf("%s", ISIS_MASK_LSP_ATT_ERROR_BIT(header_lsp->typeblock) ? "error " : "");
2357 	    printf("ATT bit set, ");
2358 	}
2359 	printf("%s", ISIS_MASK_LSP_PARTITION_BIT(header_lsp->typeblock) ? "P bit set, " : "");
2360 	printf("%s ]", tok2str(isis_lsp_istype_values,"Unknown(0x%x)",ISIS_MASK_LSP_ISTYPE_BITS(header_lsp->typeblock)));
2361 
2362         if (vflag > 1) {
2363             if(!print_unknown_data(pptr,"\n\t  ",ISIS_LSP_HEADER_SIZE))
2364                 return(0);
2365         }
2366 
2367 	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
2368 	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
2369 	break;
2370 
2371     case ISIS_PDU_L1_CSNP:
2372     case ISIS_PDU_L2_CSNP:
2373 	if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE)) {
2374 	    printf(", bogus fixed header length %u should be %lu",
2375 		   isis_header->fixed_len, (unsigned long)ISIS_CSNP_HEADER_SIZE);
2376 	    return (0);
2377 	}
2378 
2379 	pdu_len=EXTRACT_16BITS(header_csnp->pdu_len);
2380 	if (packet_len>pdu_len) {
2381             packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
2382             length=pdu_len;
2383 	}
2384 
2385 	TCHECK(*header_csnp);
2386 	printf("\n\t  source-id:    %s, PDU length: %u",
2387                isis_print_id(header_csnp->source_id, NODE_ID_LEN),
2388                pdu_len);
2389 	printf("\n\t  start lsp-id: %s",
2390                isis_print_id(header_csnp->start_lsp_id, LSP_ID_LEN));
2391 	printf("\n\t  end lsp-id:   %s",
2392                isis_print_id(header_csnp->end_lsp_id, LSP_ID_LEN));
2393 
2394         if (vflag > 1) {
2395             if(!print_unknown_data(pptr,"\n\t  ",ISIS_CSNP_HEADER_SIZE))
2396                 return(0);
2397         }
2398 
2399 	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
2400 	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
2401         break;
2402 
2403     case ISIS_PDU_L1_PSNP:
2404     case ISIS_PDU_L2_PSNP:
2405 	if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE)) {
2406 	    printf("- bogus fixed header length %u should be %lu",
2407 		   isis_header->fixed_len, (unsigned long)ISIS_PSNP_HEADER_SIZE);
2408 	    return (0);
2409 	}
2410 
2411 	pdu_len=EXTRACT_16BITS(header_psnp->pdu_len);
2412 	if (packet_len>pdu_len) {
2413             packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
2414             length=pdu_len;
2415 	}
2416 
2417 	TCHECK(*header_psnp);
2418 	printf("\n\t  source-id:    %s, PDU length: %u",
2419                isis_print_id(header_psnp->source_id, NODE_ID_LEN),
2420                pdu_len);
2421 
2422         if (vflag > 1) {
2423             if(!print_unknown_data(pptr,"\n\t  ",ISIS_PSNP_HEADER_SIZE))
2424                 return(0);
2425         }
2426 
2427 	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
2428 	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
2429 	break;
2430 
2431     default:
2432 	if(!print_unknown_data(pptr,"\n\t  ",length))
2433 	    return(0);
2434 	return (0);
2435     }
2436 
2437     /*
2438      * Now print the TLV's.
2439      */
2440 
2441     while (packet_len >= 2) {
2442         if (pptr == snapend) {
2443 	    return (1);
2444         }
2445 
2446 	if (!TTEST2(*pptr, 2)) {
2447 	    printf("\n\t\t packet exceeded snapshot (%ld) bytes",
2448                    (long)(pptr-snapend));
2449 	    return (1);
2450 	}
2451 	tlv_type = *pptr++;
2452 	tlv_len = *pptr++;
2453         tmp =tlv_len; /* copy temporary len & pointer to packet data */
2454         tptr = pptr;
2455 	packet_len -= 2;
2456 	if (tlv_len > packet_len) {
2457 	    break;
2458 	}
2459 
2460         /* first lets see if we know the TLVs name*/
2461 	printf("\n\t    %s TLV #%u, length: %u",
2462                tok2str(isis_tlv_values,
2463                        "unknown",
2464                        tlv_type),
2465                tlv_type,
2466                tlv_len);
2467 
2468         if (tlv_len == 0) /* something is malformed */
2469 	    continue;
2470 
2471         /* now check if we have a decoder otherwise do a hexdump at the end*/
2472 	switch (tlv_type) {
2473 	case ISIS_TLV_AREA_ADDR:
2474 	    if (!TTEST2(*tptr, 1))
2475 		goto trunctlv;
2476 	    alen = *tptr++;
2477 	    while (tmp && alen < tmp) {
2478 		printf("\n\t      Area address (length: %u): %s",
2479                        alen,
2480                        isonsap_string(tptr,alen));
2481 		tptr += alen;
2482 		tmp -= alen + 1;
2483 		if (tmp==0) /* if this is the last area address do not attemt a boundary check */
2484                     break;
2485 		if (!TTEST2(*tptr, 1))
2486 		    goto trunctlv;
2487 		alen = *tptr++;
2488 	    }
2489 	    break;
2490 	case ISIS_TLV_ISNEIGH:
2491 	    while (tmp >= ETHER_ADDR_LEN) {
2492                 if (!TTEST2(*tptr, ETHER_ADDR_LEN))
2493                     goto trunctlv;
2494                 printf("\n\t      SNPA: %s",isis_print_id(tptr,ETHER_ADDR_LEN));
2495                 tmp -= ETHER_ADDR_LEN;
2496                 tptr += ETHER_ADDR_LEN;
2497 	    }
2498 	    break;
2499 
2500         case ISIS_TLV_ISNEIGH_VARLEN:
2501             if (!TTEST2(*tptr, 1) || tmp < 3) /* min. TLV length */
2502 		goto trunctlv;
2503 	    lan_alen = *tptr++; /* LAN address length */
2504 	    if (lan_alen == 0) {
2505                 printf("\n\t      LAN address length 0 bytes (invalid)");
2506                 break;
2507             }
2508             tmp --;
2509             printf("\n\t      LAN address length %u bytes ",lan_alen);
2510 	    while (tmp >= lan_alen) {
2511                 if (!TTEST2(*tptr, lan_alen))
2512                     goto trunctlv;
2513                 printf("\n\t\tIS Neighbor: %s",isis_print_id(tptr,lan_alen));
2514                 tmp -= lan_alen;
2515                 tptr +=lan_alen;
2516             }
2517             break;
2518 
2519 	case ISIS_TLV_PADDING:
2520 	    break;
2521 
2522         case ISIS_TLV_MT_IS_REACH:
2523             mt_len = isis_print_mtid(tptr, "\n\t      ");
2524             if (mt_len == 0) /* did something go wrong ? */
2525                 goto trunctlv;
2526             tptr+=mt_len;
2527             tmp-=mt_len;
2528             while (tmp >= 2+NODE_ID_LEN+3+1) {
2529                 ext_is_len = isis_print_ext_is_reach(tptr,"\n\t      ",tlv_type);
2530                 if (ext_is_len == 0) /* did something go wrong ? */
2531                     goto trunctlv;
2532 
2533                 tmp-=ext_is_len;
2534                 tptr+=ext_is_len;
2535             }
2536             break;
2537 
2538         case ISIS_TLV_IS_ALIAS_ID:
2539 	    while (tmp >= NODE_ID_LEN+1) { /* is it worth attempting a decode ? */
2540 	        ext_is_len = isis_print_ext_is_reach(tptr,"\n\t      ",tlv_type);
2541 		if (ext_is_len == 0) /* did something go wrong ? */
2542 	            goto trunctlv;
2543 		tmp-=ext_is_len;
2544 		tptr+=ext_is_len;
2545 	    }
2546 	    break;
2547 
2548         case ISIS_TLV_EXT_IS_REACH:
2549             while (tmp >= NODE_ID_LEN+3+1) { /* is it worth attempting a decode ? */
2550                 ext_is_len = isis_print_ext_is_reach(tptr,"\n\t      ",tlv_type);
2551                 if (ext_is_len == 0) /* did something go wrong ? */
2552                     goto trunctlv;
2553                 tmp-=ext_is_len;
2554                 tptr+=ext_is_len;
2555             }
2556             break;
2557         case ISIS_TLV_IS_REACH:
2558 	    if (!TTEST2(*tptr,1))  /* check if there is one byte left to read out the virtual flag */
2559                 goto trunctlv;
2560             printf("\n\t      %s",
2561                    tok2str(isis_is_reach_virtual_values,
2562                            "bogus virtual flag 0x%02x",
2563                            *tptr++));
2564 	    tlv_is_reach = (const struct isis_tlv_is_reach *)tptr;
2565             while (tmp >= sizeof(struct isis_tlv_is_reach)) {
2566 		if (!TTEST(*tlv_is_reach))
2567 		    goto trunctlv;
2568 		printf("\n\t      IS Neighbor: %s",
2569 		       isis_print_id(tlv_is_reach->neighbor_nodeid, NODE_ID_LEN));
2570                 isis_print_metric_block(&tlv_is_reach->isis_metric_block);
2571 		tmp -= sizeof(struct isis_tlv_is_reach);
2572 		tlv_is_reach++;
2573 	    }
2574             break;
2575 
2576         case ISIS_TLV_ESNEIGH:
2577 	    tlv_es_reach = (const struct isis_tlv_es_reach *)tptr;
2578             while (tmp >= sizeof(struct isis_tlv_es_reach)) {
2579 		if (!TTEST(*tlv_es_reach))
2580 		    goto trunctlv;
2581 		printf("\n\t      ES Neighbor: %s",
2582                        isis_print_id(tlv_es_reach->neighbor_sysid,SYSTEM_ID_LEN));
2583                 isis_print_metric_block(&tlv_es_reach->isis_metric_block);
2584 		tmp -= sizeof(struct isis_tlv_es_reach);
2585 		tlv_es_reach++;
2586 	    }
2587             break;
2588 
2589             /* those two TLVs share the same format */
2590 	case ISIS_TLV_INT_IP_REACH:
2591 	case ISIS_TLV_EXT_IP_REACH:
2592 	    if (!isis_print_tlv_ip_reach(pptr, "\n\t      ", tlv_len))
2593 		return (1);
2594 	    break;
2595 
2596 	case ISIS_TLV_EXTD_IP_REACH:
2597 	    while (tmp>0) {
2598                 ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", AF_INET);
2599                 if (ext_ip_len == 0) /* did something go wrong ? */
2600                     goto trunctlv;
2601                 tptr+=ext_ip_len;
2602 		tmp-=ext_ip_len;
2603 	    }
2604 	    break;
2605 
2606         case ISIS_TLV_MT_IP_REACH:
2607             mt_len = isis_print_mtid(tptr, "\n\t      ");
2608             if (mt_len == 0) { /* did something go wrong ? */
2609                 goto trunctlv;
2610             }
2611             tptr+=mt_len;
2612             tmp-=mt_len;
2613 
2614             while (tmp>0) {
2615                 ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", AF_INET);
2616                 if (ext_ip_len == 0) /* did something go wrong ? */
2617                     goto trunctlv;
2618                 tptr+=ext_ip_len;
2619 		tmp-=ext_ip_len;
2620 	    }
2621 	    break;
2622 
2623 #ifdef INET6
2624 	case ISIS_TLV_IP6_REACH:
2625 	    while (tmp>0) {
2626                 ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", AF_INET6);
2627                 if (ext_ip_len == 0) /* did something go wrong ? */
2628                     goto trunctlv;
2629                 tptr+=ext_ip_len;
2630 		tmp-=ext_ip_len;
2631 	    }
2632 	    break;
2633 
2634 	case ISIS_TLV_MT_IP6_REACH:
2635             mt_len = isis_print_mtid(tptr, "\n\t      ");
2636             if (mt_len == 0) { /* did something go wrong ? */
2637                 goto trunctlv;
2638             }
2639             tptr+=mt_len;
2640             tmp-=mt_len;
2641 
2642 	    while (tmp>0) {
2643                 ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", AF_INET6);
2644                 if (ext_ip_len == 0) /* did something go wrong ? */
2645                     goto trunctlv;
2646                 tptr+=ext_ip_len;
2647 		tmp-=ext_ip_len;
2648 	    }
2649 	    break;
2650 
2651 	case ISIS_TLV_IP6ADDR:
2652 	    while (tmp>=sizeof(struct in6_addr)) {
2653 		if (!TTEST2(*tptr, sizeof(struct in6_addr)))
2654 		    goto trunctlv;
2655 
2656                 printf("\n\t      IPv6 interface address: %s",
2657 		       ip6addr_string(tptr));
2658 
2659 		tptr += sizeof(struct in6_addr);
2660 		tmp -= sizeof(struct in6_addr);
2661 	    }
2662 	    break;
2663 #endif
2664 	case ISIS_TLV_AUTH:
2665 	    if (!TTEST2(*tptr, 1))
2666 		goto trunctlv;
2667 
2668             printf("\n\t      %s: ",
2669                    tok2str(isis_subtlv_auth_values,
2670                            "unknown Authentication type 0x%02x",
2671                            *tptr));
2672 
2673 	    switch (*tptr) {
2674 	    case ISIS_SUBTLV_AUTH_SIMPLE:
2675 		for(i=1;i<tlv_len;i++) {
2676 		    if (!TTEST2(*(tptr+i), 1))
2677 			goto trunctlv;
2678 		    printf("%c",*(tptr+i));
2679 		}
2680 		break;
2681 	    case ISIS_SUBTLV_AUTH_MD5:
2682 		for(i=1;i<tlv_len;i++) {
2683 		    if (!TTEST2(*(tptr+i), 1))
2684 			goto trunctlv;
2685 		    printf("%02x",*(tptr+i));
2686 		}
2687 		if (tlv_len != ISIS_SUBTLV_AUTH_MD5_LEN+1)
2688                     printf(", (malformed subTLV) ");
2689 
2690 #ifdef HAVE_LIBCRYPTO
2691                 sigcheck = signature_verify(optr, length,
2692                                             (unsigned char *)tptr + 1);
2693 #else
2694                 sigcheck = CANT_CHECK_SIGNATURE;
2695 #endif
2696                 printf(" (%s)", tok2str(signature_check_values, "Unknown", sigcheck));
2697 
2698 		break;
2699             case ISIS_SUBTLV_AUTH_GENERIC:
2700                 key_id = EXTRACT_16BITS((tptr+1));
2701                 printf("%u, password: ", key_id);
2702                 for(i=1 + sizeof(u_int16_t);i<tlv_len;i++) {
2703                     if (!TTEST2(*(tptr+i), 1))
2704                         goto trunctlv;
2705                     printf("%02x",*(tptr+i));
2706                 }
2707                 break;
2708 	    case ISIS_SUBTLV_AUTH_PRIVATE:
2709 	    default:
2710 		if(!print_unknown_data(tptr+1,"\n\t\t  ",tlv_len-1))
2711 		    return(0);
2712 		break;
2713 	    }
2714 	    break;
2715 
2716 	case ISIS_TLV_PTP_ADJ:
2717 	    tlv_ptp_adj = (const struct isis_tlv_ptp_adj *)tptr;
2718 	    if(tmp>=1) {
2719 		if (!TTEST2(*tptr, 1))
2720 		    goto trunctlv;
2721 		printf("\n\t      Adjacency State: %s (%u)",
2722 		       tok2str(isis_ptp_adjancey_values, "unknown", *tptr),
2723                         *tptr);
2724 		tmp--;
2725 	    }
2726 	    if(tmp>sizeof(tlv_ptp_adj->extd_local_circuit_id)) {
2727 		if (!TTEST2(tlv_ptp_adj->extd_local_circuit_id,
2728                             sizeof(tlv_ptp_adj->extd_local_circuit_id)))
2729 		    goto trunctlv;
2730 		printf("\n\t      Extended Local circuit-ID: 0x%08x",
2731 		       EXTRACT_32BITS(tlv_ptp_adj->extd_local_circuit_id));
2732 		tmp-=sizeof(tlv_ptp_adj->extd_local_circuit_id);
2733 	    }
2734 	    if(tmp>=SYSTEM_ID_LEN) {
2735 		if (!TTEST2(tlv_ptp_adj->neighbor_sysid, SYSTEM_ID_LEN))
2736 		    goto trunctlv;
2737 		printf("\n\t      Neighbor System-ID: %s",
2738 		       isis_print_id(tlv_ptp_adj->neighbor_sysid,SYSTEM_ID_LEN));
2739 		tmp-=SYSTEM_ID_LEN;
2740 	    }
2741 	    if(tmp>=sizeof(tlv_ptp_adj->neighbor_extd_local_circuit_id)) {
2742 		if (!TTEST2(tlv_ptp_adj->neighbor_extd_local_circuit_id,
2743                             sizeof(tlv_ptp_adj->neighbor_extd_local_circuit_id)))
2744 		    goto trunctlv;
2745 		printf("\n\t      Neighbor Extended Local circuit-ID: 0x%08x",
2746 		       EXTRACT_32BITS(tlv_ptp_adj->neighbor_extd_local_circuit_id));
2747 	    }
2748 	    break;
2749 
2750 	case ISIS_TLV_PROTOCOLS:
2751 	    printf("\n\t      NLPID(s): ");
2752 	    while (tmp>0) {
2753 		if (!TTEST2(*(tptr), 1))
2754 		    goto trunctlv;
2755 		printf("%s (0x%02x)",
2756                        tok2str(nlpid_values,
2757                                "unknown",
2758                                *tptr),
2759                        *tptr);
2760 		if (tmp>1) /* further NPLIDs ? - put comma */
2761 		    printf(", ");
2762                 tptr++;
2763                 tmp--;
2764 	    }
2765 	    break;
2766 
2767     case ISIS_TLV_MT_PORT_CAP:
2768     {
2769       if (!TTEST2(*(tptr), 2))
2770         goto trunctlv;
2771 
2772       printf("\n\t       RES: %d, MTID(s): %d",
2773               (EXTRACT_16BITS (tptr) >> 12),
2774               (EXTRACT_16BITS (tptr) & 0x0fff));
2775 
2776       tmp = tmp-2;
2777       tptr = tptr+2;
2778 
2779       if (tmp)
2780         isis_print_mt_port_cap_subtlv (tptr, tmp);
2781 
2782       break;
2783     }
2784 
2785     case ISIS_TLV_MT_CAPABILITY:
2786 
2787       if (!TTEST2(*(tptr), 2))
2788         goto trunctlv;
2789 
2790       printf("\n\t      O: %d, RES: %d, MTID(s): %d",
2791                 (EXTRACT_16BITS(tptr) >> 15) & 0x01,
2792                 (EXTRACT_16BITS(tptr) >> 12) & 0x07,
2793                 EXTRACT_16BITS(tptr) & 0x0fff);
2794 
2795       tmp = tmp-2;
2796       tptr = tptr+2;
2797 
2798       if (tmp)
2799         isis_print_mt_capability_subtlv (tptr, tmp);
2800 
2801       break;
2802 
2803 	case ISIS_TLV_TE_ROUTER_ID:
2804 	    if (!TTEST2(*pptr, sizeof(struct in_addr)))
2805 		goto trunctlv;
2806 	    printf("\n\t      Traffic Engineering Router ID: %s", ipaddr_string(pptr));
2807 	    break;
2808 
2809 	case ISIS_TLV_IPADDR:
2810 	    while (tmp>=sizeof(struct in_addr)) {
2811 		if (!TTEST2(*tptr, sizeof(struct in_addr)))
2812 		    goto trunctlv;
2813 		printf("\n\t      IPv4 interface address: %s", ipaddr_string(tptr));
2814 		tptr += sizeof(struct in_addr);
2815 		tmp -= sizeof(struct in_addr);
2816 	    }
2817 	    break;
2818 
2819 	case ISIS_TLV_HOSTNAME:
2820 	    printf("\n\t      Hostname: ");
2821 	    while (tmp>0) {
2822 		if (!TTEST2(*tptr, 1))
2823 		    goto trunctlv;
2824 		printf("%c",*tptr++);
2825                 tmp--;
2826 	    }
2827 	    break;
2828 
2829 	case ISIS_TLV_SHARED_RISK_GROUP:
2830 	    if (tmp < NODE_ID_LEN)
2831 	        break;
2832 	    if (!TTEST2(*tptr, NODE_ID_LEN))
2833                 goto trunctlv;
2834 	    printf("\n\t      IS Neighbor: %s", isis_print_id(tptr, NODE_ID_LEN));
2835 	    tptr+=(NODE_ID_LEN);
2836 	    tmp-=(NODE_ID_LEN);
2837 
2838 	    if (tmp < 1)
2839 	        break;
2840 	    if (!TTEST2(*tptr, 1))
2841                 goto trunctlv;
2842 	    printf(", Flags: [%s]", ISIS_MASK_TLV_SHARED_RISK_GROUP(*tptr++) ? "numbered" : "unnumbered");
2843 	    tmp--;
2844 
2845 	    if (tmp < sizeof(struct in_addr))
2846 	        break;
2847 	    if (!TTEST2(*tptr,sizeof(struct in_addr)))
2848                 goto trunctlv;
2849 	    printf("\n\t      IPv4 interface address: %s", ipaddr_string(tptr));
2850 	    tptr+=sizeof(struct in_addr);
2851 	    tmp-=sizeof(struct in_addr);
2852 
2853 	    if (tmp < sizeof(struct in_addr))
2854 	        break;
2855 	    if (!TTEST2(*tptr,sizeof(struct in_addr)))
2856                 goto trunctlv;
2857 	    printf("\n\t      IPv4 neighbor address: %s", ipaddr_string(tptr));
2858 	    tptr+=sizeof(struct in_addr);
2859 	    tmp-=sizeof(struct in_addr);
2860 
2861 	    while (tmp>=4) {
2862                 if (!TTEST2(*tptr, 4))
2863                     goto trunctlv;
2864                 printf("\n\t      Link-ID: 0x%08x", EXTRACT_32BITS(tptr));
2865                 tptr+=4;
2866                 tmp-=4;
2867 	    }
2868 	    break;
2869 
2870 	case ISIS_TLV_LSP:
2871 	    tlv_lsp = (const struct isis_tlv_lsp *)tptr;
2872 	    while(tmp>=sizeof(struct isis_tlv_lsp)) {
2873 		if (!TTEST((tlv_lsp->lsp_id)[LSP_ID_LEN-1]))
2874 		    goto trunctlv;
2875 		printf("\n\t      lsp-id: %s",
2876                        isis_print_id(tlv_lsp->lsp_id, LSP_ID_LEN));
2877 		if (!TTEST2(tlv_lsp->sequence_number, 4))
2878 		    goto trunctlv;
2879 		printf(", seq: 0x%08x",EXTRACT_32BITS(tlv_lsp->sequence_number));
2880 		if (!TTEST2(tlv_lsp->remaining_lifetime, 2))
2881 		    goto trunctlv;
2882 		printf(", lifetime: %5ds",EXTRACT_16BITS(tlv_lsp->remaining_lifetime));
2883 		if (!TTEST2(tlv_lsp->checksum, 2))
2884 		    goto trunctlv;
2885 		printf(", chksum: 0x%04x",EXTRACT_16BITS(tlv_lsp->checksum));
2886 		tmp-=sizeof(struct isis_tlv_lsp);
2887 		tlv_lsp++;
2888 	    }
2889 	    break;
2890 
2891 	case ISIS_TLV_CHECKSUM:
2892 	    if (tmp < ISIS_TLV_CHECKSUM_MINLEN)
2893 	        break;
2894 	    if (!TTEST2(*tptr, ISIS_TLV_CHECKSUM_MINLEN))
2895 		goto trunctlv;
2896 	    printf("\n\t      checksum: 0x%04x ", EXTRACT_16BITS(tptr));
2897             /* do not attempt to verify the checksum if it is zero
2898              * most likely a HMAC-MD5 TLV is also present and
2899              * to avoid conflicts the checksum TLV is zeroed.
2900              * see rfc3358 for details
2901              */
2902             osi_print_cksum(optr, EXTRACT_16BITS(tptr), tptr-optr, length);
2903 	    break;
2904 
2905 	case ISIS_TLV_MT_SUPPORTED:
2906             if (tmp < ISIS_TLV_MT_SUPPORTED_MINLEN)
2907                 break;
2908 	    while (tmp>1) {
2909 		/* length can only be a multiple of 2, otherwise there is
2910 		   something broken -> so decode down until length is 1 */
2911 		if (tmp!=1) {
2912                     mt_len = isis_print_mtid(tptr, "\n\t      ");
2913                     if (mt_len == 0) /* did something go wrong ? */
2914                         goto trunctlv;
2915                     tptr+=mt_len;
2916                     tmp-=mt_len;
2917 		} else {
2918 		    printf("\n\t      malformed MT-ID");
2919 		    break;
2920 		}
2921 	    }
2922 	    break;
2923 
2924 	case ISIS_TLV_RESTART_SIGNALING:
2925             /* first attempt to decode the flags */
2926             if (tmp < ISIS_TLV_RESTART_SIGNALING_FLAGLEN)
2927                 break;
2928             if (!TTEST2(*tptr, ISIS_TLV_RESTART_SIGNALING_FLAGLEN))
2929                 goto trunctlv;
2930             printf("\n\t      Flags [%s]",
2931                    bittok2str(isis_restart_flag_values, "none", *tptr));
2932             tptr+=ISIS_TLV_RESTART_SIGNALING_FLAGLEN;
2933             tmp-=ISIS_TLV_RESTART_SIGNALING_FLAGLEN;
2934 
2935             /* is there anything other than the flags field? */
2936             if (tmp == 0)
2937                 break;
2938 
2939             if (tmp < ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN)
2940                 break;
2941             if (!TTEST2(*tptr, ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN))
2942                 goto trunctlv;
2943 
2944             printf(", Remaining holding time %us", EXTRACT_16BITS(tptr));
2945             tptr+=ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN;
2946             tmp-=ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN;
2947 
2948             /* is there an additional sysid field present ?*/
2949             if (tmp == SYSTEM_ID_LEN) {
2950                     if (!TTEST2(*tptr, SYSTEM_ID_LEN))
2951                             goto trunctlv;
2952                     printf(", for %s",isis_print_id(tptr,SYSTEM_ID_LEN));
2953             }
2954 	    break;
2955 
2956         case ISIS_TLV_IDRP_INFO:
2957 	    if (tmp < ISIS_TLV_IDRP_INFO_MINLEN)
2958 	        break;
2959             if (!TTEST2(*tptr, ISIS_TLV_IDRP_INFO_MINLEN))
2960                 goto trunctlv;
2961             printf("\n\t      Inter-Domain Information Type: %s",
2962                    tok2str(isis_subtlv_idrp_values,
2963                            "Unknown (0x%02x)",
2964                            *tptr));
2965             switch (*tptr++) {
2966             case ISIS_SUBTLV_IDRP_ASN:
2967                 if (!TTEST2(*tptr, 2)) /* fetch AS number */
2968                     goto trunctlv;
2969                 printf("AS Number: %u",EXTRACT_16BITS(tptr));
2970                 break;
2971             case ISIS_SUBTLV_IDRP_LOCAL:
2972             case ISIS_SUBTLV_IDRP_RES:
2973             default:
2974                 if(!print_unknown_data(tptr,"\n\t      ",tlv_len-1))
2975                     return(0);
2976                 break;
2977             }
2978             break;
2979 
2980         case ISIS_TLV_LSP_BUFFERSIZE:
2981 	    if (tmp < ISIS_TLV_LSP_BUFFERSIZE_MINLEN)
2982 	        break;
2983             if (!TTEST2(*tptr, ISIS_TLV_LSP_BUFFERSIZE_MINLEN))
2984                 goto trunctlv;
2985             printf("\n\t      LSP Buffersize: %u",EXTRACT_16BITS(tptr));
2986             break;
2987 
2988         case ISIS_TLV_PART_DIS:
2989             while (tmp >= SYSTEM_ID_LEN) {
2990                 if (!TTEST2(*tptr, SYSTEM_ID_LEN))
2991                     goto trunctlv;
2992                 printf("\n\t      %s",isis_print_id(tptr,SYSTEM_ID_LEN));
2993                 tptr+=SYSTEM_ID_LEN;
2994                 tmp-=SYSTEM_ID_LEN;
2995             }
2996             break;
2997 
2998         case ISIS_TLV_PREFIX_NEIGH:
2999 	    if (tmp < sizeof(struct isis_metric_block))
3000 	        break;
3001             if (!TTEST2(*tptr, sizeof(struct isis_metric_block)))
3002                 goto trunctlv;
3003             printf("\n\t      Metric Block");
3004             isis_print_metric_block((const struct isis_metric_block *)tptr);
3005             tptr+=sizeof(struct isis_metric_block);
3006             tmp-=sizeof(struct isis_metric_block);
3007 
3008             while(tmp>0) {
3009                 if (!TTEST2(*tptr, 1))
3010                     goto trunctlv;
3011                 prefix_len=*tptr++; /* read out prefix length in semioctets*/
3012                 if (prefix_len < 2) {
3013                     printf("\n\t\tAddress: prefix length %u < 2", prefix_len);
3014                     break;
3015                 }
3016                 tmp--;
3017                 if (tmp < prefix_len/2)
3018                     break;
3019                 if (!TTEST2(*tptr, prefix_len/2))
3020                     goto trunctlv;
3021                 printf("\n\t\tAddress: %s/%u",
3022                        isonsap_string(tptr,prefix_len/2),
3023                        prefix_len*4);
3024                 tptr+=prefix_len/2;
3025                 tmp-=prefix_len/2;
3026             }
3027             break;
3028 
3029         case ISIS_TLV_IIH_SEQNR:
3030 	    if (tmp < ISIS_TLV_IIH_SEQNR_MINLEN)
3031 	        break;
3032             if (!TTEST2(*tptr, ISIS_TLV_IIH_SEQNR_MINLEN)) /* check if four bytes are on the wire */
3033                 goto trunctlv;
3034             printf("\n\t      Sequence number: %u", EXTRACT_32BITS(tptr) );
3035             break;
3036 
3037         case ISIS_TLV_VENDOR_PRIVATE:
3038 	    if (tmp < ISIS_TLV_VENDOR_PRIVATE_MINLEN)
3039 	        break;
3040             if (!TTEST2(*tptr, ISIS_TLV_VENDOR_PRIVATE_MINLEN)) /* check if enough byte for a full oui */
3041                 goto trunctlv;
3042             vendor_id = EXTRACT_24BITS(tptr);
3043             printf("\n\t      Vendor: %s (%u)",
3044                    tok2str(oui_values,"Unknown",vendor_id),
3045                    vendor_id);
3046             tptr+=3;
3047             tmp-=3;
3048             if (tmp > 0) /* hexdump the rest */
3049                 if(!print_unknown_data(tptr,"\n\t\t",tmp))
3050                     return(0);
3051             break;
3052             /*
3053              * FIXME those are the defined TLVs that lack a decoder
3054              * you are welcome to contribute code ;-)
3055              */
3056 
3057         case ISIS_TLV_DECNET_PHASE4:
3058         case ISIS_TLV_LUCENT_PRIVATE:
3059         case ISIS_TLV_IPAUTH:
3060         case ISIS_TLV_NORTEL_PRIVATE1:
3061         case ISIS_TLV_NORTEL_PRIVATE2:
3062 
3063 	default:
3064             if (vflag <= 1) {
3065                 if(!print_unknown_data(pptr,"\n\t\t",tlv_len))
3066                     return(0);
3067             }
3068 	    break;
3069 	}
3070         /* do we want to see an additionally hexdump ? */
3071         if (vflag> 1) {
3072 	    if(!print_unknown_data(pptr,"\n\t      ",tlv_len))
3073 	        return(0);
3074         }
3075 
3076 	pptr += tlv_len;
3077 	packet_len -= tlv_len;
3078     }
3079 
3080     if (packet_len != 0) {
3081 	printf("\n\t      %u straggler bytes", packet_len);
3082     }
3083     return (1);
3084 
3085  trunc:
3086     fputs("[|isis]", stdout);
3087     return (1);
3088 
3089  trunctlv:
3090     printf("\n\t\t packet exceeded snapshot");
3091     return(1);
3092 }
3093 
3094 static void
3095 osi_print_cksum (const u_int8_t *pptr, u_int16_t checksum,
3096                     u_int checksum_offset, u_int length)
3097 {
3098         u_int16_t calculated_checksum;
3099 
3100         /* do not attempt to verify the checksum if it is zero */
3101         if (!checksum) {
3102                 printf("(unverified)");
3103         } else {
3104                 calculated_checksum = create_osi_cksum(pptr, checksum_offset, length);
3105                 if (checksum == calculated_checksum) {
3106                         printf(" (correct)");
3107                 } else {
3108                         printf(" (incorrect should be 0x%04x)", calculated_checksum);
3109                 }
3110         }
3111 }
3112 
3113 /*
3114  * Local Variables:
3115  * c-style: whitesmith
3116  * c-basic-offset: 8
3117  * End:
3118  */
3119