print-isoclns.c revision 172686
117680Spst/*
217680Spst * Copyright (c) 1992, 1993, 1994, 1995, 1996
317680Spst *	The Regents of the University of California.  All rights reserved.
417680Spst *
517680Spst * Redistribution and use in source and binary forms, with or without
617680Spst * modification, are permitted provided that: (1) source code distributions
717680Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817680Spst * distributions including binary code include the above copyright notice and
917680Spst * this paragraph in its entirety in the documentation or other materials
1017680Spst * provided with the distribution, and (3) all advertising materials mentioning
1117680Spst * features or use of this software display the following acknowledgement:
1217680Spst * ``This product includes software developed by the University of California,
1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417680Spst * the University nor the names of its contributors may be used to endorse
1517680Spst * or promote products derived from this software without specific prior
1617680Spst * written permission.
1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2026183Sfenner *
2117680Spst * Original code by Matt Thomas, Digital Equipment Corporation
2256896Sfenner *
2398527Sfenner * Extensively modified by Hannes Gredler (hannes@juniper.net) for more
24146778Ssam * complete IS-IS & CLNP support.
2598527Sfenner *
2656896Sfenner * $FreeBSD: head/contrib/tcpdump/print-isoclns.c 172686 2007-10-16 02:31:48Z mlaier $
2717680Spst */
2817680Spst
2917680Spst#ifndef lint
30127675Sbmsstatic const char rcsid[] _U_ =
31172686Smlaier    "@(#) $Header: /tcpdump/master/tcpdump/print-isoclns.c,v 1.133.2.25 2007/03/02 09:20:27 hannes Exp $ (LBL)";
3217680Spst#endif
3317680Spst
3456896Sfenner#ifdef HAVE_CONFIG_H
3556896Sfenner#include "config.h"
3656896Sfenner#endif
3756896Sfenner
38127675Sbms#include <tcpdump-stdinc.h>
3917680Spst
4017680Spst#include <stdio.h>
4198527Sfenner#include <string.h>
4217680Spst
4317680Spst#include "interface.h"
4417680Spst#include "addrtoname.h"
4517680Spst#include "ethertype.h"
4675118Sfenner#include "ether.h"
47146778Ssam#include "nlpid.h"
4817688Spst#include "extract.h"
49127675Sbms#include "gmpls.h"
50146778Ssam#include "oui.h"
5117680Spst
52127675Sbms#define IPV4            1       /* AFI value */
53127675Sbms#define IPV6            2       /* AFI value */
54127675Sbms
5532149Spst/*
5632149Spst * IS-IS is defined in ISO 10589.  Look there for protocol definitions.
5732149Spst */
5832149Spst
5975118Sfenner#define SYSTEM_ID_LEN	ETHER_ADDR_LEN
60127675Sbms#define NODE_ID_LEN     SYSTEM_ID_LEN+1
61127675Sbms#define LSP_ID_LEN      SYSTEM_ID_LEN+2
62127675Sbms
6332149Spst#define ISIS_VERSION	1
64146778Ssam#define ESIS_VERSION	1
65146778Ssam#define CLNP_VERSION	1
6632149Spst
67146778Ssam#define ISIS_PDU_TYPE_MASK      0x1F
68146778Ssam#define ESIS_PDU_TYPE_MASK      0x1F
69146778Ssam#define CLNP_PDU_TYPE_MASK      0x1F
70146778Ssam#define CLNP_FLAG_MASK          0xE0
71146778Ssam#define ISIS_LAN_PRIORITY_MASK  0x7F
7232149Spst
73146778Ssam#define ISIS_PDU_L1_LAN_IIH	15
74146778Ssam#define ISIS_PDU_L2_LAN_IIH	16
75146778Ssam#define ISIS_PDU_PTP_IIH	17
76146778Ssam#define ISIS_PDU_L1_LSP       	18
77146778Ssam#define ISIS_PDU_L2_LSP       	20
78146778Ssam#define ISIS_PDU_L1_CSNP  	24
79146778Ssam#define ISIS_PDU_L2_CSNP  	25
80146778Ssam#define ISIS_PDU_L1_PSNP        26
81146778Ssam#define ISIS_PDU_L2_PSNP        27
82146778Ssam
83127675Sbmsstatic struct tok isis_pdu_values[] = {
84146778Ssam    { ISIS_PDU_L1_LAN_IIH,       "L1 Lan IIH"},
85146778Ssam    { ISIS_PDU_L2_LAN_IIH,       "L2 Lan IIH"},
86146778Ssam    { ISIS_PDU_PTP_IIH,          "p2p IIH"},
87146778Ssam    { ISIS_PDU_L1_LSP,           "L1 LSP"},
88146778Ssam    { ISIS_PDU_L2_LSP,           "L2 LSP"},
89146778Ssam    { ISIS_PDU_L1_CSNP,          "L1 CSNP"},
90146778Ssam    { ISIS_PDU_L2_CSNP,          "L2 CSNP"},
91146778Ssam    { ISIS_PDU_L1_PSNP,          "L1 PSNP"},
92146778Ssam    { ISIS_PDU_L2_PSNP,          "L2 PSNP"},
93127675Sbms    { 0, NULL}
94127675Sbms};
9598527Sfenner
9632149Spst/*
9732149Spst * A TLV is a tuple of a type, length and a value and is normally used for
9832149Spst * encoding information in all sorts of places.  This is an enumeration of
9932149Spst * the well known types.
100127675Sbms *
101127675Sbms * list taken from rfc3359 plus some memory from veterans ;-)
10232149Spst */
10332149Spst
104146778Ssam#define ISIS_TLV_AREA_ADDR           1   /* iso10589 */
105146778Ssam#define ISIS_TLV_IS_REACH            2   /* iso10589 */
106146778Ssam#define ISIS_TLV_ESNEIGH             3   /* iso10589 */
107146778Ssam#define ISIS_TLV_PART_DIS            4   /* iso10589 */
108146778Ssam#define ISIS_TLV_PREFIX_NEIGH        5   /* iso10589 */
109146778Ssam#define ISIS_TLV_ISNEIGH             6   /* iso10589 */
110146778Ssam#define ISIS_TLV_ISNEIGH_VARLEN      7   /* iso10589 */
111146778Ssam#define ISIS_TLV_PADDING             8   /* iso10589 */
112146778Ssam#define ISIS_TLV_LSP                 9   /* iso10589 */
113146778Ssam#define ISIS_TLV_AUTH                10  /* iso10589, rfc3567 */
114146778Ssam#define ISIS_TLV_CHECKSUM            12  /* rfc3358 */
115162021Ssam#define ISIS_TLV_CHECKSUM_MINLEN 2
116146778Ssam#define ISIS_TLV_LSP_BUFFERSIZE      14  /* iso10589 rev2 */
117162021Ssam#define ISIS_TLV_LSP_BUFFERSIZE_MINLEN 2
118146778Ssam#define ISIS_TLV_EXT_IS_REACH        22  /* draft-ietf-isis-traffic-05 */
119146778Ssam#define ISIS_TLV_IS_ALIAS_ID         24  /* draft-ietf-isis-ext-lsp-frags-02 */
120146778Ssam#define ISIS_TLV_DECNET_PHASE4       42
121146778Ssam#define ISIS_TLV_LUCENT_PRIVATE      66
122146778Ssam#define ISIS_TLV_INT_IP_REACH        128 /* rfc1195, rfc2966 */
123146778Ssam#define ISIS_TLV_PROTOCOLS           129 /* rfc1195 */
124146778Ssam#define ISIS_TLV_EXT_IP_REACH        130 /* rfc1195, rfc2966 */
125146778Ssam#define ISIS_TLV_IDRP_INFO           131 /* rfc1195 */
126162021Ssam#define ISIS_TLV_IDRP_INFO_MINLEN      1
127146778Ssam#define ISIS_TLV_IPADDR              132 /* rfc1195 */
128146778Ssam#define ISIS_TLV_IPAUTH              133 /* rfc1195 */
129146778Ssam#define ISIS_TLV_TE_ROUTER_ID        134 /* draft-ietf-isis-traffic-05 */
130146778Ssam#define ISIS_TLV_EXTD_IP_REACH       135 /* draft-ietf-isis-traffic-05 */
131146778Ssam#define ISIS_TLV_HOSTNAME            137 /* rfc2763 */
132146778Ssam#define ISIS_TLV_SHARED_RISK_GROUP   138 /* draft-ietf-isis-gmpls-extensions */
133146778Ssam#define ISIS_TLV_NORTEL_PRIVATE1     176
134146778Ssam#define ISIS_TLV_NORTEL_PRIVATE2     177
135147904Ssam#define ISIS_TLV_RESTART_SIGNALING   211 /* rfc3847 */
136162021Ssam#define ISIS_TLV_RESTART_SIGNALING_FLAGLEN 1
137162021Ssam#define ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN 2
138146778Ssam#define ISIS_TLV_MT_IS_REACH         222 /* draft-ietf-isis-wg-multi-topology-05 */
139146778Ssam#define ISIS_TLV_MT_SUPPORTED        229 /* draft-ietf-isis-wg-multi-topology-05 */
140162021Ssam#define ISIS_TLV_MT_SUPPORTED_MINLEN 2
141146778Ssam#define ISIS_TLV_IP6ADDR             232 /* draft-ietf-isis-ipv6-02 */
142146778Ssam#define ISIS_TLV_MT_IP_REACH         235 /* draft-ietf-isis-wg-multi-topology-05 */
143146778Ssam#define ISIS_TLV_IP6_REACH           236 /* draft-ietf-isis-ipv6-02 */
144146778Ssam#define ISIS_TLV_MT_IP6_REACH        237 /* draft-ietf-isis-wg-multi-topology-05 */
145146778Ssam#define ISIS_TLV_PTP_ADJ             240 /* rfc3373 */
146146778Ssam#define ISIS_TLV_IIH_SEQNR           241 /* draft-shen-isis-iih-sequence-00 */
147162021Ssam#define ISIS_TLV_IIH_SEQNR_MINLEN 4
148146778Ssam#define ISIS_TLV_VENDOR_PRIVATE      250 /* draft-ietf-isis-experimental-tlv-01 */
149162021Ssam#define ISIS_TLV_VENDOR_PRIVATE_MINLEN 3
15032149Spst
151127675Sbmsstatic struct tok isis_tlv_values[] = {
152146778Ssam    { ISIS_TLV_AREA_ADDR,	   "Area address(es)"},
153146778Ssam    { ISIS_TLV_IS_REACH,           "IS Reachability"},
154146778Ssam    { ISIS_TLV_ESNEIGH,            "ES Neighbor(s)"},
155146778Ssam    { ISIS_TLV_PART_DIS,           "Partition DIS"},
156146778Ssam    { ISIS_TLV_PREFIX_NEIGH,       "Prefix Neighbors"},
157146778Ssam    { ISIS_TLV_ISNEIGH,            "IS Neighbor(s)"},
158146778Ssam    { ISIS_TLV_ISNEIGH_VARLEN,     "IS Neighbor(s) (variable length)"},
159146778Ssam    { ISIS_TLV_PADDING,            "Padding"},
160146778Ssam    { ISIS_TLV_LSP,                "LSP entries"},
161146778Ssam    { ISIS_TLV_AUTH,               "Authentication"},
162146778Ssam    { ISIS_TLV_CHECKSUM,           "Checksum"},
163146778Ssam    { ISIS_TLV_LSP_BUFFERSIZE,     "LSP Buffersize"},
164146778Ssam    { ISIS_TLV_EXT_IS_REACH,       "Extended IS Reachability"},
165146778Ssam    { ISIS_TLV_IS_ALIAS_ID,        "IS Alias ID"},
166146778Ssam    { ISIS_TLV_DECNET_PHASE4,      "DECnet Phase IV"},
167146778Ssam    { ISIS_TLV_LUCENT_PRIVATE,     "Lucent Proprietary"},
168146778Ssam    { ISIS_TLV_INT_IP_REACH,       "IPv4 Internal Reachability"},
169146778Ssam    { ISIS_TLV_PROTOCOLS,          "Protocols supported"},
170146778Ssam    { ISIS_TLV_EXT_IP_REACH,       "IPv4 External Reachability"},
171146778Ssam    { ISIS_TLV_IDRP_INFO,          "Inter-Domain Information Type"},
172146778Ssam    { ISIS_TLV_IPADDR,             "IPv4 Interface address(es)"},
173146778Ssam    { ISIS_TLV_IPAUTH,             "IPv4 authentication (deprecated)"},
174146778Ssam    { ISIS_TLV_TE_ROUTER_ID,       "Traffic Engineering Router ID"},
175146778Ssam    { ISIS_TLV_EXTD_IP_REACH,      "Extended IPv4 Reachability"},
176146778Ssam    { ISIS_TLV_SHARED_RISK_GROUP,  "Shared Risk Link Group"},
177146778Ssam    { ISIS_TLV_NORTEL_PRIVATE1,    "Nortel Proprietary"},
178146778Ssam    { ISIS_TLV_NORTEL_PRIVATE2,    "Nortel Proprietary"},
179146778Ssam    { ISIS_TLV_HOSTNAME,           "Hostname"},
180146778Ssam    { ISIS_TLV_RESTART_SIGNALING,  "Restart Signaling"},
181146778Ssam    { ISIS_TLV_MT_IS_REACH,        "Multi Topology IS Reachability"},
182146778Ssam    { ISIS_TLV_MT_SUPPORTED,       "Multi Topology"},
183146778Ssam    { ISIS_TLV_IP6ADDR,            "IPv6 Interface address(es)"},
184146778Ssam    { ISIS_TLV_MT_IP_REACH,        "Multi-Topology IPv4 Reachability"},
185146778Ssam    { ISIS_TLV_IP6_REACH,          "IPv6 reachability"},
186146778Ssam    { ISIS_TLV_MT_IP6_REACH,       "Multi-Topology IP6 Reachability"},
187146778Ssam    { ISIS_TLV_PTP_ADJ,            "Point-to-point Adjacency State"},
188146778Ssam    { ISIS_TLV_IIH_SEQNR,          "Hello PDU Sequence Number"},
189146778Ssam    { ISIS_TLV_VENDOR_PRIVATE,     "Vendor Private"},
190127675Sbms    { 0, NULL }
191127675Sbms};
19298527Sfenner
193146778Ssam#define ESIS_OPTION_PROTOCOLS        129
194146778Ssam#define ESIS_OPTION_QOS_MAINTENANCE  195 /* iso9542 */
195146778Ssam#define ESIS_OPTION_SECURITY         197 /* iso9542 */
196146778Ssam#define ESIS_OPTION_ES_CONF_TIME     198 /* iso9542 */
197146778Ssam#define ESIS_OPTION_PRIORITY         205 /* iso9542 */
198146778Ssam#define ESIS_OPTION_ADDRESS_MASK     225 /* iso9542 */
199146778Ssam#define ESIS_OPTION_SNPA_MASK        226 /* iso9542 */
20098527Sfenner
201146778Ssamstatic struct tok esis_option_values[] = {
202146778Ssam    { ESIS_OPTION_PROTOCOLS,       "Protocols supported"},
203146778Ssam    { ESIS_OPTION_QOS_MAINTENANCE, "QoS Maintenance" },
204146778Ssam    { ESIS_OPTION_SECURITY,        "Security" },
205146778Ssam    { ESIS_OPTION_ES_CONF_TIME,    "ES Configuration Time" },
206146778Ssam    { ESIS_OPTION_PRIORITY,        "Priority" },
207146778Ssam    { ESIS_OPTION_ADDRESS_MASK,    "Addressk Mask" },
208146778Ssam    { ESIS_OPTION_SNPA_MASK,       "SNPA Mask" },
209146778Ssam    { 0, NULL }
210146778Ssam};
211146778Ssam
212146778Ssam#define CLNP_OPTION_DISCARD_REASON   193
213146778Ssam#define CLNP_OPTION_QOS_MAINTENANCE  195 /* iso8473 */
214147904Ssam#define CLNP_OPTION_SECURITY         197 /* iso8473 */
215147904Ssam#define CLNP_OPTION_SOURCE_ROUTING   200 /* iso8473 */
216147904Ssam#define CLNP_OPTION_ROUTE_RECORDING  203 /* iso8473 */
217147904Ssam#define CLNP_OPTION_PADDING          204 /* iso8473 */
218146778Ssam#define CLNP_OPTION_PRIORITY         205 /* iso8473 */
219146778Ssam
220146778Ssamstatic struct tok clnp_option_values[] = {
221146778Ssam    { CLNP_OPTION_DISCARD_REASON,  "Discard Reason"},
222146778Ssam    { CLNP_OPTION_PRIORITY,        "Priority"},
223146778Ssam    { CLNP_OPTION_QOS_MAINTENANCE, "QoS Maintenance"},
224147904Ssam    { CLNP_OPTION_SECURITY, "Security"},
225147904Ssam    { CLNP_OPTION_SOURCE_ROUTING, "Source Routing"},
226147904Ssam    { CLNP_OPTION_ROUTE_RECORDING, "Route Recording"},
227147904Ssam    { CLNP_OPTION_PADDING, "Padding"},
228146778Ssam    { 0, NULL }
229146778Ssam};
230146778Ssam
231146778Ssamstatic struct tok clnp_option_rfd_class_values[] = {
232146778Ssam    { 0x0, "General"},
233146778Ssam    { 0x8, "Address"},
234146778Ssam    { 0x9, "Source Routeing"},
235146778Ssam    { 0xa, "Lifetime"},
236146778Ssam    { 0xb, "PDU Discarded"},
237146778Ssam    { 0xc, "Reassembly"},
238146778Ssam    { 0, NULL }
239146778Ssam};
240146778Ssam
241146778Ssamstatic struct tok clnp_option_rfd_general_values[] = {
242146778Ssam    { 0x0, "Reason not specified"},
243146778Ssam    { 0x1, "Protocol procedure error"},
244146778Ssam    { 0x2, "Incorrect checksum"},
245146778Ssam    { 0x3, "PDU discarded due to congestion"},
246146778Ssam    { 0x4, "Header syntax error (cannot be parsed)"},
247146778Ssam    { 0x5, "Segmentation needed but not permitted"},
248146778Ssam    { 0x6, "Incomplete PDU received"},
249146778Ssam    { 0x7, "Duplicate option"},
250146778Ssam    { 0, NULL }
251146778Ssam};
252146778Ssam
253146778Ssamstatic struct tok clnp_option_rfd_address_values[] = {
254146778Ssam    { 0x0, "Destination address unreachable"},
255146778Ssam    { 0x1, "Destination address unknown"},
256146778Ssam    { 0, NULL }
257146778Ssam};
258146778Ssam
259146778Ssamstatic struct tok clnp_option_rfd_source_routeing_values[] = {
260146778Ssam    { 0x0, "Unspecified source routeing error"},
261146778Ssam    { 0x1, "Syntax error in source routeing field"},
262146778Ssam    { 0x2, "Unknown address in source routeing field"},
263146778Ssam    { 0x3, "Path not acceptable"},
264146778Ssam    { 0, NULL }
265146778Ssam};
266146778Ssam
267146778Ssamstatic struct tok clnp_option_rfd_lifetime_values[] = {
268146778Ssam    { 0x0, "Lifetime expired while data unit in transit"},
269146778Ssam    { 0x1, "Lifetime expired during reassembly"},
270146778Ssam    { 0, NULL }
271146778Ssam};
272146778Ssam
273146778Ssamstatic struct tok clnp_option_rfd_pdu_discard_values[] = {
274146778Ssam    { 0x0, "Unsupported option not specified"},
275146778Ssam    { 0x1, "Unsupported protocol version"},
276146778Ssam    { 0x2, "Unsupported security option"},
277146778Ssam    { 0x3, "Unsupported source routeing option"},
278146778Ssam    { 0x4, "Unsupported recording of route option"},
279146778Ssam    { 0, NULL }
280146778Ssam};
281146778Ssam
282146778Ssamstatic struct tok clnp_option_rfd_reassembly_values[] = {
283146778Ssam    { 0x0, "Reassembly interference"},
284146778Ssam    { 0, NULL }
285146778Ssam};
286146778Ssam
287146778Ssam/* array of 16 error-classes */
288146778Ssamstatic struct tok *clnp_option_rfd_error_class[] = {
289146778Ssam    clnp_option_rfd_general_values,
290146778Ssam    NULL,
291146778Ssam    NULL,
292146778Ssam    NULL,
293146778Ssam    NULL,
294146778Ssam    NULL,
295146778Ssam    NULL,
296146778Ssam    NULL,
297146778Ssam    clnp_option_rfd_address_values,
298146778Ssam    clnp_option_rfd_source_routeing_values,
299146778Ssam    clnp_option_rfd_lifetime_values,
300146778Ssam    clnp_option_rfd_pdu_discard_values,
301146778Ssam    clnp_option_rfd_reassembly_values,
302146778Ssam    NULL,
303146778Ssam    NULL,
304146778Ssam    NULL
305146778Ssam};
306146778Ssam
307147904Ssam#define CLNP_OPTION_OPTION_QOS_MASK 0x3f
308147904Ssam#define CLNP_OPTION_SCOPE_MASK      0xc0
309147904Ssam#define CLNP_OPTION_SCOPE_SA_SPEC   0x40
310147904Ssam#define CLNP_OPTION_SCOPE_DA_SPEC   0x80
311147904Ssam#define CLNP_OPTION_SCOPE_GLOBAL    0xc0
312146778Ssam
313147904Ssamstatic struct tok clnp_option_scope_values[] = {
314147904Ssam    { CLNP_OPTION_SCOPE_SA_SPEC, "Source Address Specific"},
315147904Ssam    { CLNP_OPTION_SCOPE_DA_SPEC, "Destination Address Specific"},
316147904Ssam    { CLNP_OPTION_SCOPE_GLOBAL, "Globally unique"},
317147904Ssam    { 0, NULL }
318147904Ssam};
319147904Ssam
320147904Ssamstatic struct tok clnp_option_sr_rr_values[] = {
321147904Ssam    { 0x0, "partial"},
322147904Ssam    { 0x1, "complete"},
323147904Ssam    { 0, NULL }
324147904Ssam};
325147904Ssam
326147904Ssamstatic struct tok clnp_option_sr_rr_string_values[] = {
327147904Ssam    { CLNP_OPTION_SOURCE_ROUTING, "source routing"},
328147904Ssam    { CLNP_OPTION_ROUTE_RECORDING, "recording of route in progress"},
329147904Ssam    { 0, NULL }
330147904Ssam};
331147904Ssam
332147904Ssamstatic struct tok clnp_option_qos_global_values[] = {
333147904Ssam    { 0x20, "reserved"},
334147904Ssam    { 0x10, "sequencing vs. delay"},
335147904Ssam    { 0x08, "congested"},
336147904Ssam    { 0x04, "delay vs. cost"},
337147904Ssam    { 0x02, "error vs. delay"},
338147904Ssam    { 0x01, "error vs. cost"},
339147904Ssam    { 0, NULL }
340147904Ssam};
341147904Ssam
342146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP           3 /* draft-ietf-isis-traffic-05 */
343146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID  4 /* draft-ietf-isis-gmpls-extensions */
344146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID        5 /* draft-ietf-isis-traffic-05 */
345146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR        6 /* draft-ietf-isis-traffic-05 */
346146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR    8 /* draft-ietf-isis-traffic-05 */
347146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW           9 /* draft-ietf-isis-traffic-05 */
348146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW        10 /* draft-ietf-isis-traffic-05 */
349162021Ssam#define ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW        11 /* rfc4124 */
350162021Ssam#define ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS_OLD   12 /* draft-ietf-tewg-diff-te-proto-06 */
351146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC            18 /* draft-ietf-isis-traffic-05 */
352146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE 20 /* draft-ietf-isis-gmpls-extensions */
353146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR    21 /* draft-ietf-isis-gmpls-extensions */
354162021Ssam#define ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS       22 /* rfc4124 */
355146778Ssam
356127675Sbmsstatic struct tok isis_ext_is_reach_subtlv_values[] = {
357146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP,            "Administrative groups" },
358146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID,   "Link Local/Remote Identifier" },
359146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID,         "Link Remote Identifier" },
360146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR,         "IPv4 interface address" },
361146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR,     "IPv4 neighbor address" },
362146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW,            "Maximum link bandwidth" },
363146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW,          "Reservable link bandwidth" },
364146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW,          "Unreserved bandwidth" },
365146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC,              "Traffic Engineering Metric" },
366146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE,   "Link Protection Type" },
367146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR,      "Interface Switching Capability" },
368162021Ssam    { ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS_OLD,     "Bandwidth Constraints (old)" },
369162021Ssam    { ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS,         "Bandwidth Constraints" },
370146778Ssam    { 250,                                             "Reserved for cisco specific extensions" },
371146778Ssam    { 251,                                             "Reserved for cisco specific extensions" },
372146778Ssam    { 252,                                             "Reserved for cisco specific extensions" },
373146778Ssam    { 253,                                             "Reserved for cisco specific extensions" },
374146778Ssam    { 254,                                             "Reserved for cisco specific extensions" },
375146778Ssam    { 255,                                             "Reserved for future expansion" },
376127675Sbms    { 0, NULL }
377127675Sbms};
37898527Sfenner
379146778Ssam#define ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32          1 /* draft-ietf-isis-admin-tags-01 */
380146778Ssam#define ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64          2 /* draft-ietf-isis-admin-tags-01 */
381146778Ssam#define ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR  117 /* draft-ietf-isis-wg-multi-topology-05 */
382127675Sbms
383127675Sbmsstatic struct tok isis_ext_ip_reach_subtlv_values[] = {
384146778Ssam    { ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32,           "32-Bit Administrative tag" },
385146778Ssam    { ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64,           "64-Bit Administrative tag" },
386146778Ssam    { ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR,     "Management Prefix Color" },
387127675Sbms    { 0, NULL }
388127675Sbms};
389127675Sbms
390146778Ssam#define ISIS_SUBTLV_AUTH_SIMPLE        1
391146778Ssam#define ISIS_SUBTLV_AUTH_MD5          54
392146778Ssam#define ISIS_SUBTLV_AUTH_MD5_LEN      16
393146778Ssam#define ISIS_SUBTLV_AUTH_PRIVATE     255
394127675Sbms
395127675Sbmsstatic struct tok isis_subtlv_auth_values[] = {
396146778Ssam    { ISIS_SUBTLV_AUTH_SIMPLE,	"simple text password"},
397146778Ssam    { ISIS_SUBTLV_AUTH_MD5,	"HMAC-MD5 password"},
398146778Ssam    { ISIS_SUBTLV_AUTH_PRIVATE,	"Routing Domain private password"},
399127675Sbms    { 0, NULL }
400127675Sbms};
401127675Sbms
402146778Ssam#define ISIS_SUBTLV_IDRP_RES           0
403146778Ssam#define ISIS_SUBTLV_IDRP_LOCAL         1
404146778Ssam#define ISIS_SUBTLV_IDRP_ASN           2
405127675Sbms
406127675Sbmsstatic struct tok isis_subtlv_idrp_values[] = {
407146778Ssam    { ISIS_SUBTLV_IDRP_RES,         "Reserved"},
408146778Ssam    { ISIS_SUBTLV_IDRP_LOCAL,       "Routing-Domain Specific"},
409146778Ssam    { ISIS_SUBTLV_IDRP_ASN,         "AS Number Tag"},
410127675Sbms    { 0, NULL}
411127675Sbms};
412127675Sbms
413146778Ssam#define CLNP_SEGMENT_PART  0x80
414146778Ssam#define CLNP_MORE_SEGMENTS 0x40
415146778Ssam#define CLNP_REQUEST_ER    0x20
416127675Sbms
417146778Ssamstatic struct tok clnp_flag_values[] = {
418146778Ssam    { CLNP_SEGMENT_PART, "Segmentation permitted"},
419146778Ssam    { CLNP_MORE_SEGMENTS, "more Segments"},
420146778Ssam    { CLNP_REQUEST_ER, "request Error Report"},
421146778Ssam    { 0, NULL}
422146778Ssam};
423146778Ssam
42498527Sfenner#define ISIS_MASK_LSP_OL_BIT(x)            ((x)&0x4)
42598527Sfenner#define ISIS_MASK_LSP_ISTYPE_BITS(x)       ((x)&0x3)
42698527Sfenner#define ISIS_MASK_LSP_PARTITION_BIT(x)     ((x)&0x80)
42798527Sfenner#define ISIS_MASK_LSP_ATT_BITS(x)          ((x)&0x78)
42898527Sfenner#define ISIS_MASK_LSP_ATT_ERROR_BIT(x)     ((x)&0x40)
42998527Sfenner#define ISIS_MASK_LSP_ATT_EXPENSE_BIT(x)   ((x)&0x20)
43098527Sfenner#define ISIS_MASK_LSP_ATT_DELAY_BIT(x)     ((x)&0x10)
43198527Sfenner#define ISIS_MASK_LSP_ATT_DEFAULT_BIT(x)   ((x)&0x8)
43298527Sfenner
433127675Sbms#define ISIS_MASK_MTID(x)                  ((x)&0x0fff)
434127675Sbms#define ISIS_MASK_MTFLAGS(x)               ((x)&0xf000)
43598527Sfenner
436127675Sbmsstatic struct tok isis_mt_flag_values[] = {
437127675Sbms    { 0x4000,                  "sub-TLVs present"},
438127675Sbms    { 0x8000,                  "ATT bit set"},
439127675Sbms    { 0, NULL}
440127675Sbms};
44198527Sfenner
442127675Sbms#define ISIS_MASK_TLV_EXTD_IP_UPDOWN(x)     ((x)&0x80)
443127675Sbms#define ISIS_MASK_TLV_EXTD_IP_SUBTLV(x)     ((x)&0x40)
44498527Sfenner
445127675Sbms#define ISIS_MASK_TLV_EXTD_IP6_IE(x)        ((x)&0x40)
446127675Sbms#define ISIS_MASK_TLV_EXTD_IP6_SUBTLV(x)    ((x)&0x20)
447127675Sbms
44898527Sfenner#define ISIS_LSP_TLV_METRIC_SUPPORTED(x)   ((x)&0x80)
44998527Sfenner#define ISIS_LSP_TLV_METRIC_IE(x)          ((x)&0x40)
45098527Sfenner#define ISIS_LSP_TLV_METRIC_UPDOWN(x)      ((x)&0x80)
45198527Sfenner#define ISIS_LSP_TLV_METRIC_VALUE(x)	   ((x)&0x3f)
45298527Sfenner
453127675Sbms#define ISIS_MASK_TLV_SHARED_RISK_GROUP(x) ((x)&0x1)
454127675Sbms
455127675Sbmsstatic struct tok isis_mt_values[] = {
456127675Sbms    { 0,    "IPv4 unicast"},
457127675Sbms    { 1,    "In-Band Management"},
458127675Sbms    { 2,    "IPv6 unicast"},
459127675Sbms    { 3,    "Multicast"},
460127675Sbms    { 4095, "Development, Experimental or Proprietary"},
461127675Sbms    { 0, NULL }
462127675Sbms};
463127675Sbms
464127675Sbmsstatic struct tok isis_iih_circuit_type_values[] = {
465127675Sbms    { 1,    "Level 1 only"},
466127675Sbms    { 2,    "Level 2 only"},
467127675Sbms    { 3,    "Level 1, Level 2"},
468127675Sbms    { 0, NULL}
469127675Sbms};
470127675Sbms
47198527Sfenner#define ISIS_LSP_TYPE_UNUSED0   0
47298527Sfenner#define ISIS_LSP_TYPE_LEVEL_1   1
47398527Sfenner#define ISIS_LSP_TYPE_UNUSED2   2
47498527Sfenner#define ISIS_LSP_TYPE_LEVEL_2   3
47598527Sfenner
47698527Sfennerstatic struct tok isis_lsp_istype_values[] = {
477127675Sbms    { ISIS_LSP_TYPE_UNUSED0,	"Unused 0x0 (invalid)"},
478127675Sbms    { ISIS_LSP_TYPE_LEVEL_1,	"L1 IS"},
479127675Sbms    { ISIS_LSP_TYPE_UNUSED2,	"Unused 0x2 (invalid)"},
480172686Smlaier    { ISIS_LSP_TYPE_LEVEL_2,	"L2 IS"},
481127675Sbms    { 0, NULL }
48298527Sfenner};
48398527Sfenner
48432149Spst/*
48532149Spst * Katz's point to point adjacency TLV uses codes to tell us the state of
48632149Spst * the remote adjacency.  Enumerate them.
48732149Spst */
48832149Spst
48932149Spst#define ISIS_PTP_ADJ_UP   0
49032149Spst#define ISIS_PTP_ADJ_INIT 1
49132149Spst#define ISIS_PTP_ADJ_DOWN 2
49232149Spst
49398527Sfennerstatic struct tok isis_ptp_adjancey_values[] = {
494127675Sbms    { ISIS_PTP_ADJ_UP,    "Up" },
495127675Sbms    { ISIS_PTP_ADJ_INIT,  "Initializing" },
496127675Sbms    { ISIS_PTP_ADJ_DOWN,  "Down" },
497127675Sbms    { 0, NULL}
49832149Spst};
49932149Spst
50098527Sfennerstruct isis_tlv_ptp_adj {
501127675Sbms    u_int8_t adjacency_state;
502127675Sbms    u_int8_t extd_local_circuit_id[4];
503127675Sbms    u_int8_t neighbor_sysid[SYSTEM_ID_LEN];
504127675Sbms    u_int8_t neighbor_extd_local_circuit_id[4];
50532149Spst};
50632149Spst
507127675Sbmsstatic int osi_cksum(const u_int8_t *, u_int);
508146778Ssamstatic int clnp_print(const u_int8_t *, u_int);
509127675Sbmsstatic void esis_print(const u_int8_t *, u_int);
510127675Sbmsstatic int isis_print(const u_int8_t *, u_int);
511127675Sbms
512127675Sbmsstruct isis_metric_block {
513127675Sbms    u_int8_t metric_default;
514127675Sbms    u_int8_t metric_delay;
515127675Sbms    u_int8_t metric_expense;
516127675Sbms    u_int8_t metric_error;
51798527Sfenner};
51898527Sfenner
51998527Sfennerstruct isis_tlv_is_reach {
520127675Sbms    struct isis_metric_block isis_metric_block;
521127675Sbms    u_int8_t neighbor_nodeid[NODE_ID_LEN];
52298527Sfenner};
52398527Sfenner
524127675Sbmsstruct isis_tlv_es_reach {
525127675Sbms    struct isis_metric_block isis_metric_block;
526127675Sbms    u_int8_t neighbor_sysid[SYSTEM_ID_LEN];
527127675Sbms};
52898527Sfenner
529127675Sbmsstruct isis_tlv_ip_reach {
530127675Sbms    struct isis_metric_block isis_metric_block;
531127675Sbms    u_int8_t prefix[4];
532127675Sbms    u_int8_t mask[4];
533127675Sbms};
534127675Sbms
535127675Sbmsstatic struct tok isis_is_reach_virtual_values[] = {
536127675Sbms    { 0,    "IsNotVirtual"},
537127675Sbms    { 1,    "IsVirtual"},
538127675Sbms    { 0, NULL }
539127675Sbms};
540127675Sbms
541127675Sbmsstatic struct tok isis_restart_flag_values[] = {
542127675Sbms    { 0x1,  "Restart Request"},
543127675Sbms    { 0x2,  "Restart Acknowledgement"},
544147904Ssam    { 0x4,  "Suppress adjacency advertisement"},
545127675Sbms    { 0, NULL }
546127675Sbms};
547127675Sbms
54832149Spststruct isis_common_header {
549127675Sbms    u_int8_t nlpid;
550127675Sbms    u_int8_t fixed_len;
551127675Sbms    u_int8_t version;			/* Protocol version */
552127675Sbms    u_int8_t id_length;
553127675Sbms    u_int8_t pdu_type;		        /* 3 MSbits are reserved */
554127675Sbms    u_int8_t pdu_version;		/* Packet format version */
555127675Sbms    u_int8_t reserved;
556127675Sbms    u_int8_t max_area;
55732149Spst};
55832149Spst
55998527Sfennerstruct isis_iih_lan_header {
560127675Sbms    u_int8_t circuit_type;
561127675Sbms    u_int8_t source_id[SYSTEM_ID_LEN];
562127675Sbms    u_int8_t holding_time[2];
563127675Sbms    u_int8_t pdu_len[2];
564127675Sbms    u_int8_t priority;
565127675Sbms    u_int8_t lan_id[NODE_ID_LEN];
56632149Spst};
56798527Sfenner
56898527Sfennerstruct isis_iih_ptp_header {
569127675Sbms    u_int8_t circuit_type;
570127675Sbms    u_int8_t source_id[SYSTEM_ID_LEN];
571127675Sbms    u_int8_t holding_time[2];
572127675Sbms    u_int8_t pdu_len[2];
573127675Sbms    u_int8_t circuit_id;
57432149Spst};
57532149Spst
57698527Sfennerstruct isis_lsp_header {
577127675Sbms    u_int8_t pdu_len[2];
578127675Sbms    u_int8_t remaining_lifetime[2];
579127675Sbms    u_int8_t lsp_id[LSP_ID_LEN];
580127675Sbms    u_int8_t sequence_number[4];
581127675Sbms    u_int8_t checksum[2];
582127675Sbms    u_int8_t typeblock;
58332149Spst};
58432149Spst
58598527Sfennerstruct isis_csnp_header {
586127675Sbms    u_int8_t pdu_len[2];
587127675Sbms    u_int8_t source_id[NODE_ID_LEN];
588127675Sbms    u_int8_t start_lsp_id[LSP_ID_LEN];
589127675Sbms    u_int8_t end_lsp_id[LSP_ID_LEN];
59098527Sfenner};
59132149Spst
59298527Sfennerstruct isis_psnp_header {
593127675Sbms    u_int8_t pdu_len[2];
594127675Sbms    u_int8_t source_id[NODE_ID_LEN];
59598527Sfenner};
59632149Spst
59798527Sfennerstruct isis_tlv_lsp {
598127675Sbms    u_int8_t remaining_lifetime[2];
599127675Sbms    u_int8_t lsp_id[LSP_ID_LEN];
600127675Sbms    u_int8_t sequence_number[4];
601127675Sbms    u_int8_t checksum[2];
60298527Sfenner};
603127675Sbms
60498527Sfenner#define ISIS_COMMON_HEADER_SIZE (sizeof(struct isis_common_header))
60598527Sfenner#define ISIS_IIH_LAN_HEADER_SIZE (sizeof(struct isis_iih_lan_header))
60698527Sfenner#define ISIS_IIH_PTP_HEADER_SIZE (sizeof(struct isis_iih_ptp_header))
60798527Sfenner#define ISIS_LSP_HEADER_SIZE (sizeof(struct isis_lsp_header))
60898527Sfenner#define ISIS_CSNP_HEADER_SIZE (sizeof(struct isis_csnp_header))
60998527Sfenner#define ISIS_PSNP_HEADER_SIZE (sizeof(struct isis_psnp_header))
61032149Spst
611127675Sbmsvoid isoclns_print(const u_int8_t *p, u_int length, u_int caplen)
61217680Spst{
61398527Sfenner	const struct isis_common_header *header;
614127675Sbms
61598527Sfenner	header = (const struct isis_common_header *)p;
61632149Spst
617146778Ssam        if (caplen <= 1) { /* enough bytes on the wire ? */
618146778Ssam            printf("|OSI");
619146778Ssam            return;
620146778Ssam        }
62117680Spst
622146778Ssam        if (eflag)
623146778Ssam            printf("OSI NLPID %s (0x%02x): ",
624146778Ssam                   tok2str(nlpid_values,"Unknown",*p),
625146778Ssam                   *p);
626146778Ssam
62717680Spst	switch (*p) {
62817680Spst
629146778Ssam	case NLPID_CLNP:
630146778Ssam		if (!clnp_print(p, length))
631146778Ssam                        print_unknown_data(p,"\n\t",caplen);
63217680Spst		break;
63317680Spst
63417688Spst	case NLPID_ESIS:
63517680Spst		esis_print(p, length);
63617680Spst		return;
63717680Spst
63817688Spst	case NLPID_ISIS:
63917751Spst		if (!isis_print(p, length))
640127675Sbms                        print_unknown_data(p,"\n\t",caplen);
64117680Spst		break;
64217680Spst
64317688Spst	case NLPID_NULLNS:
644147904Ssam		(void)printf("%slength: %u",
645147904Ssam		             eflag ? "" : ", ",
646147904Ssam                             length);
64717680Spst		break;
64817680Spst
649146778Ssam        case NLPID_Q933:
650146778Ssam                q933_print(p+1, length-1);
651146778Ssam                break;
652146778Ssam
653146778Ssam        case NLPID_IP:
654146778Ssam		ip_print(gndo, p+1, length-1);
655146778Ssam                break;
656146778Ssam
657146778Ssam#ifdef INET6
658146778Ssam        case NLPID_IP6:
659146778Ssam                ip6_print(p+1, length-1);
660146778Ssam                break;
661146778Ssam#endif
662146778Ssam
663146778Ssam        case NLPID_PPP:
664146778Ssam                ppp_print(p+1, length-1);
665146778Ssam                break;
666146778Ssam
66717680Spst	default:
668146778Ssam                if (!eflag)
669146778Ssam                    printf("OSI NLPID 0x%02x unknown",*p);
670147904Ssam		(void)printf("%slength: %u",
671147904Ssam		             eflag ? "" : ", ",
672147904Ssam                             length);
67317680Spst		if (caplen > 1)
674127675Sbms                        print_unknown_data(p,"\n\t",caplen);
67517680Spst		break;
67617680Spst	}
67717680Spst}
67817680Spst
679146778Ssam#define	CLNP_PDU_ER	 1
680146778Ssam#define	CLNP_PDU_DT	28
681146778Ssam#define	CLNP_PDU_MD	29
682146778Ssam#define	CLNP_PDU_ERQ	30
683146778Ssam#define	CLNP_PDU_ERP	31
68417680Spst
685146778Ssamstatic struct tok clnp_pdu_values[] = {
686146778Ssam    { CLNP_PDU_ER,  "Error Report"},
687146778Ssam    { CLNP_PDU_MD,  "MD"},
688146778Ssam    { CLNP_PDU_DT,  "Data"},
689146778Ssam    { CLNP_PDU_ERQ, "Echo Request"},
690146778Ssam    { CLNP_PDU_ERP, "Echo Response"},
691127675Sbms    { 0, NULL }
692127675Sbms};
693127675Sbms
694146778Ssamstruct clnp_header_t {
695146778Ssam    u_int8_t nlpid;
696146778Ssam    u_int8_t length_indicator;
697146778Ssam    u_int8_t version;
698146778Ssam    u_int8_t lifetime; /* units of 500ms */
699146778Ssam    u_int8_t type;
700146778Ssam    u_int8_t segment_length[2];
701146778Ssam    u_int8_t cksum[2];
702146778Ssam};
703146778Ssam
704146778Ssamstruct clnp_segment_header_t {
705146778Ssam    u_int8_t data_unit_id[2];
706146778Ssam    u_int8_t segment_offset[2];
707146778Ssam    u_int8_t total_length[2];
708146778Ssam};
709146778Ssam
710146778Ssam/*
711146778Ssam * clnp_print
712146778Ssam * Decode CLNP packets.  Return 0 on error.
713146778Ssam */
714146778Ssam
715146778Ssamstatic int clnp_print (const u_int8_t *pptr, u_int length)
716146778Ssam{
717146778Ssam	const u_int8_t *optr,*source_address,*dest_address;
718147904Ssam        u_int li,tlen,nsap_offset,source_address_length,dest_address_length, clnp_pdu_type, clnp_flags;
719146778Ssam	const struct clnp_header_t *clnp_header;
720146778Ssam	const struct clnp_segment_header_t *clnp_segment_header;
721146778Ssam        u_int8_t rfd_error_major,rfd_error_minor;
722146778Ssam
723146778Ssam	clnp_header = (const struct clnp_header_t *) pptr;
724146778Ssam        TCHECK(*clnp_header);
725146778Ssam
726146778Ssam        li = clnp_header->length_indicator;
727146778Ssam        optr = pptr;
728146778Ssam
729146778Ssam        if (!eflag)
730146778Ssam            printf("CLNP");
731146778Ssam
732146778Ssam        /*
733146778Ssam         * Sanity checking of the header.
734146778Ssam         */
735146778Ssam
736146778Ssam        if (clnp_header->version != CLNP_VERSION) {
737146778Ssam            printf("version %d packet not supported", clnp_header->version);
738146778Ssam            return (0);
739146778Ssam        }
740146778Ssam
741146778Ssam        /* FIXME further header sanity checking */
742146778Ssam
743146778Ssam        clnp_pdu_type = clnp_header->type & CLNP_PDU_TYPE_MASK;
744146778Ssam        clnp_flags = clnp_header->type & CLNP_FLAG_MASK;
745146778Ssam
746146778Ssam        pptr += sizeof(struct clnp_header_t);
747146778Ssam        li -= sizeof(struct clnp_header_t);
748146778Ssam        dest_address_length = *pptr;
749146778Ssam        dest_address = pptr + 1;
750146778Ssam
751146778Ssam        pptr += (1 + dest_address_length);
752146778Ssam        li -= (1 + dest_address_length);
753146778Ssam        source_address_length = *pptr;
754146778Ssam        source_address = pptr +1;
755146778Ssam
756146778Ssam        pptr += (1 + source_address_length);
757146778Ssam        li -= (1 + source_address_length);
758146778Ssam
759146778Ssam        if (vflag < 1) {
760146778Ssam            printf("%s%s > %s, %s, length %u",
761146778Ssam                   eflag ? "" : ", ",
762146778Ssam                   isonsap_string(source_address, source_address_length),
763146778Ssam                   isonsap_string(dest_address, dest_address_length),
764146778Ssam                   tok2str(clnp_pdu_values,"unknown (%u)",clnp_pdu_type),
765146778Ssam                   length);
766146778Ssam            return (1);
767146778Ssam        }
768146778Ssam        printf("%slength %u",eflag ? "" : ", ",length);
769146778Ssam
770146778Ssam        printf("\n\t%s PDU, hlen: %u, v: %u, lifetime: %u.%us, Segment PDU length: %u, checksum: 0x%04x ",
771146778Ssam               tok2str(clnp_pdu_values, "unknown (%u)",clnp_pdu_type),
772146778Ssam               clnp_header->length_indicator,
773146778Ssam               clnp_header->version,
774146778Ssam               clnp_header->lifetime/2,
775146778Ssam               (clnp_header->lifetime%2)*5,
776146778Ssam               EXTRACT_16BITS(clnp_header->segment_length),
777146778Ssam               EXTRACT_16BITS(clnp_header->cksum));
778146778Ssam
779146778Ssam        /* do not attempt to verify the checksum if it is zero */
780146778Ssam        if (EXTRACT_16BITS(clnp_header->cksum) == 0)
781146778Ssam                printf("(unverified)");
782146778Ssam            else printf("(%s)", osi_cksum(optr, clnp_header->length_indicator) ? "incorrect" : "correct");
783146778Ssam
784146778Ssam        printf("\n\tFlags [%s]",
785146778Ssam               bittok2str(clnp_flag_values,"none",clnp_flags));
786146778Ssam
787146778Ssam        printf("\n\tsource address (length %u): %s\n\tdest   address (length %u): %s",
788146778Ssam               source_address_length,
789146778Ssam               isonsap_string(source_address, source_address_length),
790146778Ssam               dest_address_length,
791146778Ssam               isonsap_string(dest_address,dest_address_length));
792146778Ssam
793146778Ssam        if (clnp_flags & CLNP_SEGMENT_PART) {
794146778Ssam            	clnp_segment_header = (const struct clnp_segment_header_t *) pptr;
795162021Ssam                TCHECK(*clnp_segment_header);
796146778Ssam                printf("\n\tData Unit ID: 0x%04x, Segment Offset: %u, Total PDU Length: %u",
797146778Ssam                       EXTRACT_16BITS(clnp_segment_header->data_unit_id),
798146778Ssam                       EXTRACT_16BITS(clnp_segment_header->segment_offset),
799146778Ssam                       EXTRACT_16BITS(clnp_segment_header->total_length));
800146778Ssam                pptr+=sizeof(const struct clnp_segment_header_t);
801146778Ssam                li-=sizeof(const struct clnp_segment_header_t);
802146778Ssam        }
803146778Ssam
804146778Ssam        /* now walk the options */
805146778Ssam        while (li >= 2) {
806146778Ssam            u_int op, opli;
807146778Ssam            const u_int8_t *tptr;
808146778Ssam
809147904Ssam            TCHECK2(*pptr, 2);
810146778Ssam            if (li < 2) {
811146778Ssam                printf(", bad opts/li");
812146778Ssam                return (0);
813146778Ssam            }
814146778Ssam            op = *pptr++;
815146778Ssam            opli = *pptr++;
816146778Ssam            li -= 2;
817147904Ssam            TCHECK2(*pptr, opli);
818146778Ssam            if (opli > li) {
819146778Ssam                printf(", opt (%d) too long", op);
820146778Ssam                return (0);
821146778Ssam            }
822146778Ssam            li -= opli;
823146778Ssam            tptr = pptr;
824147904Ssam            tlen = opli;
825146778Ssam
826146778Ssam            printf("\n\t  %s Option #%u, length %u, value: ",
827146778Ssam                   tok2str(clnp_option_values,"Unknown",op),
828146778Ssam                   op,
829146778Ssam                   opli);
830146778Ssam
831146778Ssam            switch (op) {
832146778Ssam
833147904Ssam
834147904Ssam            case CLNP_OPTION_ROUTE_RECORDING: /* those two options share the format */
835147904Ssam            case CLNP_OPTION_SOURCE_ROUTING:
836147904Ssam                    printf("%s %s",
837147904Ssam                           tok2str(clnp_option_sr_rr_values,"Unknown",*tptr),
838147904Ssam                           tok2str(clnp_option_sr_rr_string_values,"Unknown Option %u",op));
839147904Ssam                    nsap_offset=*(tptr+1);
840147904Ssam                    if (nsap_offset == 0) {
841147904Ssam                            printf(" Bad NSAP offset (0)");
842147904Ssam                            break;
843147904Ssam                    }
844147904Ssam                    nsap_offset-=1; /* offset to nsap list */
845147904Ssam                    if (nsap_offset > tlen) {
846147904Ssam                            printf(" Bad NSAP offset (past end of option)");
847147904Ssam                            break;
848147904Ssam                    }
849147904Ssam                    tptr+=nsap_offset;
850147904Ssam                    tlen-=nsap_offset;
851147904Ssam                    while (tlen > 0) {
852147904Ssam                            source_address_length=*tptr;
853147904Ssam                            if (tlen < source_address_length+1) {
854147904Ssam                                    printf("\n\t    NSAP address goes past end of option");
855147904Ssam                                    break;
856162021Ssam                            }
857147904Ssam                            if (source_address_length > 0) {
858147904Ssam                                    source_address=(tptr+1);
859147904Ssam                                    TCHECK2(*source_address, source_address_length);
860147904Ssam                                    printf("\n\t    NSAP address (length %u): %s",
861147904Ssam                                           source_address_length,
862147904Ssam                                           isonsap_string(source_address, source_address_length));
863147904Ssam                            }
864147904Ssam                            tlen-=source_address_length+1;
865147904Ssam                    }
866147904Ssam                    break;
867147904Ssam
868146778Ssam            case CLNP_OPTION_PRIORITY:
869147904Ssam                    printf("0x%1x", *tptr&0x0f);
870147904Ssam                    break;
871146778Ssam
872147904Ssam            case CLNP_OPTION_QOS_MAINTENANCE:
873147904Ssam                    printf("\n\t    Format Code: %s",
874147904Ssam                           tok2str(clnp_option_scope_values,"Reserved",*tptr&CLNP_OPTION_SCOPE_MASK));
875147904Ssam
876147904Ssam                    if ((*tptr&CLNP_OPTION_SCOPE_MASK) == CLNP_OPTION_SCOPE_GLOBAL)
877147904Ssam                            printf("\n\t    QoS Flags [%s]",
878147904Ssam                                   bittok2str(clnp_option_qos_global_values,
879147904Ssam                                              "none",
880147904Ssam                                              *tptr&CLNP_OPTION_OPTION_QOS_MASK));
881147904Ssam                    break;
882147904Ssam
883147904Ssam            case CLNP_OPTION_SECURITY:
884147904Ssam                    printf("\n\t    Format Code: %s, Security-Level %u",
885147904Ssam                           tok2str(clnp_option_scope_values,"Reserved",*tptr&CLNP_OPTION_SCOPE_MASK),
886147904Ssam                           *(tptr+1));
887147904Ssam                    break;
888147904Ssam
889146778Ssam            case CLNP_OPTION_DISCARD_REASON:
890146778Ssam                rfd_error_major = (*tptr&0xf0) >> 4;
891146778Ssam                rfd_error_minor = *tptr&0x0f;
892146778Ssam                printf("\n\t    Class: %s Error (0x%01x), %s (0x%01x)",
893146778Ssam                       tok2str(clnp_option_rfd_class_values,"Unknown",rfd_error_major),
894146778Ssam                       rfd_error_major,
895146778Ssam                       tok2str(clnp_option_rfd_error_class[rfd_error_major],"Unknown",rfd_error_minor),
896146778Ssam                       rfd_error_minor);
897146778Ssam                break;
898146778Ssam
899147904Ssam            case CLNP_OPTION_PADDING:
900147904Ssam                    printf("padding data");
901147904Ssam                break;
902147904Ssam
903146778Ssam                /*
904146778Ssam                 * FIXME those are the defined Options that lack a decoder
905146778Ssam                 * you are welcome to contribute code ;-)
906146778Ssam                 */
907146778Ssam
908146778Ssam            default:
909146778Ssam                print_unknown_data(tptr,"\n\t  ",opli);
910146778Ssam                break;
911146778Ssam            }
912146778Ssam            if (vflag > 1)
913146778Ssam                print_unknown_data(pptr,"\n\t  ",opli);
914146778Ssam            pptr += opli;
915146778Ssam        }
916146778Ssam
917146778Ssam        switch (clnp_pdu_type) {
918146778Ssam
919146778Ssam        case    CLNP_PDU_ER: /* fall through */
920146778Ssam        case 	CLNP_PDU_ERP:
921147904Ssam            TCHECK(*pptr);
922146778Ssam            if (*(pptr) == NLPID_CLNP) {
923146778Ssam                printf("\n\t-----original packet-----\n\t");
924146778Ssam                /* FIXME recursion protection */
925146778Ssam                clnp_print(pptr, length-clnp_header->length_indicator);
926146778Ssam                break;
927146778Ssam            }
928146778Ssam
929146778Ssam        case 	CLNP_PDU_DT:
930146778Ssam        case 	CLNP_PDU_MD:
931146778Ssam        case 	CLNP_PDU_ERQ:
932146778Ssam
933146778Ssam        default:
934146778Ssam            /* dump the PDU specific data */
935146778Ssam            if (length-(pptr-optr) > 0) {
936146778Ssam                printf("\n\t  undecoded non-header data, length %u",length-clnp_header->length_indicator);
937146778Ssam                print_unknown_data(pptr,"\n\t  ",length-(pptr-optr));
938146778Ssam            }
939146778Ssam        }
940146778Ssam
941146778Ssam        return (1);
942146778Ssam
943146778Ssam trunc:
944146778Ssam    fputs("[|clnp]", stdout);
945146778Ssam    return (1);
946146778Ssam
947146778Ssam}
948146778Ssam
949146778Ssam
950146778Ssam#define	ESIS_PDU_REDIRECT	6
951146778Ssam#define	ESIS_PDU_ESH	        2
952146778Ssam#define	ESIS_PDU_ISH	        4
953146778Ssam
954146778Ssamstatic struct tok esis_pdu_values[] = {
955146778Ssam    { ESIS_PDU_REDIRECT, "redirect"},
956146778Ssam    { ESIS_PDU_ESH,      "ESH"},
957146778Ssam    { ESIS_PDU_ISH,      "ISH"},
958146778Ssam    { 0, NULL }
959146778Ssam};
960146778Ssam
961146778Ssamstruct esis_header_t {
962146778Ssam	u_int8_t nlpid;
963146778Ssam	u_int8_t length_indicator;
964127675Sbms	u_int8_t version;
965127675Sbms	u_int8_t reserved;
966127675Sbms	u_int8_t type;
967146778Ssam	u_int8_t holdtime[2];
968127675Sbms	u_int8_t cksum[2];
96917680Spst};
97017680Spst
97117680Spststatic void
972146778Ssamesis_print(const u_int8_t *pptr, u_int length)
97317680Spst{
974146778Ssam	const u_int8_t *optr;
975146778Ssam	u_int li,esis_pdu_type,source_address_length, source_address_number;
976146778Ssam	const struct esis_header_t *esis_header;
97717680Spst
978146778Ssam        if (!eflag)
979146778Ssam            printf("ES-IS");
980146778Ssam
98198527Sfenner	if (length <= 2) {
98217680Spst		if (qflag)
983146778Ssam			printf("bad pkt!");
98417680Spst		else
985146778Ssam			printf("no header at all!");
98617680Spst		return;
98717680Spst	}
988146778Ssam
989146778Ssam	esis_header = (const struct esis_header_t *) pptr;
990147904Ssam        TCHECK(*esis_header);
991146778Ssam        li = esis_header->length_indicator;
992146778Ssam        optr = pptr;
993146778Ssam
994146778Ssam        /*
995146778Ssam         * Sanity checking of the header.
996146778Ssam         */
997146778Ssam
998146778Ssam        if (esis_header->nlpid != NLPID_ESIS) {
999146778Ssam            printf(" nlpid 0x%02x packet not supported", esis_header->nlpid);
1000146778Ssam            return;
1001146778Ssam        }
1002146778Ssam
1003146778Ssam        if (esis_header->version != ESIS_VERSION) {
1004146778Ssam            printf(" version %d packet not supported", esis_header->version);
1005146778Ssam            return;
1006146778Ssam        }
1007146778Ssam
100817680Spst	if (li > length) {
1009146778Ssam            printf(" length indicator(%d) > PDU size (%d)!", li, length);
1010146778Ssam            return;
101117680Spst	}
1012146778Ssam
1013146778Ssam	if (li < sizeof(struct esis_header_t) + 2) {
1014146778Ssam            printf(" length indicator < min PDU size %d:", li);
1015146778Ssam            while (--length != 0)
1016146778Ssam                printf("%02X", *pptr++);
1017146778Ssam            return;
101817680Spst	}
101917680Spst
1020146778Ssam        esis_pdu_type = esis_header->type & ESIS_PDU_TYPE_MASK;
102117680Spst
1022146778Ssam        if (vflag < 1) {
1023146778Ssam            printf("%s%s, length %u",
1024146778Ssam                   eflag ? "" : ", ",
1025146778Ssam                   tok2str(esis_pdu_values,"unknown type (%u)",esis_pdu_type),
1026146778Ssam                   length);
1027146778Ssam            return;
1028146778Ssam        } else
1029146778Ssam            printf("%slength %u\n\t%s (%u)",
1030146778Ssam                   eflag ? "" : ", ",
1031146778Ssam                   length,
1032146778Ssam                   tok2str(esis_pdu_values,"unknown type: %u", esis_pdu_type),
1033146778Ssam                   esis_pdu_type);
103417680Spst
1035146778Ssam        printf(", v: %u%s", esis_header->version, esis_header->version == ESIS_VERSION ? "" : "unsupported" );
1036146778Ssam        printf(", checksum: 0x%04x ", EXTRACT_16BITS(esis_header->cksum));
1037146778Ssam        /* do not attempt to verify the checksum if it is zero */
1038146778Ssam        if (EXTRACT_16BITS(esis_header->cksum) == 0)
1039146778Ssam                printf("(unverified)");
1040147904Ssam        else
1041147904Ssam                printf("(%s)", osi_cksum(pptr, li) ? "incorrect" : "correct");
104217680Spst
1043146778Ssam        printf(", holding time: %us, length indicator: %u",EXTRACT_16BITS(esis_header->holdtime),li);
104417680Spst
1045146778Ssam        if (vflag > 1)
1046146778Ssam            print_unknown_data(optr,"\n\t",sizeof(struct esis_header_t));
1047146778Ssam
1048146778Ssam	pptr += sizeof(struct esis_header_t);
1049146778Ssam	li -= sizeof(struct esis_header_t);
1050146778Ssam
1051146778Ssam	switch (esis_pdu_type) {
1052146778Ssam	case ESIS_PDU_REDIRECT: {
1053147904Ssam		const u_int8_t *dst, *snpa, *neta;
1054147904Ssam		u_int dstl, snpal, netal;
1055146778Ssam
1056147904Ssam		TCHECK(*pptr);
1057147904Ssam		if (li < 1) {
1058147904Ssam			printf(", bad redirect/li");
105917680Spst			return;
1060147904Ssam		}
1061147904Ssam		dstl = *pptr;
1062147904Ssam		pptr++;
1063147904Ssam		li--;
1064147904Ssam		TCHECK2(*pptr, dstl);
1065147904Ssam		if (li < dstl) {
1066147904Ssam			printf(", bad redirect/li");
106717680Spst			return;
1068147904Ssam		}
1069147904Ssam		dst = pptr;
1070147904Ssam		pptr += dstl;
1071147904Ssam                li -= dstl;
1072147904Ssam		printf("\n\t  %s", isonsap_string(dst,dstl));
1073146778Ssam
1074147904Ssam		TCHECK(*pptr);
1075147904Ssam		if (li < 1) {
1076147904Ssam			printf(", bad redirect/li");
1077147904Ssam			return;
1078147904Ssam		}
1079147904Ssam		snpal = *pptr;
1080147904Ssam		pptr++;
1081147904Ssam		li--;
1082147904Ssam		TCHECK2(*pptr, snpal);
1083147904Ssam		if (li < snpal) {
1084147904Ssam			printf(", bad redirect/li");
1085147904Ssam			return;
1086147904Ssam		}
1087147904Ssam		snpa = pptr;
1088147904Ssam		pptr += snpal;
1089147904Ssam                li -= snpal;
1090147904Ssam		TCHECK(*pptr);
1091147904Ssam		if (li < 1) {
1092147904Ssam			printf(", bad redirect/li");
1093147904Ssam			return;
1094147904Ssam		}
1095147904Ssam		netal = *pptr;
1096147904Ssam		pptr++;
1097147904Ssam		TCHECK2(*pptr, netal);
1098147904Ssam		if (li < netal) {
1099147904Ssam			printf(", bad redirect/li");
1100147904Ssam			return;
1101147904Ssam		}
1102147904Ssam		neta = pptr;
1103147904Ssam		pptr += netal;
1104147904Ssam                li -= netal;
1105147904Ssam
1106147904Ssam		if (netal == 0)
1107147904Ssam			printf("\n\t  %s", etheraddr_string(snpa));
110817680Spst		else
1109147904Ssam			printf("\n\t  %s", isonsap_string(neta,netal));
111017680Spst		break;
111117680Spst	}
1112127675Sbms
1113146778Ssam	case ESIS_PDU_ESH:
1114147904Ssam            TCHECK(*pptr);
1115147904Ssam            if (li < 1) {
1116147904Ssam                printf(", bad esh/li");
1117147904Ssam                return;
1118147904Ssam            }
1119146778Ssam            source_address_number = *pptr;
1120146778Ssam            pptr++;
1121146778Ssam            li--;
1122127675Sbms
1123146778Ssam            printf("\n\t  Number of Source Addresses: %u", source_address_number);
1124146778Ssam
1125146778Ssam            while (source_address_number > 0) {
1126147904Ssam                TCHECK(*pptr);
1127147904Ssam            	if (li < 1) {
1128147904Ssam                    printf(", bad esh/li");
1129147904Ssam            	    return;
1130147904Ssam            	}
1131146778Ssam                source_address_length = *pptr;
1132147904Ssam                pptr++;
1133147904Ssam            	li--;
1134147904Ssam
1135147904Ssam                TCHECK2(*pptr, source_address_length);
1136147904Ssam            	if (li < source_address_length) {
1137147904Ssam                    printf(", bad esh/li");
1138147904Ssam            	    return;
1139147904Ssam            	}
1140146778Ssam                printf("\n\t  NET (length: %u): %s",
1141146778Ssam                       source_address_length,
1142147904Ssam                       isonsap_string(pptr,source_address_length));
1143147904Ssam                pptr += source_address_length;
1144147904Ssam                li -= source_address_length;
1145146778Ssam                source_address_number--;
1146146778Ssam            }
1147146778Ssam
1148146778Ssam            break;
1149146778Ssam
1150146778Ssam	case ESIS_PDU_ISH: {
1151147904Ssam            TCHECK(*pptr);
1152147904Ssam            if (li < 1) {
1153147904Ssam                printf(", bad ish/li");
1154147904Ssam                return;
1155147904Ssam            }
1156146778Ssam            source_address_length = *pptr;
1157147904Ssam            pptr++;
1158147904Ssam            li--;
1159147904Ssam            TCHECK2(*pptr, source_address_length);
1160147904Ssam            if (li < source_address_length) {
1161147904Ssam                printf(", bad ish/li");
1162147904Ssam                return;
1163147904Ssam            }
1164147904Ssam            printf("\n\t  NET (length: %u): %s", source_address_length, isonsap_string(pptr, source_address_length));
1165147904Ssam            pptr += source_address_length;
1166147904Ssam            li -= source_address_length;
1167146778Ssam            break;
116817680Spst	}
116917680Spst
117017680Spst	default:
1171127675Sbms            if (vflag <= 1) {
1172146778Ssam		    if (pptr < snapend)
1173146778Ssam                            print_unknown_data(pptr,"\n\t  ",snapend-pptr);
1174127675Sbms            }
1175127675Sbms            return;
117617680Spst	}
1177127675Sbms
1178146778Ssam        /* now walk the options */
1179146778Ssam        while (li >= 2) {
1180146778Ssam            u_int op, opli;
1181146778Ssam            const u_int8_t *tptr;
1182146778Ssam
1183147904Ssam            TCHECK2(*pptr, 2);
1184146778Ssam            if (li < 2) {
1185146778Ssam                printf(", bad opts/li");
1186146778Ssam                return;
1187146778Ssam            }
1188146778Ssam            op = *pptr++;
1189146778Ssam            opli = *pptr++;
1190146778Ssam            li -= 2;
1191146778Ssam            if (opli > li) {
1192146778Ssam                printf(", opt (%d) too long", op);
1193146778Ssam                return;
1194146778Ssam            }
1195146778Ssam            li -= opli;
1196146778Ssam            tptr = pptr;
1197146778Ssam
1198146778Ssam            printf("\n\t  %s Option #%u, length %u, value: ",
1199146778Ssam                   tok2str(esis_option_values,"Unknown",op),
1200146778Ssam                   op,
1201146778Ssam                   opli);
120217680Spst
1203146778Ssam            switch (op) {
1204127675Sbms
1205146778Ssam            case ESIS_OPTION_ES_CONF_TIME:
1206147904Ssam                TCHECK2(*pptr, 2);
1207146778Ssam                printf("%us", EXTRACT_16BITS(tptr));
1208146778Ssam                break;
1209127675Sbms
1210146778Ssam            case ESIS_OPTION_PROTOCOLS:
1211146778Ssam                while (opli>0) {
1212147904Ssam                    TCHECK(*pptr);
1213146778Ssam                    printf("%s (0x%02x)",
1214146778Ssam                           tok2str(nlpid_values,
1215146778Ssam                                   "unknown",
1216146778Ssam                                   *tptr),
1217146778Ssam                           *tptr);
1218146778Ssam                    if (opli>1) /* further NPLIDs ? - put comma */
1219146778Ssam                        printf(", ");
1220146778Ssam                    tptr++;
1221146778Ssam                    opli--;
1222146778Ssam                }
1223146778Ssam                break;
1224127675Sbms
1225146778Ssam                /*
1226146778Ssam                 * FIXME those are the defined Options that lack a decoder
1227146778Ssam                 * you are welcome to contribute code ;-)
1228146778Ssam                 */
1229127675Sbms
1230146778Ssam            case ESIS_OPTION_QOS_MAINTENANCE:
1231146778Ssam            case ESIS_OPTION_SECURITY:
1232146778Ssam            case ESIS_OPTION_PRIORITY:
1233146778Ssam            case ESIS_OPTION_ADDRESS_MASK:
1234146778Ssam            case ESIS_OPTION_SNPA_MASK:
123517680Spst
1236146778Ssam            default:
1237146778Ssam                print_unknown_data(tptr,"\n\t  ",opli);
1238146778Ssam                break;
1239146778Ssam            }
1240146778Ssam            if (vflag > 1)
1241146778Ssam                print_unknown_data(pptr,"\n\t  ",opli);
1242146778Ssam            pptr += opli;
1243146778Ssam        }
1244147904Ssamtrunc:
1245147904Ssam	return;
1246146778Ssam}
1247146778Ssam
1248127675Sbms/* shared routine for printing system, node and lsp-ids */
1249127675Sbmsstatic char *
1250127675Sbmsisis_print_id(const u_int8_t *cp, int id_len)
125198527Sfenner{
1252127675Sbms    int i;
1253127675Sbms    static char id[sizeof("xxxx.xxxx.xxxx.yy-zz")];
1254127675Sbms    char *pos = id;
125517688Spst
1256127675Sbms    for (i = 1; i <= SYSTEM_ID_LEN; i++) {
1257127675Sbms        snprintf(pos, sizeof(id) - (pos - id), "%02x", *cp++);
1258127675Sbms	pos += strlen(pos);
1259127675Sbms	if (i == 2 || i == 4)
1260127675Sbms	    *pos++ = '.';
126198527Sfenner	}
1262127675Sbms    if (id_len >= NODE_ID_LEN) {
1263127675Sbms        snprintf(pos, sizeof(id) - (pos - id), ".%02x", *cp++);
1264127675Sbms	pos += strlen(pos);
1265127675Sbms    }
1266127675Sbms    if (id_len == LSP_ID_LEN)
1267127675Sbms        snprintf(pos, sizeof(id) - (pos - id), "-%02x", *cp);
1268127675Sbms    return (id);
126998527Sfenner}
127098527Sfenner
1271127675Sbms/* print the 4-byte metric block which is common found in the old-style TLVs */
127298527Sfennerstatic int
1273127675Sbmsisis_print_metric_block (const struct isis_metric_block *isis_metric_block)
127498527Sfenner{
1275127675Sbms    printf(", Default Metric: %d, %s",
1276127675Sbms           ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_default),
1277127675Sbms           ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_default) ? "External" : "Internal");
1278127675Sbms    if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_delay))
1279127675Sbms        printf("\n\t\t  Delay Metric: %d, %s",
1280127675Sbms               ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_delay),
1281127675Sbms               ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_delay) ? "External" : "Internal");
1282127675Sbms    if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_expense))
1283127675Sbms        printf("\n\t\t  Expense Metric: %d, %s",
1284127675Sbms               ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_expense),
1285127675Sbms               ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_expense) ? "External" : "Internal");
1286127675Sbms    if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_error))
1287127675Sbms        printf("\n\t\t  Error Metric: %d, %s",
1288127675Sbms               ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_error),
1289127675Sbms               ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_error) ? "External" : "Internal");
129098527Sfenner
1291127675Sbms    return(1); /* everything is ok */
129298527Sfenner}
129398527Sfenner
129498527Sfennerstatic int
1295127675Sbmsisis_print_tlv_ip_reach (const u_int8_t *cp, const char *ident, int length)
129698527Sfenner{
1297127675Sbms	int prefix_len;
1298127675Sbms	const struct isis_tlv_ip_reach *tlv_ip_reach;
129998527Sfenner
1300127675Sbms	tlv_ip_reach = (const struct isis_tlv_ip_reach *)cp;
1301127675Sbms
1302127675Sbms	while (length > 0) {
1303127675Sbms		if ((size_t)length < sizeof(*tlv_ip_reach)) {
1304127675Sbms			printf("short IPv4 Reachability (%d vs %lu)",
1305127675Sbms                               length,
1306127675Sbms                               (unsigned long)sizeof(*tlv_ip_reach));
130798527Sfenner			return (0);
130898527Sfenner		}
1309127675Sbms
1310127675Sbms		if (!TTEST(*tlv_ip_reach))
1311127675Sbms		    return (0);
1312127675Sbms
1313127675Sbms		prefix_len = mask2plen(EXTRACT_32BITS(tlv_ip_reach->mask));
1314127675Sbms
1315127675Sbms		if (prefix_len == -1)
1316127675Sbms			printf("%sIPv4 prefix: %s mask %s",
1317127675Sbms                               ident,
1318127675Sbms			       ipaddr_string((tlv_ip_reach->prefix)),
1319127675Sbms			       ipaddr_string((tlv_ip_reach->mask)));
1320127675Sbms		else
1321127675Sbms			printf("%sIPv4 prefix: %15s/%u",
1322127675Sbms                               ident,
1323127675Sbms			       ipaddr_string((tlv_ip_reach->prefix)),
1324127675Sbms			       prefix_len);
1325127675Sbms
1326127675Sbms		printf(", Distribution: %s, Metric: %u, %s",
1327127675Sbms                       ISIS_LSP_TLV_METRIC_UPDOWN(tlv_ip_reach->isis_metric_block.metric_default) ? "down" : "up",
1328127675Sbms                       ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_default),
1329127675Sbms                       ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_default) ? "External" : "Internal");
1330127675Sbms
1331127675Sbms		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_delay))
1332127675Sbms                    printf("%s  Delay Metric: %u, %s",
1333127675Sbms                           ident,
1334127675Sbms                           ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_delay),
1335127675Sbms                           ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_delay) ? "External" : "Internal");
1336127675Sbms
1337127675Sbms		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_expense))
1338127675Sbms                    printf("%s  Expense Metric: %u, %s",
1339127675Sbms                           ident,
1340127675Sbms                           ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_expense),
1341127675Sbms                           ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_expense) ? "External" : "Internal");
1342127675Sbms
1343127675Sbms		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_error))
1344127675Sbms                    printf("%s  Error Metric: %u, %s",
1345127675Sbms                           ident,
1346127675Sbms                           ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_error),
1347127675Sbms                           ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_error) ? "External" : "Internal");
1348127675Sbms
1349127675Sbms		length -= sizeof(struct isis_tlv_ip_reach);
1350127675Sbms		tlv_ip_reach++;
135198527Sfenner	}
135298527Sfenner	return (1);
135398527Sfenner}
135498527Sfenner
1355127675Sbms/*
1356127675Sbms * this is the common IP-REACH subTLV decoder it is called
1357127675Sbms * from various EXTD-IP REACH TLVs (135,235,236,237)
1358127675Sbms */
135998527Sfenner
1360127675Sbmsstatic int
1361127675Sbmsisis_print_ip_reach_subtlv (const u_int8_t *tptr,int subt,int subl,const char *ident) {
1362127675Sbms
1363127675Sbms        /* first lets see if we know the subTLVs name*/
1364127675Sbms	printf("%s%s subTLV #%u, length: %u",
1365127675Sbms	       ident,
1366127675Sbms               tok2str(isis_ext_ip_reach_subtlv_values,
1367127675Sbms                       "unknown",
1368127675Sbms                       subt),
1369127675Sbms               subt,
1370127675Sbms               subl);
1371127675Sbms
1372127675Sbms	if (!TTEST2(*tptr,subl))
1373127675Sbms	    goto trunctlv;
1374127675Sbms
1375127675Sbms    switch(subt) {
1376146778Ssam    case ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR: /* fall through */
1377146778Ssam    case ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32:
1378127675Sbms        while (subl >= 4) {
1379127675Sbms	    printf(", 0x%08x (=%u)",
1380127675Sbms		   EXTRACT_32BITS(tptr),
1381127675Sbms		   EXTRACT_32BITS(tptr));
1382127675Sbms	    tptr+=4;
1383127675Sbms	    subl-=4;
138417688Spst	}
1385127675Sbms	break;
1386146778Ssam    case ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64:
1387127675Sbms        while (subl >= 8) {
1388127675Sbms	    printf(", 0x%08x%08x",
1389127675Sbms		   EXTRACT_32BITS(tptr),
1390127675Sbms		   EXTRACT_32BITS(tptr+4));
1391127675Sbms	    tptr+=8;
1392127675Sbms	    subl-=8;
1393127675Sbms	}
1394127675Sbms	break;
1395127675Sbms    default:
1396127675Sbms	if(!print_unknown_data(tptr,"\n\t\t    ",
1397127675Sbms			       subl))
1398127675Sbms	  return(0);
1399127675Sbms	break;
1400127675Sbms    }
1401127675Sbms    return(1);
1402127675Sbms
1403127675Sbmstrunctlv:
1404127675Sbms    printf("%spacket exceeded snapshot",ident);
1405127675Sbms    return(0);
140698527Sfenner}
140717688Spst
1408127675Sbms/*
1409127675Sbms * this is the common IS-REACH subTLV decoder it is called
1410127675Sbms * from isis_print_ext_is_reach()
1411127675Sbms */
1412127675Sbms
141398527Sfennerstatic int
1414162021Ssamisis_print_is_reach_subtlv (const u_int8_t *tptr,u_int subt,u_int subl,const char *ident) {
141598527Sfenner
1416162021Ssam        u_int te_class,priority_level;
1417127675Sbms        union { /* int to float conversion buffer for several subTLVs */
1418127675Sbms            float f;
1419127675Sbms            u_int32_t i;
1420127675Sbms        } bw;
142198527Sfenner
1422127675Sbms        /* first lets see if we know the subTLVs name*/
1423127675Sbms	printf("%s%s subTLV #%u, length: %u",
1424127675Sbms	       ident,
1425127675Sbms               tok2str(isis_ext_is_reach_subtlv_values,
1426127675Sbms                       "unknown",
1427127675Sbms                       subt),
1428127675Sbms               subt,
1429127675Sbms               subl);
143098527Sfenner
1431127675Sbms	if (!TTEST2(*tptr,subl))
1432127675Sbms	    goto trunctlv;
143398527Sfenner
1434127675Sbms        switch(subt) {
1435146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP:
1436146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID:
1437146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID:
1438127675Sbms	    if (subl >= 4) {
1439127675Sbms	      printf(", 0x%08x", EXTRACT_32BITS(tptr));
1440127675Sbms	      if (subl == 8) /* draft-ietf-isis-gmpls-extensions */
1441127675Sbms	        printf(", 0x%08x", EXTRACT_32BITS(tptr+4));
1442127675Sbms	    }
1443127675Sbms	    break;
1444146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR:
1445146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR:
1446162021Ssam            if (subl >= sizeof(struct in_addr))
1447127675Sbms              printf(", %s", ipaddr_string(tptr));
1448127675Sbms            break;
1449146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW :
1450146778Ssam	case ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW:
1451127675Sbms            if (subl >= 4) {
1452127675Sbms              bw.i = EXTRACT_32BITS(tptr);
1453127675Sbms              printf(", %.3f Mbps", bw.f*8/1000000 );
1454127675Sbms            }
1455127675Sbms            break;
1456146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW :
1457127675Sbms            if (subl >= 32) {
1458162021Ssam              for (te_class = 0; te_class < 8; te_class++) {
1459127675Sbms                bw.i = EXTRACT_32BITS(tptr);
1460162021Ssam                printf("%s  TE-Class %u: %.3f Mbps",
1461127675Sbms                       ident,
1462162021Ssam                       te_class,
1463127675Sbms                       bw.f*8/1000000 );
1464127675Sbms		tptr+=4;
1465127675Sbms	      }
1466127675Sbms            }
1467127675Sbms            break;
1468162021Ssam        case ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS: /* fall through */
1469162021Ssam        case ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS_OLD:
1470146778Ssam            printf("%sBandwidth Constraints Model ID: %s (%u)",
1471146778Ssam                   ident,
1472146778Ssam                   tok2str(diffserv_te_bc_values, "unknown", *tptr),
1473146778Ssam                   *tptr);
1474146778Ssam            tptr++;
1475146778Ssam            /* decode BCs until the subTLV ends */
1476162021Ssam            for (te_class = 0; te_class < (subl-1)/4; te_class++) {
1477146778Ssam                bw.i = EXTRACT_32BITS(tptr);
1478162021Ssam                printf("%s  Bandwidth constraint CT%u: %.3f Mbps",
1479146778Ssam                       ident,
1480162021Ssam                       te_class,
1481146778Ssam                       bw.f*8/1000000 );
1482146778Ssam		tptr+=4;
1483146778Ssam            }
1484146778Ssam            break;
1485146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC:
1486127675Sbms            if (subl >= 3)
1487127675Sbms              printf(", %u", EXTRACT_24BITS(tptr));
1488127675Sbms            break;
1489146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE:
1490127675Sbms            if (subl >= 2) {
1491127675Sbms              printf(", %s, Priority %u",
1492127675Sbms		   bittok2str(gmpls_link_prot_values, "none", *tptr),
1493127675Sbms                   *(tptr+1));
1494127675Sbms            }
1495127675Sbms            break;
1496146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR:
1497127675Sbms            if (subl >= 36) {
1498127675Sbms              printf("%s  Interface Switching Capability:%s",
1499127675Sbms                   ident,
1500127675Sbms                   tok2str(gmpls_switch_cap_values, "Unknown", *(tptr)));
1501127675Sbms              printf(", LSP Encoding: %s",
1502127675Sbms                   tok2str(gmpls_encoding_values, "Unknown", *(tptr+1)));
1503127675Sbms	      tptr+=4;
1504127675Sbms              printf("%s  Max LSP Bandwidth:",ident);
1505127675Sbms              for (priority_level = 0; priority_level < 8; priority_level++) {
1506127675Sbms                bw.i = EXTRACT_32BITS(tptr);
1507127675Sbms                printf("%s    priority level %d: %.3f Mbps",
1508127675Sbms                       ident,
1509127675Sbms                       priority_level,
1510127675Sbms                       bw.f*8/1000000 );
1511127675Sbms		tptr+=4;
1512127675Sbms              }
1513127675Sbms              subl-=36;
1514127675Sbms              /* there is some optional stuff left to decode but this is as of yet
1515127675Sbms                 not specified so just lets hexdump what is left */
1516127675Sbms              if(subl>0){
1517127675Sbms                if(!print_unknown_data(tptr,"\n\t\t    ",
1518147904Ssam				       subl))
1519127675Sbms                    return(0);
1520127675Sbms              }
1521127675Sbms            }
1522127675Sbms            break;
1523127675Sbms        default:
1524127675Sbms            if(!print_unknown_data(tptr,"\n\t\t    ",
1525127675Sbms				   subl))
1526127675Sbms                return(0);
1527127675Sbms            break;
1528127675Sbms        }
1529127675Sbms        return(1);
153098527Sfenner
1531127675Sbmstrunctlv:
1532127675Sbms    printf("%spacket exceeded snapshot",ident);
1533127675Sbms    return(0);
1534127675Sbms}
153598527Sfenner
153698527Sfenner
1537127675Sbms/*
1538127675Sbms * this is the common IS-REACH decoder it is called
1539127675Sbms * from various EXTD-IS REACH style TLVs (22,24,222)
1540127675Sbms */
154198527Sfenner
1542127675Sbmsstatic int
1543127675Sbmsisis_print_ext_is_reach (const u_int8_t *tptr,const char *ident, int tlv_type) {
154498527Sfenner
1545127675Sbms    char ident_buffer[20];
1546127675Sbms    int subtlv_type,subtlv_len,subtlv_sum_len;
1547127675Sbms    int proc_bytes = 0; /* how many bytes did we process ? */
1548127675Sbms
1549127675Sbms    if (!TTEST2(*tptr, NODE_ID_LEN))
1550127675Sbms        return(0);
155198527Sfenner
1552127675Sbms    printf("%sIS Neighbor: %s", ident, isis_print_id(tptr, NODE_ID_LEN));
1553127675Sbms    tptr+=(NODE_ID_LEN);
155498527Sfenner
1555146778Ssam    if (tlv_type != ISIS_TLV_IS_ALIAS_ID) { /* the Alias TLV Metric field is implicit 0 */
1556127675Sbms        if (!TTEST2(*tptr, 3))    /* and is therefore skipped */
1557127675Sbms	    return(0);
1558127675Sbms	printf(", Metric: %d",EXTRACT_24BITS(tptr));
1559127675Sbms	tptr+=3;
1560127675Sbms    }
1561127675Sbms
1562127675Sbms    if (!TTEST2(*tptr, 1))
1563127675Sbms        return(0);
1564127675Sbms    subtlv_sum_len=*(tptr++); /* read out subTLV length */
1565127675Sbms    proc_bytes=NODE_ID_LEN+3+1;
1566127675Sbms    printf(", %ssub-TLVs present",subtlv_sum_len ? "" : "no ");
1567127675Sbms    if (subtlv_sum_len) {
1568127675Sbms        printf(" (%u)",subtlv_sum_len);
1569127675Sbms        while (subtlv_sum_len>0) {
1570127675Sbms            if (!TTEST2(*tptr,2))
1571127675Sbms                return(0);
1572127675Sbms            subtlv_type=*(tptr++);
1573127675Sbms            subtlv_len=*(tptr++);
1574127675Sbms            /* prepend the ident string */
1575127675Sbms            snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
1576127675Sbms            if(!isis_print_is_reach_subtlv(tptr,subtlv_type,subtlv_len,ident_buffer))
1577127675Sbms                return(0);
1578127675Sbms            tptr+=subtlv_len;
1579127675Sbms            subtlv_sum_len-=(subtlv_len+2);
1580127675Sbms            proc_bytes+=(subtlv_len+2);
1581127675Sbms        }
1582127675Sbms    }
1583127675Sbms    return(proc_bytes);
158417688Spst}
158517688Spst
158617688Spst/*
1587127675Sbms * this is the common Multi Topology ID decoder
1588127675Sbms * it is called from various MT-TLVs (222,229,235,237)
1589127675Sbms */
1590127675Sbms
1591127675Sbmsstatic int
1592127675Sbmsisis_print_mtid (const u_int8_t *tptr,const char *ident) {
1593127675Sbms
1594127675Sbms    if (!TTEST2(*tptr, 2))
1595127675Sbms        return(0);
1596127675Sbms
1597127675Sbms    printf("%s%s",
1598127675Sbms           ident,
1599127675Sbms           tok2str(isis_mt_values,
1600127675Sbms                   "Reserved for IETF Consensus",
1601127675Sbms                   ISIS_MASK_MTID(EXTRACT_16BITS(tptr))));
1602127675Sbms
1603127675Sbms    printf(" Topology (0x%03x), Flags: [%s]",
1604127675Sbms           ISIS_MASK_MTID(EXTRACT_16BITS(tptr)),
1605127675Sbms           bittok2str(isis_mt_flag_values, "none",ISIS_MASK_MTFLAGS(EXTRACT_16BITS(tptr))));
1606127675Sbms
1607127675Sbms    return(2);
1608127675Sbms}
1609127675Sbms
1610127675Sbms/*
1611127675Sbms * this is the common extended IP reach decoder
1612127675Sbms * it is called from TLVs (135,235,236,237)
1613127675Sbms * we process the TLV and optional subTLVs and return
1614127675Sbms * the amount of processed bytes
1615127675Sbms */
1616127675Sbms
1617127675Sbmsstatic int
1618127675Sbmsisis_print_extd_ip_reach (const u_int8_t *tptr, const char *ident, u_int16_t afi) {
1619127675Sbms
1620127675Sbms    char ident_buffer[20];
1621172686Smlaier#ifdef INET6
1622162021Ssam    u_int8_t prefix[sizeof(struct in6_addr)]; /* shared copy buffer for IPv4 and IPv6 prefixes */
1623172686Smlaier#else
1624172686Smlaier    u_int8_t prefix[sizeof(struct in_addr)]; /* shared copy buffer for IPv4 prefixes */
1625172686Smlaier#endif
1626127675Sbms    u_int metric, status_byte, bit_length, byte_length, sublen, processed, subtlvtype, subtlvlen;
1627127675Sbms
1628127675Sbms    if (!TTEST2(*tptr, 4))
1629127675Sbms        return (0);
1630127675Sbms    metric = EXTRACT_32BITS(tptr);
1631127675Sbms    processed=4;
1632127675Sbms    tptr+=4;
1633127675Sbms
1634127675Sbms    if (afi == IPV4) {
1635127675Sbms        if (!TTEST2(*tptr, 1)) /* fetch status byte */
1636127675Sbms            return (0);
1637127675Sbms        status_byte=*(tptr++);
1638127675Sbms        bit_length = status_byte&0x3f;
1639172686Smlaier        if (bit_length > 32) {
1640172686Smlaier            printf("%sIPv4 prefix: bad bit length %u",
1641172686Smlaier                   ident,
1642172686Smlaier                   bit_length);
1643172686Smlaier            return (0);
1644172686Smlaier        }
1645127675Sbms        processed++;
1646127675Sbms#ifdef INET6
1647127675Sbms    } else if (afi == IPV6) {
1648127675Sbms        if (!TTEST2(*tptr, 1)) /* fetch status & prefix_len byte */
1649127675Sbms            return (0);
1650127675Sbms        status_byte=*(tptr++);
1651127675Sbms        bit_length=*(tptr++);
1652172686Smlaier        if (bit_length > 128) {
1653172686Smlaier            printf("%sIPv6 prefix: bad bit length %u",
1654172686Smlaier                   ident,
1655172686Smlaier                   bit_length);
1656172686Smlaier            return (0);
1657172686Smlaier        }
1658127675Sbms        processed+=2;
1659127675Sbms#endif
1660127675Sbms    } else
1661127675Sbms        return (0); /* somebody is fooling us */
1662127675Sbms
1663127675Sbms    byte_length = (bit_length + 7) / 8; /* prefix has variable length encoding */
1664127675Sbms
1665127675Sbms    if (!TTEST2(*tptr, byte_length))
1666127675Sbms        return (0);
1667172686Smlaier    memset(prefix, 0, sizeof prefix);   /* clear the copy buffer */
1668127675Sbms    memcpy(prefix,tptr,byte_length);    /* copy as much as is stored in the TLV */
1669127675Sbms    tptr+=byte_length;
1670127675Sbms    processed+=byte_length;
1671127675Sbms
1672127675Sbms    if (afi == IPV4)
1673127675Sbms        printf("%sIPv4 prefix: %15s/%u",
1674127675Sbms               ident,
1675127675Sbms               ipaddr_string(prefix),
1676127675Sbms               bit_length);
1677127675Sbms#ifdef INET6
1678127675Sbms    if (afi == IPV6)
1679127675Sbms        printf("%sIPv6 prefix: %s/%u",
1680127675Sbms               ident,
1681127675Sbms               ip6addr_string(prefix),
1682127675Sbms               bit_length);
1683127675Sbms#endif
1684127675Sbms
1685127675Sbms    printf(", Distribution: %s, Metric: %u",
1686127675Sbms           ISIS_MASK_TLV_EXTD_IP_UPDOWN(status_byte) ? "down" : "up",
1687127675Sbms           metric);
1688127675Sbms
1689127675Sbms    if (afi == IPV4 && ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte))
1690127675Sbms        printf(", sub-TLVs present");
1691127675Sbms#ifdef INET6
1692127675Sbms    if (afi == IPV6)
1693127675Sbms        printf(", %s%s",
1694127675Sbms               ISIS_MASK_TLV_EXTD_IP6_IE(status_byte) ? "External" : "Internal",
1695127675Sbms               ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte) ? ", sub-TLVs present" : "");
1696127675Sbms#endif
1697127675Sbms
1698127675Sbms    if ((ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte)  && afi == IPV4) ||
1699127675Sbms        (ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte) && afi == IPV6)) {
1700127675Sbms        /* assume that one prefix can hold more
1701127675Sbms           than one subTLV - therefore the first byte must reflect
1702127675Sbms           the aggregate bytecount of the subTLVs for this prefix
1703127675Sbms        */
1704127675Sbms        if (!TTEST2(*tptr, 1))
1705127675Sbms            return (0);
1706127675Sbms        sublen=*(tptr++);
1707127675Sbms        processed+=sublen+1;
1708127675Sbms        printf(" (%u)",sublen);   /* print out subTLV length */
1709127675Sbms
1710127675Sbms        while (sublen>0) {
1711127675Sbms            if (!TTEST2(*tptr,2))
1712127675Sbms                return (0);
1713127675Sbms            subtlvtype=*(tptr++);
1714127675Sbms            subtlvlen=*(tptr++);
1715127675Sbms            /* prepend the ident string */
1716127675Sbms            snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
1717127675Sbms            if(!isis_print_ip_reach_subtlv(tptr,subtlvtype,subtlvlen,ident_buffer))
1718127675Sbms                return(0);
1719127675Sbms            tptr+=subtlvlen;
1720127675Sbms            sublen-=(subtlvlen+2);
1721127675Sbms        }
1722127675Sbms    }
1723127675Sbms    return (processed);
1724127675Sbms}
1725127675Sbms
1726127675Sbms/*
172717688Spst * isis_print
172817688Spst * Decode IS-IS packets.  Return 0 on error.
172917688Spst */
173017688Spst
1731127675Sbmsstatic int isis_print (const u_int8_t *p, u_int length)
173217688Spst{
1733146778Ssam    const struct isis_common_header *isis_header;
173417688Spst
173598527Sfenner    const struct isis_iih_lan_header *header_iih_lan;
173698527Sfenner    const struct isis_iih_ptp_header *header_iih_ptp;
173798527Sfenner    const struct isis_lsp_header *header_lsp;
173898527Sfenner    const struct isis_csnp_header *header_csnp;
173998527Sfenner    const struct isis_psnp_header *header_psnp;
174017688Spst
174198527Sfenner    const struct isis_tlv_lsp *tlv_lsp;
174298527Sfenner    const struct isis_tlv_ptp_adj *tlv_ptp_adj;
174398527Sfenner    const struct isis_tlv_is_reach *tlv_is_reach;
1744127675Sbms    const struct isis_tlv_es_reach *tlv_es_reach;
174598527Sfenner
1746127675Sbms    u_int8_t pdu_type, max_area, id_length, tlv_type, tlv_len, tmp, alen, lan_alen, prefix_len;
1747127675Sbms    u_int8_t ext_is_len, ext_ip_len, mt_len;
1748127675Sbms    const u_int8_t *optr, *pptr, *tptr;
174998527Sfenner    u_short packet_len,pdu_len;
1750146778Ssam    u_int i,vendor_id;
175198527Sfenner
175298527Sfenner    packet_len=length;
1753127675Sbms    optr = p; /* initialize the _o_riginal pointer to the packet start -
1754127675Sbms                 need it for parsing the checksum TLV */
1755146778Ssam    isis_header = (const struct isis_common_header *)p;
1756146778Ssam    TCHECK(*isis_header);
1757127675Sbms    pptr = p+(ISIS_COMMON_HEADER_SIZE);
175898527Sfenner    header_iih_lan = (const struct isis_iih_lan_header *)pptr;
175998527Sfenner    header_iih_ptp = (const struct isis_iih_ptp_header *)pptr;
176098527Sfenner    header_lsp = (const struct isis_lsp_header *)pptr;
176198527Sfenner    header_csnp = (const struct isis_csnp_header *)pptr;
176298527Sfenner    header_psnp = (const struct isis_psnp_header *)pptr;
1763127675Sbms
1764146778Ssam    if (!eflag)
1765146778Ssam        printf("IS-IS");
1766146778Ssam
176717688Spst    /*
176817688Spst     * Sanity checking of the header.
176917688Spst     */
177017688Spst
1771146778Ssam    if (isis_header->version != ISIS_VERSION) {
1772146778Ssam	printf("version %d packet not supported", isis_header->version);
177398527Sfenner	return (0);
177417688Spst    }
177517688Spst
1776146778Ssam    if ((isis_header->id_length != SYSTEM_ID_LEN) && (isis_header->id_length != 0)) {
1777146778Ssam	printf("system ID length of %d is not supported",
1778146778Ssam	       isis_header->id_length);
177998527Sfenner	return (0);
178017688Spst    }
1781127675Sbms
1782146778Ssam    if (isis_header->pdu_version != ISIS_VERSION) {
1783146778Ssam	printf("version %d packet not supported", isis_header->pdu_version);
178498527Sfenner	return (0);
178517688Spst    }
178617688Spst
1787146778Ssam    max_area = isis_header->max_area;
178817688Spst    switch(max_area) {
178917688Spst    case 0:
1790127675Sbms	max_area = 3;	 /* silly shit */
179117688Spst	break;
179217688Spst    case 255:
1793146778Ssam	printf("bad packet -- 255 areas");
179498527Sfenner	return (0);
179517688Spst    default:
179617688Spst	break;
179717688Spst    }
179817688Spst
1799146778Ssam    id_length = isis_header->id_length;
1800127675Sbms    switch(id_length) {
1801127675Sbms    case 0:
1802127675Sbms        id_length = 6;	 /* silly shit again */
1803127675Sbms	break;
1804127675Sbms    case 1:              /* 1-8 are valid sys-ID lenghts */
1805127675Sbms    case 2:
1806127675Sbms    case 3:
1807127675Sbms    case 4:
1808127675Sbms    case 5:
1809127675Sbms    case 6:
1810127675Sbms    case 7:
1811127675Sbms    case 8:
1812127675Sbms        break;
1813127675Sbms    case 255:
1814127675Sbms        id_length = 0;   /* entirely useless */
1815127675Sbms	break;
1816127675Sbms    default:
1817127675Sbms        break;
1818127675Sbms    }
1819127675Sbms
1820127675Sbms    /* toss any non 6-byte sys-ID len PDUs */
1821127675Sbms    if (id_length != 6 ) {
1822146778Ssam	printf("bad packet -- illegal sys-ID length (%u)", id_length);
1823127675Sbms	return (0);
1824127675Sbms    }
1825127675Sbms
1826146778Ssam    pdu_type=isis_header->pdu_type;
1827127675Sbms
1828127675Sbms    /* in non-verbose mode print the basic PDU Type plus PDU specific brief information*/
1829127675Sbms    if (vflag < 1) {
1830146778Ssam        printf("%s%s",
1831146778Ssam               eflag ? "" : ", ",
1832127675Sbms               tok2str(isis_pdu_values,"unknown PDU-Type %u",pdu_type));
1833127675Sbms
1834127675Sbms	switch (pdu_type) {
1835127675Sbms
1836146778Ssam	case ISIS_PDU_L1_LAN_IIH:
1837146778Ssam	case ISIS_PDU_L2_LAN_IIH:
1838127675Sbms	    printf(", src-id %s",
1839127675Sbms                   isis_print_id(header_iih_lan->source_id,SYSTEM_ID_LEN));
1840127675Sbms	    printf(", lan-id %s, prio %u",
1841127675Sbms                   isis_print_id(header_iih_lan->lan_id,NODE_ID_LEN),
1842127675Sbms                   header_iih_lan->priority);
1843127675Sbms	    break;
1844146778Ssam	case ISIS_PDU_PTP_IIH:
1845127675Sbms	    printf(", src-id %s", isis_print_id(header_iih_ptp->source_id,SYSTEM_ID_LEN));
1846127675Sbms	    break;
1847146778Ssam	case ISIS_PDU_L1_LSP:
1848146778Ssam	case ISIS_PDU_L2_LSP:
1849127675Sbms	    printf(", lsp-id %s, seq 0x%08x, lifetime %5us",
1850127675Sbms		   isis_print_id(header_lsp->lsp_id, LSP_ID_LEN),
1851127675Sbms		   EXTRACT_32BITS(header_lsp->sequence_number),
1852127675Sbms		   EXTRACT_16BITS(header_lsp->remaining_lifetime));
1853127675Sbms	    break;
1854146778Ssam	case ISIS_PDU_L1_CSNP:
1855146778Ssam	case ISIS_PDU_L2_CSNP:
1856146778Ssam	    printf(", src-id %s", isis_print_id(header_csnp->source_id,NODE_ID_LEN));
1857127675Sbms	    break;
1858146778Ssam	case ISIS_PDU_L1_PSNP:
1859146778Ssam	case ISIS_PDU_L2_PSNP:
1860146778Ssam	    printf(", src-id %s", isis_print_id(header_psnp->source_id,NODE_ID_LEN));
1861127675Sbms	    break;
1862127675Sbms
1863127675Sbms	}
1864127675Sbms	printf(", length %u", length);
1865127675Sbms
1866127675Sbms        return(1);
1867127675Sbms    }
1868127675Sbms
1869127675Sbms    /* ok they seem to want to know everything - lets fully decode it */
1870146778Ssam    printf("%slength %u", eflag ? "" : ", ",length);
1871127675Sbms
1872127675Sbms    printf("\n\t%s, hlen: %u, v: %u, pdu-v: %u, sys-id-len: %u (%u), max-area: %u (%u)",
1873127675Sbms           tok2str(isis_pdu_values,
1874127675Sbms                   "unknown, type %u",
1875127675Sbms                   pdu_type),
1876146778Ssam           isis_header->fixed_len,
1877146778Ssam           isis_header->version,
1878146778Ssam           isis_header->pdu_version,
1879127675Sbms	   id_length,
1880146778Ssam	   isis_header->id_length,
188198527Sfenner           max_area,
1882146778Ssam           isis_header->max_area);
1883127675Sbms
1884127675Sbms    if (vflag > 1) {
1885127675Sbms        if(!print_unknown_data(optr,"\n\t",8)) /* provide the _o_riginal pointer */
1886127675Sbms            return(0);                         /* for optionally debugging the common header */
1887127675Sbms    }
1888127675Sbms
188998527Sfenner    switch (pdu_type) {
189098527Sfenner
1891146778Ssam    case ISIS_PDU_L1_LAN_IIH:
1892146778Ssam    case ISIS_PDU_L2_LAN_IIH:
1893146778Ssam	if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE)) {
189498527Sfenner	    printf(", bogus fixed header length %u should be %lu",
1895146778Ssam		   isis_header->fixed_len, (unsigned long)ISIS_IIH_LAN_HEADER_SIZE);
189698527Sfenner	    return (0);
189717688Spst	}
189898527Sfenner
189998527Sfenner	pdu_len=EXTRACT_16BITS(header_iih_lan->pdu_len);
190098527Sfenner	if (packet_len>pdu_len) {
1901127675Sbms            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1902127675Sbms            length=pdu_len;
190398527Sfenner	}
190498527Sfenner
190598527Sfenner	TCHECK(*header_iih_lan);
1906127675Sbms	printf("\n\t  source-id: %s,  holding time: %us, Flags: [%s]",
1907127675Sbms               isis_print_id(header_iih_lan->source_id,SYSTEM_ID_LEN),
1908127675Sbms               EXTRACT_16BITS(header_iih_lan->holding_time),
1909127675Sbms               tok2str(isis_iih_circuit_type_values,
1910127675Sbms                       "unknown circuit type 0x%02x",
1911127675Sbms                       header_iih_lan->circuit_type));
191298527Sfenner
1913127675Sbms	printf("\n\t  lan-id:    %s, Priority: %u, PDU length: %u",
1914127675Sbms               isis_print_id(header_iih_lan->lan_id, NODE_ID_LEN),
1915146778Ssam               (header_iih_lan->priority) & ISIS_LAN_PRIORITY_MASK,
1916127675Sbms               pdu_len);
191798527Sfenner
1918127675Sbms        if (vflag > 1) {
1919127675Sbms            if(!print_unknown_data(pptr,"\n\t  ",ISIS_IIH_LAN_HEADER_SIZE))
1920127675Sbms                return(0);
1921127675Sbms        }
192298527Sfenner
192398527Sfenner	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
192498527Sfenner	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
192517688Spst	break;
192698527Sfenner
1927146778Ssam    case ISIS_PDU_PTP_IIH:
1928146778Ssam	if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE)) {
192998527Sfenner	    printf(", bogus fixed header length %u should be %lu",
1930146778Ssam		   isis_header->fixed_len, (unsigned long)ISIS_IIH_PTP_HEADER_SIZE);
193198527Sfenner	    return (0);
193217688Spst	}
1933127675Sbms
193498527Sfenner	pdu_len=EXTRACT_16BITS(header_iih_ptp->pdu_len);
193598527Sfenner	if (packet_len>pdu_len) {
1936127675Sbms            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1937127675Sbms            length=pdu_len;
193898527Sfenner	}
1939127675Sbms
194098527Sfenner	TCHECK(*header_iih_ptp);
1941127675Sbms	printf("\n\t  source-id: %s, holding time: %us, Flags: [%s]",
1942127675Sbms               isis_print_id(header_iih_ptp->source_id,SYSTEM_ID_LEN),
1943127675Sbms               EXTRACT_16BITS(header_iih_ptp->holding_time),
1944127675Sbms               tok2str(isis_iih_circuit_type_values,
1945127675Sbms                       "unknown circuit type 0x%02x",
1946127675Sbms                       header_iih_ptp->circuit_type));
194798527Sfenner
1948127675Sbms	printf("\n\t  circuit-id: 0x%02x, PDU length: %u",
1949127675Sbms               header_iih_ptp->circuit_id,
1950127675Sbms               pdu_len);
195198527Sfenner
1952127675Sbms        if (vflag > 1) {
1953127675Sbms            if(!print_unknown_data(pptr,"\n\t  ",ISIS_IIH_PTP_HEADER_SIZE))
1954127675Sbms                return(0);
1955127675Sbms        }
195698527Sfenner
195798527Sfenner	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
195898527Sfenner	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
195917688Spst	break;
196098527Sfenner
1961146778Ssam    case ISIS_PDU_L1_LSP:
1962146778Ssam    case ISIS_PDU_L2_LSP:
1963146778Ssam	if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE)) {
196498527Sfenner	    printf(", bogus fixed header length %u should be %lu",
1965146778Ssam		   isis_header->fixed_len, (unsigned long)ISIS_LSP_HEADER_SIZE);
196698527Sfenner	    return (0);
196798527Sfenner	}
1968127675Sbms
196998527Sfenner	pdu_len=EXTRACT_16BITS(header_lsp->pdu_len);
197098527Sfenner	if (packet_len>pdu_len) {
1971127675Sbms            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1972127675Sbms            length=pdu_len;
197398527Sfenner	}
197498527Sfenner
197598527Sfenner	TCHECK(*header_lsp);
1976127675Sbms	printf("\n\t  lsp-id: %s, seq: 0x%08x, lifetime: %5us\n\t  chksum: 0x%04x",
1977127675Sbms               isis_print_id(header_lsp->lsp_id, LSP_ID_LEN),
1978127675Sbms               EXTRACT_32BITS(header_lsp->sequence_number),
1979127675Sbms               EXTRACT_16BITS(header_lsp->remaining_lifetime),
1980127675Sbms               EXTRACT_16BITS(header_lsp->checksum));
198198527Sfenner
1982127675Sbms        /* if this is a purge do not attempt to verify the checksum */
1983127675Sbms        if ( EXTRACT_16BITS(header_lsp->remaining_lifetime) == 0 &&
1984127675Sbms             EXTRACT_16BITS(header_lsp->checksum) == 0)
1985127675Sbms            printf(" (purged)");
1986127675Sbms        else
1987127675Sbms            /* verify the checksum -
1988127675Sbms             * checking starts at the lsp-id field at byte position [12]
1989127675Sbms             * hence the length needs to be reduced by 12 bytes */
1990127675Sbms            printf(" (%s)", (osi_cksum((u_int8_t *)header_lsp->lsp_id, length-12)) ? "incorrect" : "correct");
1991127675Sbms
1992127675Sbms	printf(", PDU length: %u, Flags: [ %s",
1993127675Sbms               pdu_len,
1994127675Sbms               ISIS_MASK_LSP_OL_BIT(header_lsp->typeblock) ? "Overload bit set, " : "");
1995127675Sbms
199698527Sfenner	if (ISIS_MASK_LSP_ATT_BITS(header_lsp->typeblock)) {
199798527Sfenner	    printf("%s", ISIS_MASK_LSP_ATT_DEFAULT_BIT(header_lsp->typeblock) ? "default " : "");
199898527Sfenner	    printf("%s", ISIS_MASK_LSP_ATT_DELAY_BIT(header_lsp->typeblock) ? "delay " : "");
199998527Sfenner	    printf("%s", ISIS_MASK_LSP_ATT_EXPENSE_BIT(header_lsp->typeblock) ? "expense " : "");
200098527Sfenner	    printf("%s", ISIS_MASK_LSP_ATT_ERROR_BIT(header_lsp->typeblock) ? "error " : "");
200198527Sfenner	    printf("ATT bit set, ");
200298527Sfenner	}
200398527Sfenner	printf("%s", ISIS_MASK_LSP_PARTITION_BIT(header_lsp->typeblock) ? "P bit set, " : "");
2004127675Sbms	printf("%s ]", tok2str(isis_lsp_istype_values,"Unknown(0x%x)",ISIS_MASK_LSP_ISTYPE_BITS(header_lsp->typeblock)));
200598527Sfenner
2006127675Sbms        if (vflag > 1) {
2007127675Sbms            if(!print_unknown_data(pptr,"\n\t  ",ISIS_LSP_HEADER_SIZE))
2008127675Sbms                return(0);
2009127675Sbms        }
2010127675Sbms
201198527Sfenner	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
201298527Sfenner	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
201317688Spst	break;
201498527Sfenner
2015146778Ssam    case ISIS_PDU_L1_CSNP:
2016146778Ssam    case ISIS_PDU_L2_CSNP:
2017146778Ssam	if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE)) {
201898527Sfenner	    printf(", bogus fixed header length %u should be %lu",
2019146778Ssam		   isis_header->fixed_len, (unsigned long)ISIS_CSNP_HEADER_SIZE);
202098527Sfenner	    return (0);
202198527Sfenner	}
2022127675Sbms
202398527Sfenner	pdu_len=EXTRACT_16BITS(header_csnp->pdu_len);
202498527Sfenner	if (packet_len>pdu_len) {
2025127675Sbms            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
2026127675Sbms            length=pdu_len;
202798527Sfenner	}
202817688Spst
202998527Sfenner	TCHECK(*header_csnp);
2030127675Sbms	printf("\n\t  source-id:    %s, PDU length: %u",
2031127675Sbms               isis_print_id(header_csnp->source_id, NODE_ID_LEN),
2032127675Sbms               pdu_len);
2033127675Sbms	printf("\n\t  start lsp-id: %s",
2034127675Sbms               isis_print_id(header_csnp->start_lsp_id, LSP_ID_LEN));
2035127675Sbms	printf("\n\t  end lsp-id:   %s",
2036127675Sbms               isis_print_id(header_csnp->end_lsp_id, LSP_ID_LEN));
203717688Spst
2038127675Sbms        if (vflag > 1) {
2039127675Sbms            if(!print_unknown_data(pptr,"\n\t  ",ISIS_CSNP_HEADER_SIZE))
2040127675Sbms                return(0);
2041127675Sbms        }
2042127675Sbms
204398527Sfenner	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
204498527Sfenner	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
204598527Sfenner        break;
204617688Spst
2047146778Ssam    case ISIS_PDU_L1_PSNP:
2048146778Ssam    case ISIS_PDU_L2_PSNP:
2049146778Ssam	if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE)) {
205098527Sfenner	    printf("- bogus fixed header length %u should be %lu",
2051146778Ssam		   isis_header->fixed_len, (unsigned long)ISIS_PSNP_HEADER_SIZE);
205298527Sfenner	    return (0);
205398527Sfenner	}
205498527Sfenner
205598527Sfenner	pdu_len=EXTRACT_16BITS(header_psnp->pdu_len);
205698527Sfenner	if (packet_len>pdu_len) {
2057127675Sbms            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
2058127675Sbms            length=pdu_len;
205998527Sfenner	}
206098527Sfenner
206198527Sfenner	TCHECK(*header_psnp);
2062127675Sbms	printf("\n\t  source-id:    %s, PDU length: %u",
2063127675Sbms               isis_print_id(header_psnp->source_id, NODE_ID_LEN),
2064127675Sbms               pdu_len);
2065127675Sbms
2066127675Sbms        if (vflag > 1) {
2067127675Sbms            if(!print_unknown_data(pptr,"\n\t  ",ISIS_PSNP_HEADER_SIZE))
2068127675Sbms                return(0);
2069127675Sbms        }
2070127675Sbms
207198527Sfenner	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
207298527Sfenner	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
207317688Spst	break;
207417688Spst
207598527Sfenner    default:
2076127675Sbms	if(!print_unknown_data(pptr,"\n\t  ",length))
2077127675Sbms	    return(0);
2078127675Sbms	return (0);
207917688Spst    }
208017688Spst
208117688Spst    /*
208217688Spst     * Now print the TLV's.
208317688Spst     */
2084127675Sbms
208517688Spst    while (packet_len >= 2) {
208698527Sfenner        if (pptr == snapend) {
208798527Sfenner	    return (1);
208898527Sfenner        }
208998527Sfenner
209098527Sfenner	if (!TTEST2(*pptr, 2)) {
2091127675Sbms	    printf("\n\t\t packet exceeded snapshot (%ld) bytes",
2092127675Sbms                   (long)(pptr-snapend));
209398527Sfenner	    return (1);
209417688Spst	}
2095127675Sbms	tlv_type = *pptr++;
2096127675Sbms	tlv_len = *pptr++;
2097127675Sbms        tmp =tlv_len; /* copy temporary len & pointer to packet data */
2098127675Sbms        tptr = pptr;
209917688Spst	packet_len -= 2;
2100127675Sbms	if (tlv_len > packet_len) {
210117688Spst	    break;
210217688Spst	}
210317688Spst
2104127675Sbms        /* first lets see if we know the TLVs name*/
2105127675Sbms	printf("\n\t    %s TLV #%u, length: %u",
2106127675Sbms               tok2str(isis_tlv_values,
2107127675Sbms                       "unknown",
2108127675Sbms                       tlv_type),
2109127675Sbms               tlv_type,
2110127675Sbms               tlv_len);
2111127675Sbms
2112147175Ssam        if (tlv_len == 0) /* something is malformed */
2113172686Smlaier	    continue;
2114147175Ssam
2115127675Sbms        /* now check if we have a decoder otherwise do a hexdump at the end*/
2116127675Sbms	switch (tlv_type) {
2117146778Ssam	case ISIS_TLV_AREA_ADDR:
211898527Sfenner	    if (!TTEST2(*tptr, 1))
211998527Sfenner		goto trunctlv;
212017688Spst	    alen = *tptr++;
212117688Spst	    while (tmp && alen < tmp) {
2122127675Sbms		printf("\n\t      Area address (length: %u): %s",
2123127675Sbms                       alen,
2124146778Ssam                       isonsap_string(tptr,alen));
212517688Spst		tptr += alen;
212617688Spst		tmp -= alen + 1;
212798527Sfenner		if (tmp==0) /* if this is the last area address do not attemt a boundary check */
2128127675Sbms                    break;
212998527Sfenner		if (!TTEST2(*tptr, 1))
213098527Sfenner		    goto trunctlv;
213117688Spst		alen = *tptr++;
213217688Spst	    }
213317688Spst	    break;
2134146778Ssam	case ISIS_TLV_ISNEIGH:
213575118Sfenner	    while (tmp >= ETHER_ADDR_LEN) {
2136127675Sbms                if (!TTEST2(*tptr, ETHER_ADDR_LEN))
2137127675Sbms                    goto trunctlv;
2138127675Sbms                printf("\n\t      SNPA: %s",isis_print_id(tptr,ETHER_ADDR_LEN));
2139127675Sbms                tmp -= ETHER_ADDR_LEN;
2140127675Sbms                tptr += ETHER_ADDR_LEN;
214117688Spst	    }
214217688Spst	    break;
214398527Sfenner
2144146778Ssam        case ISIS_TLV_ISNEIGH_VARLEN:
2145147175Ssam            if (!TTEST2(*tptr, 1) || tmp < 3) /* min. TLV length */
2146127675Sbms		goto trunctlv;
2147147904Ssam	    lan_alen = *tptr++; /* LAN address length */
2148147904Ssam	    if (lan_alen == 0) {
2149147904Ssam                printf("\n\t      LAN address length 0 bytes (invalid)");
2150147904Ssam                break;
2151147904Ssam            }
2152127675Sbms            tmp --;
2153127675Sbms            printf("\n\t      LAN address length %u bytes ",lan_alen);
2154127675Sbms	    while (tmp >= lan_alen) {
2155127675Sbms                if (!TTEST2(*tptr, lan_alen))
2156127675Sbms                    goto trunctlv;
2157127675Sbms                printf("\n\t\tIS Neighbor: %s",isis_print_id(tptr,lan_alen));
2158127675Sbms                tmp -= lan_alen;
2159127675Sbms                tptr +=lan_alen;
2160127675Sbms            }
2161127675Sbms            break;
2162127675Sbms
2163146778Ssam	case ISIS_TLV_PADDING:
216417688Spst	    break;
216598527Sfenner
2166146778Ssam        case ISIS_TLV_MT_IS_REACH:
2167127675Sbms            while (tmp >= 2+NODE_ID_LEN+3+1) {
2168127675Sbms                mt_len = isis_print_mtid(tptr, "\n\t      ");
2169127675Sbms                if (mt_len == 0) /* did something go wrong ? */
2170127675Sbms                    goto trunctlv;
2171127675Sbms                tptr+=mt_len;
2172127675Sbms                tmp-=mt_len;
217398527Sfenner
2174127675Sbms                ext_is_len = isis_print_ext_is_reach(tptr,"\n\t      ",tlv_type);
2175127675Sbms                if (ext_is_len == 0) /* did something go wrong ? */
217698527Sfenner                    goto trunctlv;
2177127675Sbms
2178127675Sbms                tmp-=ext_is_len;
2179127675Sbms                tptr+=ext_is_len;
218098527Sfenner            }
218198527Sfenner            break;
218298527Sfenner
2183146778Ssam        case ISIS_TLV_IS_ALIAS_ID:
2184127675Sbms	    while (tmp >= NODE_ID_LEN+1) { /* is it worth attempting a decode ? */
2185127675Sbms	        ext_is_len = isis_print_ext_is_reach(tptr,"\n\t      ",tlv_type);
2186127675Sbms		if (ext_is_len == 0) /* did something go wrong ? */
2187127675Sbms	            goto trunctlv;
2188127675Sbms		tmp-=ext_is_len;
2189127675Sbms		tptr+=ext_is_len;
2190127675Sbms	    }
2191127675Sbms	    break;
2192127675Sbms
2193146778Ssam        case ISIS_TLV_EXT_IS_REACH:
2194127675Sbms            while (tmp >= NODE_ID_LEN+3+1) { /* is it worth attempting a decode ? */
2195127675Sbms                ext_is_len = isis_print_ext_is_reach(tptr,"\n\t      ",tlv_type);
2196127675Sbms                if (ext_is_len == 0) /* did something go wrong ? */
2197127675Sbms                    goto trunctlv;
2198127675Sbms                tmp-=ext_is_len;
2199127675Sbms                tptr+=ext_is_len;
220098527Sfenner            }
220198527Sfenner            break;
2202146778Ssam        case ISIS_TLV_IS_REACH:
220398527Sfenner	    if (!TTEST2(*tptr,1))  /* check if there is one byte left to read out the virtual flag */
2204127675Sbms                goto trunctlv;
2205127675Sbms            printf("\n\t      %s",
2206127675Sbms                   tok2str(isis_is_reach_virtual_values,
2207127675Sbms                           "bogus virtual flag 0x%02x",
2208127675Sbms                           *tptr++));
220998527Sfenner	    tlv_is_reach = (const struct isis_tlv_is_reach *)tptr;
221098527Sfenner            while (tmp >= sizeof(struct isis_tlv_is_reach)) {
221198527Sfenner		if (!TTEST(*tlv_is_reach))
221298527Sfenner		    goto trunctlv;
2213127675Sbms		printf("\n\t      IS Neighbor: %s",
2214127675Sbms		       isis_print_id(tlv_is_reach->neighbor_nodeid, NODE_ID_LEN));
2215127675Sbms                isis_print_metric_block(&tlv_is_reach->isis_metric_block);
221698527Sfenner		tmp -= sizeof(struct isis_tlv_is_reach);
221798527Sfenner		tlv_is_reach++;
221898527Sfenner	    }
221998527Sfenner            break;
222098527Sfenner
2221146778Ssam        case ISIS_TLV_ESNEIGH:
2222127675Sbms	    tlv_es_reach = (const struct isis_tlv_es_reach *)tptr;
2223127675Sbms            while (tmp >= sizeof(struct isis_tlv_es_reach)) {
2224127675Sbms		if (!TTEST(*tlv_es_reach))
2225127675Sbms		    goto trunctlv;
2226127675Sbms		printf("\n\t      ES Neighbor: %s",
2227127675Sbms                       isis_print_id(tlv_es_reach->neighbor_sysid,SYSTEM_ID_LEN));
2228127675Sbms                isis_print_metric_block(&tlv_es_reach->isis_metric_block);
2229127675Sbms		tmp -= sizeof(struct isis_tlv_es_reach);
2230127675Sbms		tlv_es_reach++;
2231127675Sbms	    }
2232127675Sbms            break;
2233127675Sbms
2234127675Sbms            /* those two TLVs share the same format */
2235146778Ssam	case ISIS_TLV_INT_IP_REACH:
2236146778Ssam	case ISIS_TLV_EXT_IP_REACH:
2237127675Sbms	    if (!isis_print_tlv_ip_reach(pptr, "\n\t      ", tlv_len))
223898527Sfenner		return (1);
223917688Spst	    break;
224098527Sfenner
2241146778Ssam	case ISIS_TLV_EXTD_IP_REACH:
2242127675Sbms	    while (tmp>0) {
2243127675Sbms                ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", IPV4);
2244127675Sbms                if (ext_ip_len == 0) /* did something go wrong ? */
2245127675Sbms                    goto trunctlv;
2246127675Sbms                tptr+=ext_ip_len;
2247127675Sbms		tmp-=ext_ip_len;
2248127675Sbms	    }
224998527Sfenner	    break;
225098527Sfenner
2251146778Ssam        case ISIS_TLV_MT_IP_REACH:
2252172686Smlaier            mt_len = isis_print_mtid(tptr, "\n\t      ");
2253172686Smlaier            if (mt_len == 0) { /* did something go wrong ? */
2254172686Smlaier                goto trunctlv;
2255172686Smlaier            }
2256172686Smlaier            tptr+=mt_len;
2257172686Smlaier            tmp-=mt_len;
225898527Sfenner
2259172686Smlaier            while (tmp>0) {
2260127675Sbms                ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", IPV4);
2261127675Sbms                if (ext_ip_len == 0) /* did something go wrong ? */
2262127675Sbms                    goto trunctlv;
2263127675Sbms                tptr+=ext_ip_len;
2264127675Sbms		tmp-=ext_ip_len;
226598527Sfenner	    }
226698527Sfenner	    break;
226798527Sfenner
226898527Sfenner#ifdef INET6
2269146778Ssam	case ISIS_TLV_IP6_REACH:
2270127675Sbms	    while (tmp>0) {
2271127675Sbms                ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", IPV6);
2272127675Sbms                if (ext_ip_len == 0) /* did something go wrong ? */
2273127675Sbms                    goto trunctlv;
2274127675Sbms                tptr+=ext_ip_len;
2275127675Sbms		tmp-=ext_ip_len;
2276127675Sbms	    }
2277127675Sbms	    break;
227898527Sfenner
2279146778Ssam	case ISIS_TLV_MT_IP6_REACH:
2280172686Smlaier            mt_len = isis_print_mtid(tptr, "\n\t      ");
2281172686Smlaier            if (mt_len == 0) { /* did something go wrong ? */
2282172686Smlaier                goto trunctlv;
2283172686Smlaier            }
2284172686Smlaier            tptr+=mt_len;
2285172686Smlaier            tmp-=mt_len;
2286172686Smlaier
2287127675Sbms	    while (tmp>0) {
2288127675Sbms                ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", IPV6);
2289127675Sbms                if (ext_ip_len == 0) /* did something go wrong ? */
2290127675Sbms                    goto trunctlv;
2291127675Sbms                tptr+=ext_ip_len;
2292127675Sbms		tmp-=ext_ip_len;
229398527Sfenner	    }
229498527Sfenner	    break;
229598527Sfenner
2296146778Ssam	case ISIS_TLV_IP6ADDR:
2297162021Ssam	    while (tmp>=sizeof(struct in6_addr)) {
2298162021Ssam		if (!TTEST2(*tptr, sizeof(struct in6_addr)))
229998527Sfenner		    goto trunctlv;
230098527Sfenner
2301127675Sbms                printf("\n\t      IPv6 interface address: %s",
230298527Sfenner		       ip6addr_string(tptr));
230398527Sfenner
2304162021Ssam		tptr += sizeof(struct in6_addr);
2305162021Ssam		tmp -= sizeof(struct in6_addr);
230698527Sfenner	    }
230798527Sfenner	    break;
230898527Sfenner#endif
2309146778Ssam	case ISIS_TLV_AUTH:
2310127675Sbms	    if (!TTEST2(*tptr, 1))
231198527Sfenner		goto trunctlv;
2312127675Sbms
2313127675Sbms            printf("\n\t      %s: ",
2314127675Sbms                   tok2str(isis_subtlv_auth_values,
2315127675Sbms                           "unknown Authentication type 0x%02x",
2316127675Sbms                           *tptr));
2317127675Sbms
2318127675Sbms	    switch (*tptr) {
2319146778Ssam	    case ISIS_SUBTLV_AUTH_SIMPLE:
2320127675Sbms		for(i=1;i<tlv_len;i++) {
2321127675Sbms		    if (!TTEST2(*(tptr+i), 1))
232298527Sfenner			goto trunctlv;
2323127675Sbms		    printf("%c",*(tptr+i));
232498527Sfenner		}
2325127675Sbms		break;
2326146778Ssam	    case ISIS_SUBTLV_AUTH_MD5:
2327127675Sbms		for(i=1;i<tlv_len;i++) {
2328127675Sbms		    if (!TTEST2(*(tptr+i), 1))
232998527Sfenner			goto trunctlv;
2330127675Sbms		    printf("%02x",*(tptr+i));
233198527Sfenner		}
2332146778Ssam		if (tlv_len != ISIS_SUBTLV_AUTH_MD5_LEN+1)
2333127675Sbms                    printf(", (malformed subTLV) ");
2334127675Sbms		break;
2335146778Ssam	    case ISIS_SUBTLV_AUTH_PRIVATE:
2336127675Sbms	    default:
2337127675Sbms		if(!print_unknown_data(tptr+1,"\n\t\t  ",tlv_len-1))
2338127675Sbms		    return(0);
2339127675Sbms		break;
234098527Sfenner	    }
234198527Sfenner	    break;
234298527Sfenner
2343146778Ssam	case ISIS_TLV_PTP_ADJ:
2344127675Sbms	    tlv_ptp_adj = (const struct isis_tlv_ptp_adj *)tptr;
2345127675Sbms	    if(tmp>=1) {
2346127675Sbms		if (!TTEST2(*tptr, 1))
234798527Sfenner		    goto trunctlv;
2348127675Sbms		printf("\n\t      Adjacency State: %s (%u)",
2349127675Sbms		       tok2str(isis_ptp_adjancey_values, "unknown", *tptr),
2350127675Sbms                        *tptr);
2351127675Sbms		tmp--;
235298527Sfenner	    }
2353127675Sbms	    if(tmp>sizeof(tlv_ptp_adj->extd_local_circuit_id)) {
2354127675Sbms		if (!TTEST2(tlv_ptp_adj->extd_local_circuit_id,
2355127675Sbms                            sizeof(tlv_ptp_adj->extd_local_circuit_id)))
235698527Sfenner		    goto trunctlv;
2357127675Sbms		printf("\n\t      Extended Local circuit-ID: 0x%08x",
2358127675Sbms		       EXTRACT_32BITS(tlv_ptp_adj->extd_local_circuit_id));
2359127675Sbms		tmp-=sizeof(tlv_ptp_adj->extd_local_circuit_id);
236098527Sfenner	    }
2361127675Sbms	    if(tmp>=SYSTEM_ID_LEN) {
2362127675Sbms		if (!TTEST2(tlv_ptp_adj->neighbor_sysid, SYSTEM_ID_LEN))
236398527Sfenner		    goto trunctlv;
2364127675Sbms		printf("\n\t      Neighbor System-ID: %s",
2365127675Sbms		       isis_print_id(tlv_ptp_adj->neighbor_sysid,SYSTEM_ID_LEN));
2366127675Sbms		tmp-=SYSTEM_ID_LEN;
236798527Sfenner	    }
2368127675Sbms	    if(tmp>=sizeof(tlv_ptp_adj->neighbor_extd_local_circuit_id)) {
2369127675Sbms		if (!TTEST2(tlv_ptp_adj->neighbor_extd_local_circuit_id,
2370127675Sbms                            sizeof(tlv_ptp_adj->neighbor_extd_local_circuit_id)))
237198527Sfenner		    goto trunctlv;
2372127675Sbms		printf("\n\t      Neighbor Extended Local circuit-ID: 0x%08x",
2373127675Sbms		       EXTRACT_32BITS(tlv_ptp_adj->neighbor_extd_local_circuit_id));
237498527Sfenner	    }
237532149Spst	    break;
237698527Sfenner
2377146778Ssam	case ISIS_TLV_PROTOCOLS:
2378127675Sbms	    printf("\n\t      NLPID(s): ");
2379127675Sbms	    while (tmp>0) {
2380127675Sbms		if (!TTEST2(*(tptr), 1))
238198527Sfenner		    goto trunctlv;
2382127675Sbms		printf("%s (0x%02x)",
2383146778Ssam                       tok2str(nlpid_values,
2384127675Sbms                               "unknown",
2385127675Sbms                               *tptr),
2386127675Sbms                       *tptr);
2387127675Sbms		if (tmp>1) /* further NPLIDs ? - put comma */
238898527Sfenner		    printf(", ");
2389127675Sbms                tptr++;
2390127675Sbms                tmp--;
239198527Sfenner	    }
239232149Spst	    break;
239398527Sfenner
2394146778Ssam	case ISIS_TLV_TE_ROUTER_ID:
2395162021Ssam	    if (!TTEST2(*pptr, sizeof(struct in_addr)))
239698527Sfenner		goto trunctlv;
2397127675Sbms	    printf("\n\t      Traffic Engineering Router ID: %s", ipaddr_string(pptr));
239898527Sfenner	    break;
239998527Sfenner
2400146778Ssam	case ISIS_TLV_IPADDR:
2401162021Ssam	    while (tmp>=sizeof(struct in_addr)) {
2402162021Ssam		if (!TTEST2(*tptr, sizeof(struct in_addr)))
240398527Sfenner		    goto trunctlv;
2404127675Sbms		printf("\n\t      IPv4 interface address: %s", ipaddr_string(tptr));
2405162021Ssam		tptr += sizeof(struct in_addr);
2406162021Ssam		tmp -= sizeof(struct in_addr);
240798527Sfenner	    }
240832149Spst	    break;
240998527Sfenner
2410146778Ssam	case ISIS_TLV_HOSTNAME:
2411127675Sbms	    printf("\n\t      Hostname: ");
2412127675Sbms	    while (tmp>0) {
2413127675Sbms		if (!TTEST2(*tptr, 1))
241498527Sfenner		    goto trunctlv;
2415127675Sbms		printf("%c",*tptr++);
2416127675Sbms                tmp--;
241798527Sfenner	    }
241898527Sfenner	    break;
241998527Sfenner
2420146778Ssam	case ISIS_TLV_SHARED_RISK_GROUP:
2421147904Ssam	    if (tmp < NODE_ID_LEN)
2422147904Ssam	        break;
2423127675Sbms	    if (!TTEST2(*tptr, NODE_ID_LEN))
2424127675Sbms                goto trunctlv;
2425127675Sbms	    printf("\n\t      IS Neighbor: %s", isis_print_id(tptr, NODE_ID_LEN));
2426127675Sbms	    tptr+=(NODE_ID_LEN);
2427127675Sbms	    tmp-=(NODE_ID_LEN);
2428127675Sbms
2429147904Ssam	    if (tmp < 1)
2430147904Ssam	        break;
2431127675Sbms	    if (!TTEST2(*tptr, 1))
2432127675Sbms                goto trunctlv;
2433127675Sbms	    printf(", Flags: [%s]", ISIS_MASK_TLV_SHARED_RISK_GROUP(*tptr++) ? "numbered" : "unnumbered");
2434127675Sbms	    tmp--;
2435127675Sbms
2436162021Ssam	    if (tmp < sizeof(struct in_addr))
2437147904Ssam	        break;
2438162021Ssam	    if (!TTEST2(*tptr,sizeof(struct in_addr)))
2439127675Sbms                goto trunctlv;
2440127675Sbms	    printf("\n\t      IPv4 interface address: %s", ipaddr_string(tptr));
2441162021Ssam	    tptr+=sizeof(struct in_addr);
2442162021Ssam	    tmp-=sizeof(struct in_addr);
2443127675Sbms
2444162021Ssam	    if (tmp < sizeof(struct in_addr))
2445147904Ssam	        break;
2446162021Ssam	    if (!TTEST2(*tptr,sizeof(struct in_addr)))
2447127675Sbms                goto trunctlv;
2448127675Sbms	    printf("\n\t      IPv4 neighbor address: %s", ipaddr_string(tptr));
2449162021Ssam	    tptr+=sizeof(struct in_addr);
2450162021Ssam	    tmp-=sizeof(struct in_addr);
2451127675Sbms
2452147904Ssam	    while (tmp>=4) {
2453127675Sbms                if (!TTEST2(*tptr, 4))
2454127675Sbms                    goto trunctlv;
2455127675Sbms                printf("\n\t      Link-ID: 0x%08x", EXTRACT_32BITS(tptr));
2456127675Sbms                tptr+=4;
2457127675Sbms                tmp-=4;
2458127675Sbms	    }
2459127675Sbms	    break;
2460127675Sbms
2461146778Ssam	case ISIS_TLV_LSP:
2462127675Sbms	    tlv_lsp = (const struct isis_tlv_lsp *)tptr;
2463147904Ssam	    while(tmp>=sizeof(struct isis_tlv_lsp)) {
2464127675Sbms		if (!TTEST((tlv_lsp->lsp_id)[LSP_ID_LEN-1]))
246598527Sfenner		    goto trunctlv;
2466127675Sbms		printf("\n\t      lsp-id: %s",
2467127675Sbms                       isis_print_id(tlv_lsp->lsp_id, LSP_ID_LEN));
246898527Sfenner		if (!TTEST2(tlv_lsp->sequence_number, 4))
246998527Sfenner		    goto trunctlv;
2470127675Sbms		printf(", seq: 0x%08x",EXTRACT_32BITS(tlv_lsp->sequence_number));
247198527Sfenner		if (!TTEST2(tlv_lsp->remaining_lifetime, 2))
247298527Sfenner		    goto trunctlv;
2473127675Sbms		printf(", lifetime: %5ds",EXTRACT_16BITS(tlv_lsp->remaining_lifetime));
247498527Sfenner		if (!TTEST2(tlv_lsp->checksum, 2))
247598527Sfenner		    goto trunctlv;
2476127675Sbms		printf(", chksum: 0x%04x",EXTRACT_16BITS(tlv_lsp->checksum));
2477127675Sbms		tmp-=sizeof(struct isis_tlv_lsp);
247898527Sfenner		tlv_lsp++;
247998527Sfenner	    }
248098527Sfenner	    break;
248198527Sfenner
2482146778Ssam	case ISIS_TLV_CHECKSUM:
2483162021Ssam	    if (tmp < ISIS_TLV_CHECKSUM_MINLEN)
2484147904Ssam	        break;
2485162021Ssam	    if (!TTEST2(*tptr, ISIS_TLV_CHECKSUM_MINLEN))
248698527Sfenner		goto trunctlv;
2487127675Sbms	    printf("\n\t      checksum: 0x%04x ", EXTRACT_16BITS(tptr));
2488127675Sbms            /* do not attempt to verify the checksum if it is zero
2489127675Sbms             * most likely a HMAC-MD5 TLV is also present and
2490127675Sbms             * to avoid conflicts the checksum TLV is zeroed.
2491127675Sbms             * see rfc3358 for details
2492127675Sbms             */
2493127675Sbms            if (EXTRACT_16BITS(tptr) == 0)
2494127675Sbms                printf("(unverified)");
2495127675Sbms            else printf("(%s)", osi_cksum(optr, length) ? "incorrect" : "correct");
249698527Sfenner	    break;
249798527Sfenner
2498146778Ssam	case ISIS_TLV_MT_SUPPORTED:
2499162021Ssam            if (tmp < ISIS_TLV_MT_SUPPORTED_MINLEN)
2500162021Ssam                break;
2501127675Sbms	    while (tmp>1) {
2502127675Sbms		/* length can only be a multiple of 2, otherwise there is
250398527Sfenner		   something broken -> so decode down until length is 1 */
2504127675Sbms		if (tmp!=1) {
2505127675Sbms                    mt_len = isis_print_mtid(tptr, "\n\t      ");
2506127675Sbms                    if (mt_len == 0) /* did something go wrong ? */
2507127675Sbms                        goto trunctlv;
2508127675Sbms                    tptr+=mt_len;
2509127675Sbms                    tmp-=mt_len;
251098527Sfenner		} else {
2511127675Sbms		    printf("\n\t      malformed MT-ID");
251298527Sfenner		    break;
251398527Sfenner		}
251498527Sfenner	    }
251598527Sfenner	    break;
251698527Sfenner
2517146778Ssam	case ISIS_TLV_RESTART_SIGNALING:
2518162021Ssam            /* first attempt to decode the flags */
2519162021Ssam            if (tmp < ISIS_TLV_RESTART_SIGNALING_FLAGLEN)
2520162021Ssam                break;
2521162021Ssam            if (!TTEST2(*tptr, ISIS_TLV_RESTART_SIGNALING_FLAGLEN))
2522127675Sbms                goto trunctlv;
2523162021Ssam            printf("\n\t      Flags [%s]",
2524162021Ssam                   bittok2str(isis_restart_flag_values, "none", *tptr));
2525162021Ssam            tptr+=ISIS_TLV_RESTART_SIGNALING_FLAGLEN;
2526162021Ssam            tmp-=ISIS_TLV_RESTART_SIGNALING_FLAGLEN;
2527162021Ssam
2528162021Ssam            /* is there anything other than the flags field? */
2529162021Ssam            if (tmp == 0)
2530162021Ssam                break;
2531162021Ssam
2532162021Ssam            if (tmp < ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN)
2533162021Ssam                break;
2534162021Ssam            if (!TTEST2(*tptr, ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN))
2535162021Ssam                goto trunctlv;
2536162021Ssam
2537172686Smlaier            printf(", Remaining holding time %us", EXTRACT_16BITS(tptr));
2538162021Ssam            tptr+=ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN;
2539162021Ssam            tmp-=ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN;
2540162021Ssam
2541162021Ssam            /* is there an additional sysid field present ?*/
2542147904Ssam            if (tmp == SYSTEM_ID_LEN) {
2543147904Ssam                    if (!TTEST2(*tptr, SYSTEM_ID_LEN))
2544147904Ssam                            goto trunctlv;
2545147904Ssam                    printf(", for %s",isis_print_id(tptr,SYSTEM_ID_LEN));
2546162021Ssam            }
254798527Sfenner	    break;
254898527Sfenner
2549146778Ssam        case ISIS_TLV_IDRP_INFO:
2550162021Ssam	    if (tmp < ISIS_TLV_IDRP_INFO_MINLEN)
2551147904Ssam	        break;
2552162021Ssam            if (!TTEST2(*tptr, ISIS_TLV_IDRP_INFO_MINLEN))
2553127675Sbms                goto trunctlv;
2554127675Sbms            printf("\n\t      Inter-Domain Information Type: %s",
2555127675Sbms                   tok2str(isis_subtlv_idrp_values,
2556127675Sbms                           "Unknown (0x%02x)",
2557127675Sbms                           *tptr));
2558127675Sbms            switch (*tptr++) {
2559146778Ssam            case ISIS_SUBTLV_IDRP_ASN:
2560127675Sbms                if (!TTEST2(*tptr, 2)) /* fetch AS number */
2561127675Sbms                    goto trunctlv;
2562127675Sbms                printf("AS Number: %u",EXTRACT_16BITS(tptr));
2563127675Sbms                break;
2564146778Ssam            case ISIS_SUBTLV_IDRP_LOCAL:
2565146778Ssam            case ISIS_SUBTLV_IDRP_RES:
2566127675Sbms            default:
2567127675Sbms                if(!print_unknown_data(tptr,"\n\t      ",tlv_len-1))
2568127675Sbms                    return(0);
2569127675Sbms                break;
2570127675Sbms            }
2571127675Sbms            break;
2572127675Sbms
2573146778Ssam        case ISIS_TLV_LSP_BUFFERSIZE:
2574162021Ssam	    if (tmp < ISIS_TLV_LSP_BUFFERSIZE_MINLEN)
2575147904Ssam	        break;
2576162021Ssam            if (!TTEST2(*tptr, ISIS_TLV_LSP_BUFFERSIZE_MINLEN))
2577127675Sbms                goto trunctlv;
2578127675Sbms            printf("\n\t      LSP Buffersize: %u",EXTRACT_16BITS(tptr));
2579127675Sbms            break;
2580127675Sbms
2581146778Ssam        case ISIS_TLV_PART_DIS:
2582127675Sbms            while (tmp >= SYSTEM_ID_LEN) {
2583127675Sbms                if (!TTEST2(*tptr, SYSTEM_ID_LEN))
2584127675Sbms                    goto trunctlv;
2585127675Sbms                printf("\n\t      %s",isis_print_id(tptr,SYSTEM_ID_LEN));
2586127675Sbms                tptr+=SYSTEM_ID_LEN;
2587127675Sbms                tmp-=SYSTEM_ID_LEN;
2588127675Sbms            }
2589127675Sbms            break;
2590127675Sbms
2591146778Ssam        case ISIS_TLV_PREFIX_NEIGH:
2592147904Ssam	    if (tmp < sizeof(struct isis_metric_block))
2593147904Ssam	        break;
2594127675Sbms            if (!TTEST2(*tptr, sizeof(struct isis_metric_block)))
2595127675Sbms                goto trunctlv;
2596127675Sbms            printf("\n\t      Metric Block");
2597127675Sbms            isis_print_metric_block((const struct isis_metric_block *)tptr);
2598127675Sbms            tptr+=sizeof(struct isis_metric_block);
2599127675Sbms            tmp-=sizeof(struct isis_metric_block);
2600127675Sbms
2601127675Sbms            while(tmp>0) {
2602127675Sbms                if (!TTEST2(*tptr, 1))
2603127675Sbms                    goto trunctlv;
2604127675Sbms                prefix_len=*tptr++; /* read out prefix length in semioctets*/
2605147904Ssam                if (prefix_len < 2) {
2606147904Ssam                    printf("\n\t\tAddress: prefix length %u < 2", prefix_len);
2607147904Ssam                    break;
2608147904Ssam                }
2609127675Sbms                tmp--;
2610147904Ssam                if (tmp < prefix_len/2)
2611147904Ssam                    break;
2612127675Sbms                if (!TTEST2(*tptr, prefix_len/2))
2613127675Sbms                    goto trunctlv;
2614127675Sbms                printf("\n\t\tAddress: %s/%u",
2615146778Ssam                       isonsap_string(tptr,prefix_len/2),
2616127675Sbms                       prefix_len*4);
2617127675Sbms                tptr+=prefix_len/2;
2618127675Sbms                tmp-=prefix_len/2;
2619127675Sbms            }
2620127675Sbms            break;
2621127675Sbms
2622146778Ssam        case ISIS_TLV_IIH_SEQNR:
2623162021Ssam	    if (tmp < ISIS_TLV_IIH_SEQNR_MINLEN)
2624147904Ssam	        break;
2625162021Ssam            if (!TTEST2(*tptr, ISIS_TLV_IIH_SEQNR_MINLEN)) /* check if four bytes are on the wire */
2626127675Sbms                goto trunctlv;
2627127675Sbms            printf("\n\t      Sequence number: %u", EXTRACT_32BITS(tptr) );
2628127675Sbms            break;
2629127675Sbms
2630146778Ssam        case ISIS_TLV_VENDOR_PRIVATE:
2631162021Ssam	    if (tmp < ISIS_TLV_VENDOR_PRIVATE_MINLEN)
2632147904Ssam	        break;
2633162021Ssam            if (!TTEST2(*tptr, ISIS_TLV_VENDOR_PRIVATE_MINLEN)) /* check if enough byte for a full oui */
2634127675Sbms                goto trunctlv;
2635146778Ssam            vendor_id = EXTRACT_24BITS(tptr);
2636146778Ssam            printf("\n\t      Vendor: %s (%u)",
2637146778Ssam                   tok2str(oui_values,"Unknown",vendor_id),
2638146778Ssam                   vendor_id);
2639127675Sbms            tptr+=3;
2640127675Sbms            tmp-=3;
2641127675Sbms            if (tmp > 0) /* hexdump the rest */
2642127675Sbms                if(!print_unknown_data(tptr,"\n\t\t",tmp))
2643127675Sbms                    return(0);
2644127675Sbms            break;
2645127675Sbms            /*
2646127675Sbms             * FIXME those are the defined TLVs that lack a decoder
2647127675Sbms             * you are welcome to contribute code ;-)
2648127675Sbms             */
2649127675Sbms
2650146778Ssam        case ISIS_TLV_DECNET_PHASE4:
2651146778Ssam        case ISIS_TLV_LUCENT_PRIVATE:
2652146778Ssam        case ISIS_TLV_IPAUTH:
2653146778Ssam        case ISIS_TLV_NORTEL_PRIVATE1:
2654146778Ssam        case ISIS_TLV_NORTEL_PRIVATE2:
2655127675Sbms
265617688Spst	default:
2657127675Sbms            if (vflag <= 1) {
2658127675Sbms                if(!print_unknown_data(pptr,"\n\t\t",tlv_len))
2659127675Sbms                    return(0);
2660127675Sbms            }
266117688Spst	    break;
266217688Spst	}
2663127675Sbms        /* do we want to see an additionally hexdump ? */
2664127675Sbms        if (vflag> 1) {
2665127675Sbms	    if(!print_unknown_data(pptr,"\n\t      ",tlv_len))
2666127675Sbms	        return(0);
2667127675Sbms        }
266817688Spst
2669127675Sbms	pptr += tlv_len;
2670127675Sbms	packet_len -= tlv_len;
267117688Spst    }
267217688Spst
267317688Spst    if (packet_len != 0) {
2674127675Sbms	printf("\n\t      %u straggler bytes", packet_len);
267517688Spst    }
267698527Sfenner    return (1);
267798527Sfenner
2678127675Sbms trunc:
267998527Sfenner    fputs("[|isis]", stdout);
268098527Sfenner    return (1);
268198527Sfenner
2682127675Sbms trunctlv:
2683127675Sbms    printf("\n\t\t packet exceeded snapshot");
268417688Spst    return(1);
268517688Spst}
268617688Spst
268717751Spst/*
268817751Spst * Verify the checksum.  See 8473-1, Appendix C, section C.4.
268917751Spst */
269017751Spst
269117688Spststatic int
2692127675Sbmsosi_cksum(const u_int8_t *tptr, u_int len)
269317680Spst{
269417680Spst	int32_t c0 = 0, c1 = 0;
269517680Spst
269639300Sfenner	while ((int)--len >= 0) {
2697127675Sbms		c0 += *tptr++;
269817751Spst		c0 %= 255;
269917680Spst		c1 += c0;
270017680Spst		c1 %= 255;
270117680Spst	}
270217751Spst	return (c0 | c1);
270317680Spst}
2704146778Ssam
2705146778Ssam
2706146778Ssam/*
2707146778Ssam * Local Variables:
2708146778Ssam * c-style: whitesmith
2709146778Ssam * c-basic-offset: 8
2710146778Ssam * End:
2711146778Ssam */
2712