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