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