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$
2717680Spst */
2817680Spst
2917680Spst#ifndef lint
30127675Sbmsstatic const char rcsid[] _U_ =
31214478Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-isoclns.c,v 1.165 2008-08-16 13:38:15 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"
51214478Srpaulo#include "signature.h"
5217680Spst
5332149Spst/*
5432149Spst * IS-IS is defined in ISO 10589.  Look there for protocol definitions.
5532149Spst */
5632149Spst
5775118Sfenner#define SYSTEM_ID_LEN	ETHER_ADDR_LEN
58127675Sbms#define NODE_ID_LEN     SYSTEM_ID_LEN+1
59127675Sbms#define LSP_ID_LEN      SYSTEM_ID_LEN+2
60127675Sbms
6132149Spst#define ISIS_VERSION	1
62146778Ssam#define ESIS_VERSION	1
63146778Ssam#define CLNP_VERSION	1
6432149Spst
65146778Ssam#define ISIS_PDU_TYPE_MASK      0x1F
66146778Ssam#define ESIS_PDU_TYPE_MASK      0x1F
67146778Ssam#define CLNP_PDU_TYPE_MASK      0x1F
68146778Ssam#define CLNP_FLAG_MASK          0xE0
69146778Ssam#define ISIS_LAN_PRIORITY_MASK  0x7F
7032149Spst
71146778Ssam#define ISIS_PDU_L1_LAN_IIH	15
72146778Ssam#define ISIS_PDU_L2_LAN_IIH	16
73146778Ssam#define ISIS_PDU_PTP_IIH	17
74146778Ssam#define ISIS_PDU_L1_LSP       	18
75146778Ssam#define ISIS_PDU_L2_LSP       	20
76146778Ssam#define ISIS_PDU_L1_CSNP  	24
77146778Ssam#define ISIS_PDU_L2_CSNP  	25
78146778Ssam#define ISIS_PDU_L1_PSNP        26
79146778Ssam#define ISIS_PDU_L2_PSNP        27
80146778Ssam
81127675Sbmsstatic struct tok isis_pdu_values[] = {
82146778Ssam    { ISIS_PDU_L1_LAN_IIH,       "L1 Lan IIH"},
83146778Ssam    { ISIS_PDU_L2_LAN_IIH,       "L2 Lan IIH"},
84146778Ssam    { ISIS_PDU_PTP_IIH,          "p2p IIH"},
85146778Ssam    { ISIS_PDU_L1_LSP,           "L1 LSP"},
86146778Ssam    { ISIS_PDU_L2_LSP,           "L2 LSP"},
87146778Ssam    { ISIS_PDU_L1_CSNP,          "L1 CSNP"},
88146778Ssam    { ISIS_PDU_L2_CSNP,          "L2 CSNP"},
89146778Ssam    { ISIS_PDU_L1_PSNP,          "L1 PSNP"},
90146778Ssam    { ISIS_PDU_L2_PSNP,          "L2 PSNP"},
91127675Sbms    { 0, NULL}
92127675Sbms};
9398527Sfenner
9432149Spst/*
9532149Spst * A TLV is a tuple of a type, length and a value and is normally used for
9632149Spst * encoding information in all sorts of places.  This is an enumeration of
9732149Spst * the well known types.
98127675Sbms *
99127675Sbms * list taken from rfc3359 plus some memory from veterans ;-)
10032149Spst */
10132149Spst
102146778Ssam#define ISIS_TLV_AREA_ADDR           1   /* iso10589 */
103146778Ssam#define ISIS_TLV_IS_REACH            2   /* iso10589 */
104146778Ssam#define ISIS_TLV_ESNEIGH             3   /* iso10589 */
105146778Ssam#define ISIS_TLV_PART_DIS            4   /* iso10589 */
106146778Ssam#define ISIS_TLV_PREFIX_NEIGH        5   /* iso10589 */
107146778Ssam#define ISIS_TLV_ISNEIGH             6   /* iso10589 */
108146778Ssam#define ISIS_TLV_ISNEIGH_VARLEN      7   /* iso10589 */
109146778Ssam#define ISIS_TLV_PADDING             8   /* iso10589 */
110146778Ssam#define ISIS_TLV_LSP                 9   /* iso10589 */
111146778Ssam#define ISIS_TLV_AUTH                10  /* iso10589, rfc3567 */
112146778Ssam#define ISIS_TLV_CHECKSUM            12  /* rfc3358 */
113162021Ssam#define ISIS_TLV_CHECKSUM_MINLEN 2
114146778Ssam#define ISIS_TLV_LSP_BUFFERSIZE      14  /* iso10589 rev2 */
115162021Ssam#define ISIS_TLV_LSP_BUFFERSIZE_MINLEN 2
116146778Ssam#define ISIS_TLV_EXT_IS_REACH        22  /* draft-ietf-isis-traffic-05 */
117146778Ssam#define ISIS_TLV_IS_ALIAS_ID         24  /* draft-ietf-isis-ext-lsp-frags-02 */
118146778Ssam#define ISIS_TLV_DECNET_PHASE4       42
119146778Ssam#define ISIS_TLV_LUCENT_PRIVATE      66
120146778Ssam#define ISIS_TLV_INT_IP_REACH        128 /* rfc1195, rfc2966 */
121146778Ssam#define ISIS_TLV_PROTOCOLS           129 /* rfc1195 */
122146778Ssam#define ISIS_TLV_EXT_IP_REACH        130 /* rfc1195, rfc2966 */
123146778Ssam#define ISIS_TLV_IDRP_INFO           131 /* rfc1195 */
124162021Ssam#define ISIS_TLV_IDRP_INFO_MINLEN      1
125146778Ssam#define ISIS_TLV_IPADDR              132 /* rfc1195 */
126146778Ssam#define ISIS_TLV_IPAUTH              133 /* rfc1195 */
127146778Ssam#define ISIS_TLV_TE_ROUTER_ID        134 /* draft-ietf-isis-traffic-05 */
128146778Ssam#define ISIS_TLV_EXTD_IP_REACH       135 /* draft-ietf-isis-traffic-05 */
129146778Ssam#define ISIS_TLV_HOSTNAME            137 /* rfc2763 */
130146778Ssam#define ISIS_TLV_SHARED_RISK_GROUP   138 /* draft-ietf-isis-gmpls-extensions */
131252283Sdelphij#define ISIS_TLV_MT_PORT_CAP         143 /* rfc6165 */
132252283Sdelphij#define ISIS_TLV_MT_CAPABILITY       144 /* rfc6329 */
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"},
177252283Sdelphij    { ISIS_TLV_MT_PORT_CAP,        "Multi-Topology-Aware Port Capability"},
178252283Sdelphij    { ISIS_TLV_MT_CAPABILITY,      "Multi-Topology Capability"},
179146778Ssam    { ISIS_TLV_NORTEL_PRIVATE1,    "Nortel Proprietary"},
180146778Ssam    { ISIS_TLV_NORTEL_PRIVATE2,    "Nortel Proprietary"},
181146778Ssam    { ISIS_TLV_HOSTNAME,           "Hostname"},
182146778Ssam    { ISIS_TLV_RESTART_SIGNALING,  "Restart Signaling"},
183146778Ssam    { ISIS_TLV_MT_IS_REACH,        "Multi Topology IS Reachability"},
184146778Ssam    { ISIS_TLV_MT_SUPPORTED,       "Multi Topology"},
185146778Ssam    { ISIS_TLV_IP6ADDR,            "IPv6 Interface address(es)"},
186146778Ssam    { ISIS_TLV_MT_IP_REACH,        "Multi-Topology IPv4 Reachability"},
187146778Ssam    { ISIS_TLV_IP6_REACH,          "IPv6 reachability"},
188146778Ssam    { ISIS_TLV_MT_IP6_REACH,       "Multi-Topology IP6 Reachability"},
189146778Ssam    { ISIS_TLV_PTP_ADJ,            "Point-to-point Adjacency State"},
190146778Ssam    { ISIS_TLV_IIH_SEQNR,          "Hello PDU Sequence Number"},
191146778Ssam    { ISIS_TLV_VENDOR_PRIVATE,     "Vendor Private"},
192127675Sbms    { 0, NULL }
193127675Sbms};
19498527Sfenner
195146778Ssam#define ESIS_OPTION_PROTOCOLS        129
196146778Ssam#define ESIS_OPTION_QOS_MAINTENANCE  195 /* iso9542 */
197146778Ssam#define ESIS_OPTION_SECURITY         197 /* iso9542 */
198146778Ssam#define ESIS_OPTION_ES_CONF_TIME     198 /* iso9542 */
199146778Ssam#define ESIS_OPTION_PRIORITY         205 /* iso9542 */
200146778Ssam#define ESIS_OPTION_ADDRESS_MASK     225 /* iso9542 */
201146778Ssam#define ESIS_OPTION_SNPA_MASK        226 /* iso9542 */
20298527Sfenner
203146778Ssamstatic struct tok esis_option_values[] = {
204146778Ssam    { ESIS_OPTION_PROTOCOLS,       "Protocols supported"},
205146778Ssam    { ESIS_OPTION_QOS_MAINTENANCE, "QoS Maintenance" },
206146778Ssam    { ESIS_OPTION_SECURITY,        "Security" },
207146778Ssam    { ESIS_OPTION_ES_CONF_TIME,    "ES Configuration Time" },
208146778Ssam    { ESIS_OPTION_PRIORITY,        "Priority" },
209146778Ssam    { ESIS_OPTION_ADDRESS_MASK,    "Addressk Mask" },
210146778Ssam    { ESIS_OPTION_SNPA_MASK,       "SNPA Mask" },
211146778Ssam    { 0, NULL }
212146778Ssam};
213146778Ssam
214146778Ssam#define CLNP_OPTION_DISCARD_REASON   193
215146778Ssam#define CLNP_OPTION_QOS_MAINTENANCE  195 /* iso8473 */
216147904Ssam#define CLNP_OPTION_SECURITY         197 /* iso8473 */
217147904Ssam#define CLNP_OPTION_SOURCE_ROUTING   200 /* iso8473 */
218147904Ssam#define CLNP_OPTION_ROUTE_RECORDING  203 /* iso8473 */
219147904Ssam#define CLNP_OPTION_PADDING          204 /* iso8473 */
220146778Ssam#define CLNP_OPTION_PRIORITY         205 /* iso8473 */
221146778Ssam
222146778Ssamstatic struct tok clnp_option_values[] = {
223146778Ssam    { CLNP_OPTION_DISCARD_REASON,  "Discard Reason"},
224146778Ssam    { CLNP_OPTION_PRIORITY,        "Priority"},
225146778Ssam    { CLNP_OPTION_QOS_MAINTENANCE, "QoS Maintenance"},
226147904Ssam    { CLNP_OPTION_SECURITY, "Security"},
227147904Ssam    { CLNP_OPTION_SOURCE_ROUTING, "Source Routing"},
228147904Ssam    { CLNP_OPTION_ROUTE_RECORDING, "Route Recording"},
229147904Ssam    { CLNP_OPTION_PADDING, "Padding"},
230146778Ssam    { 0, NULL }
231146778Ssam};
232146778Ssam
233146778Ssamstatic struct tok clnp_option_rfd_class_values[] = {
234146778Ssam    { 0x0, "General"},
235146778Ssam    { 0x8, "Address"},
236146778Ssam    { 0x9, "Source Routeing"},
237146778Ssam    { 0xa, "Lifetime"},
238146778Ssam    { 0xb, "PDU Discarded"},
239146778Ssam    { 0xc, "Reassembly"},
240146778Ssam    { 0, NULL }
241146778Ssam};
242146778Ssam
243146778Ssamstatic struct tok clnp_option_rfd_general_values[] = {
244146778Ssam    { 0x0, "Reason not specified"},
245146778Ssam    { 0x1, "Protocol procedure error"},
246146778Ssam    { 0x2, "Incorrect checksum"},
247146778Ssam    { 0x3, "PDU discarded due to congestion"},
248146778Ssam    { 0x4, "Header syntax error (cannot be parsed)"},
249146778Ssam    { 0x5, "Segmentation needed but not permitted"},
250146778Ssam    { 0x6, "Incomplete PDU received"},
251146778Ssam    { 0x7, "Duplicate option"},
252146778Ssam    { 0, NULL }
253146778Ssam};
254146778Ssam
255146778Ssamstatic struct tok clnp_option_rfd_address_values[] = {
256146778Ssam    { 0x0, "Destination address unreachable"},
257146778Ssam    { 0x1, "Destination address unknown"},
258146778Ssam    { 0, NULL }
259146778Ssam};
260146778Ssam
261146778Ssamstatic struct tok clnp_option_rfd_source_routeing_values[] = {
262146778Ssam    { 0x0, "Unspecified source routeing error"},
263146778Ssam    { 0x1, "Syntax error in source routeing field"},
264146778Ssam    { 0x2, "Unknown address in source routeing field"},
265146778Ssam    { 0x3, "Path not acceptable"},
266146778Ssam    { 0, NULL }
267146778Ssam};
268146778Ssam
269146778Ssamstatic struct tok clnp_option_rfd_lifetime_values[] = {
270146778Ssam    { 0x0, "Lifetime expired while data unit in transit"},
271146778Ssam    { 0x1, "Lifetime expired during reassembly"},
272146778Ssam    { 0, NULL }
273146778Ssam};
274146778Ssam
275146778Ssamstatic struct tok clnp_option_rfd_pdu_discard_values[] = {
276146778Ssam    { 0x0, "Unsupported option not specified"},
277146778Ssam    { 0x1, "Unsupported protocol version"},
278146778Ssam    { 0x2, "Unsupported security option"},
279146778Ssam    { 0x3, "Unsupported source routeing option"},
280146778Ssam    { 0x4, "Unsupported recording of route option"},
281146778Ssam    { 0, NULL }
282146778Ssam};
283146778Ssam
284146778Ssamstatic struct tok clnp_option_rfd_reassembly_values[] = {
285146778Ssam    { 0x0, "Reassembly interference"},
286146778Ssam    { 0, NULL }
287146778Ssam};
288146778Ssam
289146778Ssam/* array of 16 error-classes */
290146778Ssamstatic struct tok *clnp_option_rfd_error_class[] = {
291146778Ssam    clnp_option_rfd_general_values,
292146778Ssam    NULL,
293146778Ssam    NULL,
294146778Ssam    NULL,
295146778Ssam    NULL,
296146778Ssam    NULL,
297146778Ssam    NULL,
298146778Ssam    NULL,
299146778Ssam    clnp_option_rfd_address_values,
300146778Ssam    clnp_option_rfd_source_routeing_values,
301146778Ssam    clnp_option_rfd_lifetime_values,
302146778Ssam    clnp_option_rfd_pdu_discard_values,
303146778Ssam    clnp_option_rfd_reassembly_values,
304146778Ssam    NULL,
305146778Ssam    NULL,
306146778Ssam    NULL
307146778Ssam};
308146778Ssam
309147904Ssam#define CLNP_OPTION_OPTION_QOS_MASK 0x3f
310147904Ssam#define CLNP_OPTION_SCOPE_MASK      0xc0
311147904Ssam#define CLNP_OPTION_SCOPE_SA_SPEC   0x40
312147904Ssam#define CLNP_OPTION_SCOPE_DA_SPEC   0x80
313147904Ssam#define CLNP_OPTION_SCOPE_GLOBAL    0xc0
314146778Ssam
315147904Ssamstatic struct tok clnp_option_scope_values[] = {
316147904Ssam    { CLNP_OPTION_SCOPE_SA_SPEC, "Source Address Specific"},
317147904Ssam    { CLNP_OPTION_SCOPE_DA_SPEC, "Destination Address Specific"},
318147904Ssam    { CLNP_OPTION_SCOPE_GLOBAL, "Globally unique"},
319147904Ssam    { 0, NULL }
320147904Ssam};
321147904Ssam
322147904Ssamstatic struct tok clnp_option_sr_rr_values[] = {
323147904Ssam    { 0x0, "partial"},
324147904Ssam    { 0x1, "complete"},
325147904Ssam    { 0, NULL }
326147904Ssam};
327147904Ssam
328147904Ssamstatic struct tok clnp_option_sr_rr_string_values[] = {
329147904Ssam    { CLNP_OPTION_SOURCE_ROUTING, "source routing"},
330147904Ssam    { CLNP_OPTION_ROUTE_RECORDING, "recording of route in progress"},
331147904Ssam    { 0, NULL }
332147904Ssam};
333147904Ssam
334147904Ssamstatic struct tok clnp_option_qos_global_values[] = {
335147904Ssam    { 0x20, "reserved"},
336147904Ssam    { 0x10, "sequencing vs. delay"},
337147904Ssam    { 0x08, "congested"},
338147904Ssam    { 0x04, "delay vs. cost"},
339147904Ssam    { 0x02, "error vs. delay"},
340147904Ssam    { 0x01, "error vs. cost"},
341147904Ssam    { 0, NULL }
342147904Ssam};
343147904Ssam
344146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP           3 /* draft-ietf-isis-traffic-05 */
345190207Srpaulo#define ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID  4 /* rfc4205 */
346146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID        5 /* draft-ietf-isis-traffic-05 */
347146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR        6 /* draft-ietf-isis-traffic-05 */
348146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR    8 /* draft-ietf-isis-traffic-05 */
349146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW           9 /* draft-ietf-isis-traffic-05 */
350146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW        10 /* draft-ietf-isis-traffic-05 */
351162021Ssam#define ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW        11 /* rfc4124 */
352162021Ssam#define ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS_OLD   12 /* draft-ietf-tewg-diff-te-proto-06 */
353146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC            18 /* draft-ietf-isis-traffic-05 */
354190207Srpaulo#define ISIS_SUBTLV_EXT_IS_REACH_LINK_ATTRIBUTE       19 /* draft-ietf-isis-link-attr-01 */
355190207Srpaulo#define ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE 20 /* rfc4205 */
356190207Srpaulo#define ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR    21 /* rfc4205 */
357162021Ssam#define ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS       22 /* rfc4124 */
358146778Ssam
359252283Sdelphij#define ISIS_SUBTLV_SPB_METRIC                        29 /* rfc6329 */
360252283Sdelphij
361127675Sbmsstatic struct tok isis_ext_is_reach_subtlv_values[] = {
362146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP,            "Administrative groups" },
363146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID,   "Link Local/Remote Identifier" },
364146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID,         "Link Remote Identifier" },
365146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR,         "IPv4 interface address" },
366146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR,     "IPv4 neighbor address" },
367146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW,            "Maximum link bandwidth" },
368146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW,          "Reservable link bandwidth" },
369146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW,          "Unreserved bandwidth" },
370146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC,              "Traffic Engineering Metric" },
371190207Srpaulo    { ISIS_SUBTLV_EXT_IS_REACH_LINK_ATTRIBUTE,         "Link Attribute" },
372146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE,   "Link Protection Type" },
373146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR,      "Interface Switching Capability" },
374162021Ssam    { ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS_OLD,     "Bandwidth Constraints (old)" },
375162021Ssam    { ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS,         "Bandwidth Constraints" },
376252283Sdelphij    { ISIS_SUBTLV_SPB_METRIC,                          "SPB Metric" },
377146778Ssam    { 250,                                             "Reserved for cisco specific extensions" },
378146778Ssam    { 251,                                             "Reserved for cisco specific extensions" },
379146778Ssam    { 252,                                             "Reserved for cisco specific extensions" },
380146778Ssam    { 253,                                             "Reserved for cisco specific extensions" },
381146778Ssam    { 254,                                             "Reserved for cisco specific extensions" },
382146778Ssam    { 255,                                             "Reserved for future expansion" },
383127675Sbms    { 0, NULL }
384127675Sbms};
38598527Sfenner
386146778Ssam#define ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32          1 /* draft-ietf-isis-admin-tags-01 */
387146778Ssam#define ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64          2 /* draft-ietf-isis-admin-tags-01 */
388146778Ssam#define ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR  117 /* draft-ietf-isis-wg-multi-topology-05 */
389127675Sbms
390127675Sbmsstatic struct tok isis_ext_ip_reach_subtlv_values[] = {
391146778Ssam    { ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32,           "32-Bit Administrative tag" },
392146778Ssam    { ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64,           "64-Bit Administrative tag" },
393146778Ssam    { ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR,     "Management Prefix Color" },
394127675Sbms    { 0, NULL }
395127675Sbms};
396127675Sbms
397190207Srpaulostatic struct tok isis_subtlv_link_attribute_values[] = {
398190207Srpaulo    { 0x01, "Local Protection Available" },
399190207Srpaulo    { 0x02, "Link excluded from local protection path" },
400190207Srpaulo    { 0x04, "Local maintenance required"},
401190207Srpaulo    { 0, NULL }
402190207Srpaulo};
403190207Srpaulo
404146778Ssam#define ISIS_SUBTLV_AUTH_SIMPLE        1
405236192Sdelphij#define ISIS_SUBTLV_AUTH_GENERIC       3 /* rfc 5310 */
406146778Ssam#define ISIS_SUBTLV_AUTH_MD5          54
407146778Ssam#define ISIS_SUBTLV_AUTH_MD5_LEN      16
408146778Ssam#define ISIS_SUBTLV_AUTH_PRIVATE     255
409127675Sbms
410127675Sbmsstatic struct tok isis_subtlv_auth_values[] = {
411146778Ssam    { ISIS_SUBTLV_AUTH_SIMPLE,	"simple text password"},
412236192Sdelphij    { ISIS_SUBTLV_AUTH_GENERIC, "Generic Crypto key-id"},
413146778Ssam    { ISIS_SUBTLV_AUTH_MD5,	"HMAC-MD5 password"},
414146778Ssam    { ISIS_SUBTLV_AUTH_PRIVATE,	"Routing Domain private password"},
415127675Sbms    { 0, NULL }
416127675Sbms};
417127675Sbms
418146778Ssam#define ISIS_SUBTLV_IDRP_RES           0
419146778Ssam#define ISIS_SUBTLV_IDRP_LOCAL         1
420146778Ssam#define ISIS_SUBTLV_IDRP_ASN           2
421127675Sbms
422127675Sbmsstatic struct tok isis_subtlv_idrp_values[] = {
423146778Ssam    { ISIS_SUBTLV_IDRP_RES,         "Reserved"},
424146778Ssam    { ISIS_SUBTLV_IDRP_LOCAL,       "Routing-Domain Specific"},
425146778Ssam    { ISIS_SUBTLV_IDRP_ASN,         "AS Number Tag"},
426127675Sbms    { 0, NULL}
427127675Sbms};
428127675Sbms
429252283Sdelphij#define ISIS_SUBTLV_SPB_MCID          4
430252283Sdelphij#define ISIS_SUBTLV_SPB_DIGEST        5
431252283Sdelphij#define ISIS_SUBTLV_SPB_BVID          6
432252283Sdelphij
433252283Sdelphij#define ISIS_SUBTLV_SPB_INSTANCE      1
434252283Sdelphij#define ISIS_SUBTLV_SPBM_SI           3
435252283Sdelphij
436252283Sdelphij#define ISIS_SPB_MCID_LEN                         51
437252283Sdelphij#define ISIS_SUBTLV_SPB_MCID_MIN_LEN              102
438252283Sdelphij#define ISIS_SUBTLV_SPB_DIGEST_MIN_LEN            33
439252283Sdelphij#define ISIS_SUBTLV_SPB_BVID_MIN_LEN              6
440252283Sdelphij#define ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN          19
441252283Sdelphij#define ISIS_SUBTLV_SPB_INSTANCE_VLAN_TUPLE_LEN   8
442252283Sdelphij
443252283Sdelphijstatic struct tok isis_mt_port_cap_subtlv_values[] = {
444252283Sdelphij    { ISIS_SUBTLV_SPB_MCID,           "SPB MCID" },
445252283Sdelphij    { ISIS_SUBTLV_SPB_DIGEST,         "SPB Digest" },
446252283Sdelphij    { ISIS_SUBTLV_SPB_BVID,           "SPB BVID" },
447252283Sdelphij    { 0, NULL }
448252283Sdelphij};
449252283Sdelphij
450252283Sdelphijstatic struct tok isis_mt_capability_subtlv_values[] = {
451252283Sdelphij    { ISIS_SUBTLV_SPB_INSTANCE,      "SPB Instance" },
452252283Sdelphij    { ISIS_SUBTLV_SPBM_SI,      "SPBM Service Identifier and Unicast Address" },
453252283Sdelphij    { 0, NULL }
454252283Sdelphij};
455252283Sdelphij
456252283Sdelphijstruct isis_spb_mcid {
457252283Sdelphij  u_int8_t  format_id;
458252283Sdelphij  u_int8_t  name[32];
459252283Sdelphij  u_int8_t  revision_lvl[2];
460252283Sdelphij  u_int8_t  digest[16];
461252283Sdelphij};
462252283Sdelphij
463252283Sdelphijstruct isis_subtlv_spb_mcid {
464252283Sdelphij  struct isis_spb_mcid mcid;
465252283Sdelphij  struct isis_spb_mcid aux_mcid;
466252283Sdelphij};
467252283Sdelphij
468252283Sdelphijstruct isis_subtlv_spb_instance {
469252283Sdelphij  u_int8_t cist_root_id[8];
470252283Sdelphij  u_int8_t cist_external_root_path_cost[4];
471252283Sdelphij  u_int8_t bridge_priority[2];
472252283Sdelphij  u_int8_t spsourceid[4];
473252283Sdelphij  u_int8_t no_of_trees;
474252283Sdelphij};
475252283Sdelphij
476146778Ssam#define CLNP_SEGMENT_PART  0x80
477146778Ssam#define CLNP_MORE_SEGMENTS 0x40
478146778Ssam#define CLNP_REQUEST_ER    0x20
479127675Sbms
480146778Ssamstatic struct tok clnp_flag_values[] = {
481146778Ssam    { CLNP_SEGMENT_PART, "Segmentation permitted"},
482146778Ssam    { CLNP_MORE_SEGMENTS, "more Segments"},
483146778Ssam    { CLNP_REQUEST_ER, "request Error Report"},
484146778Ssam    { 0, NULL}
485146778Ssam};
486146778Ssam
48798527Sfenner#define ISIS_MASK_LSP_OL_BIT(x)            ((x)&0x4)
48898527Sfenner#define ISIS_MASK_LSP_ISTYPE_BITS(x)       ((x)&0x3)
48998527Sfenner#define ISIS_MASK_LSP_PARTITION_BIT(x)     ((x)&0x80)
49098527Sfenner#define ISIS_MASK_LSP_ATT_BITS(x)          ((x)&0x78)
49198527Sfenner#define ISIS_MASK_LSP_ATT_ERROR_BIT(x)     ((x)&0x40)
49298527Sfenner#define ISIS_MASK_LSP_ATT_EXPENSE_BIT(x)   ((x)&0x20)
49398527Sfenner#define ISIS_MASK_LSP_ATT_DELAY_BIT(x)     ((x)&0x10)
49498527Sfenner#define ISIS_MASK_LSP_ATT_DEFAULT_BIT(x)   ((x)&0x8)
49598527Sfenner
496127675Sbms#define ISIS_MASK_MTID(x)                  ((x)&0x0fff)
497127675Sbms#define ISIS_MASK_MTFLAGS(x)               ((x)&0xf000)
49898527Sfenner
499127675Sbmsstatic struct tok isis_mt_flag_values[] = {
500236192Sdelphij    { 0x4000,                  "ATT bit set"},
501236192Sdelphij    { 0x8000,                  "Overload bit set"},
502127675Sbms    { 0, NULL}
503127675Sbms};
50498527Sfenner
505127675Sbms#define ISIS_MASK_TLV_EXTD_IP_UPDOWN(x)     ((x)&0x80)
506127675Sbms#define ISIS_MASK_TLV_EXTD_IP_SUBTLV(x)     ((x)&0x40)
50798527Sfenner
508127675Sbms#define ISIS_MASK_TLV_EXTD_IP6_IE(x)        ((x)&0x40)
509127675Sbms#define ISIS_MASK_TLV_EXTD_IP6_SUBTLV(x)    ((x)&0x20)
510127675Sbms
51198527Sfenner#define ISIS_LSP_TLV_METRIC_SUPPORTED(x)   ((x)&0x80)
51298527Sfenner#define ISIS_LSP_TLV_METRIC_IE(x)          ((x)&0x40)
51398527Sfenner#define ISIS_LSP_TLV_METRIC_UPDOWN(x)      ((x)&0x80)
51498527Sfenner#define ISIS_LSP_TLV_METRIC_VALUE(x)	   ((x)&0x3f)
51598527Sfenner
516127675Sbms#define ISIS_MASK_TLV_SHARED_RISK_GROUP(x) ((x)&0x1)
517127675Sbms
518127675Sbmsstatic struct tok isis_mt_values[] = {
519127675Sbms    { 0,    "IPv4 unicast"},
520127675Sbms    { 1,    "In-Band Management"},
521127675Sbms    { 2,    "IPv6 unicast"},
522127675Sbms    { 3,    "Multicast"},
523127675Sbms    { 4095, "Development, Experimental or Proprietary"},
524127675Sbms    { 0, NULL }
525127675Sbms};
526127675Sbms
527127675Sbmsstatic struct tok isis_iih_circuit_type_values[] = {
528127675Sbms    { 1,    "Level 1 only"},
529127675Sbms    { 2,    "Level 2 only"},
530127675Sbms    { 3,    "Level 1, Level 2"},
531127675Sbms    { 0, NULL}
532127675Sbms};
533127675Sbms
53498527Sfenner#define ISIS_LSP_TYPE_UNUSED0   0
53598527Sfenner#define ISIS_LSP_TYPE_LEVEL_1   1
53698527Sfenner#define ISIS_LSP_TYPE_UNUSED2   2
53798527Sfenner#define ISIS_LSP_TYPE_LEVEL_2   3
53898527Sfenner
53998527Sfennerstatic struct tok isis_lsp_istype_values[] = {
540127675Sbms    { ISIS_LSP_TYPE_UNUSED0,	"Unused 0x0 (invalid)"},
541127675Sbms    { ISIS_LSP_TYPE_LEVEL_1,	"L1 IS"},
542127675Sbms    { ISIS_LSP_TYPE_UNUSED2,	"Unused 0x2 (invalid)"},
543172686Smlaier    { ISIS_LSP_TYPE_LEVEL_2,	"L2 IS"},
544127675Sbms    { 0, NULL }
54598527Sfenner};
54698527Sfenner
54732149Spst/*
54832149Spst * Katz's point to point adjacency TLV uses codes to tell us the state of
54932149Spst * the remote adjacency.  Enumerate them.
55032149Spst */
55132149Spst
55232149Spst#define ISIS_PTP_ADJ_UP   0
55332149Spst#define ISIS_PTP_ADJ_INIT 1
55432149Spst#define ISIS_PTP_ADJ_DOWN 2
55532149Spst
55698527Sfennerstatic struct tok isis_ptp_adjancey_values[] = {
557127675Sbms    { ISIS_PTP_ADJ_UP,    "Up" },
558127675Sbms    { ISIS_PTP_ADJ_INIT,  "Initializing" },
559127675Sbms    { ISIS_PTP_ADJ_DOWN,  "Down" },
560127675Sbms    { 0, NULL}
56132149Spst};
56232149Spst
56398527Sfennerstruct isis_tlv_ptp_adj {
564127675Sbms    u_int8_t adjacency_state;
565127675Sbms    u_int8_t extd_local_circuit_id[4];
566127675Sbms    u_int8_t neighbor_sysid[SYSTEM_ID_LEN];
567127675Sbms    u_int8_t neighbor_extd_local_circuit_id[4];
56832149Spst};
56932149Spst
570190207Srpaulostatic void osi_print_cksum(const u_int8_t *pptr, u_int16_t checksum,
571190207Srpaulo                            u_int checksum_offset, u_int length);
572146778Ssamstatic int clnp_print(const u_int8_t *, u_int);
573127675Sbmsstatic void esis_print(const u_int8_t *, u_int);
574127675Sbmsstatic int isis_print(const u_int8_t *, u_int);
575127675Sbms
576127675Sbmsstruct isis_metric_block {
577127675Sbms    u_int8_t metric_default;
578127675Sbms    u_int8_t metric_delay;
579127675Sbms    u_int8_t metric_expense;
580127675Sbms    u_int8_t metric_error;
58198527Sfenner};
58298527Sfenner
58398527Sfennerstruct isis_tlv_is_reach {
584127675Sbms    struct isis_metric_block isis_metric_block;
585127675Sbms    u_int8_t neighbor_nodeid[NODE_ID_LEN];
58698527Sfenner};
58798527Sfenner
588127675Sbmsstruct isis_tlv_es_reach {
589127675Sbms    struct isis_metric_block isis_metric_block;
590127675Sbms    u_int8_t neighbor_sysid[SYSTEM_ID_LEN];
591127675Sbms};
59298527Sfenner
593127675Sbmsstruct isis_tlv_ip_reach {
594127675Sbms    struct isis_metric_block isis_metric_block;
595127675Sbms    u_int8_t prefix[4];
596127675Sbms    u_int8_t mask[4];
597127675Sbms};
598127675Sbms
599127675Sbmsstatic struct tok isis_is_reach_virtual_values[] = {
600127675Sbms    { 0,    "IsNotVirtual"},
601127675Sbms    { 1,    "IsVirtual"},
602127675Sbms    { 0, NULL }
603127675Sbms};
604127675Sbms
605127675Sbmsstatic struct tok isis_restart_flag_values[] = {
606127675Sbms    { 0x1,  "Restart Request"},
607127675Sbms    { 0x2,  "Restart Acknowledgement"},
608147904Ssam    { 0x4,  "Suppress adjacency advertisement"},
609127675Sbms    { 0, NULL }
610127675Sbms};
611127675Sbms
61232149Spststruct isis_common_header {
613127675Sbms    u_int8_t nlpid;
614127675Sbms    u_int8_t fixed_len;
615127675Sbms    u_int8_t version;			/* Protocol version */
616127675Sbms    u_int8_t id_length;
617127675Sbms    u_int8_t pdu_type;		        /* 3 MSbits are reserved */
618127675Sbms    u_int8_t pdu_version;		/* Packet format version */
619127675Sbms    u_int8_t reserved;
620127675Sbms    u_int8_t max_area;
62132149Spst};
62232149Spst
62398527Sfennerstruct isis_iih_lan_header {
624127675Sbms    u_int8_t circuit_type;
625127675Sbms    u_int8_t source_id[SYSTEM_ID_LEN];
626127675Sbms    u_int8_t holding_time[2];
627127675Sbms    u_int8_t pdu_len[2];
628127675Sbms    u_int8_t priority;
629127675Sbms    u_int8_t lan_id[NODE_ID_LEN];
63032149Spst};
63198527Sfenner
63298527Sfennerstruct isis_iih_ptp_header {
633127675Sbms    u_int8_t circuit_type;
634127675Sbms    u_int8_t source_id[SYSTEM_ID_LEN];
635127675Sbms    u_int8_t holding_time[2];
636127675Sbms    u_int8_t pdu_len[2];
637127675Sbms    u_int8_t circuit_id;
63832149Spst};
63932149Spst
64098527Sfennerstruct isis_lsp_header {
641127675Sbms    u_int8_t pdu_len[2];
642127675Sbms    u_int8_t remaining_lifetime[2];
643127675Sbms    u_int8_t lsp_id[LSP_ID_LEN];
644127675Sbms    u_int8_t sequence_number[4];
645127675Sbms    u_int8_t checksum[2];
646127675Sbms    u_int8_t typeblock;
64732149Spst};
64832149Spst
64998527Sfennerstruct isis_csnp_header {
650127675Sbms    u_int8_t pdu_len[2];
651127675Sbms    u_int8_t source_id[NODE_ID_LEN];
652127675Sbms    u_int8_t start_lsp_id[LSP_ID_LEN];
653127675Sbms    u_int8_t end_lsp_id[LSP_ID_LEN];
65498527Sfenner};
65532149Spst
65698527Sfennerstruct isis_psnp_header {
657127675Sbms    u_int8_t pdu_len[2];
658127675Sbms    u_int8_t source_id[NODE_ID_LEN];
65998527Sfenner};
66032149Spst
66198527Sfennerstruct isis_tlv_lsp {
662127675Sbms    u_int8_t remaining_lifetime[2];
663127675Sbms    u_int8_t lsp_id[LSP_ID_LEN];
664127675Sbms    u_int8_t sequence_number[4];
665127675Sbms    u_int8_t checksum[2];
66698527Sfenner};
667127675Sbms
66898527Sfenner#define ISIS_COMMON_HEADER_SIZE (sizeof(struct isis_common_header))
66998527Sfenner#define ISIS_IIH_LAN_HEADER_SIZE (sizeof(struct isis_iih_lan_header))
67098527Sfenner#define ISIS_IIH_PTP_HEADER_SIZE (sizeof(struct isis_iih_ptp_header))
67198527Sfenner#define ISIS_LSP_HEADER_SIZE (sizeof(struct isis_lsp_header))
67298527Sfenner#define ISIS_CSNP_HEADER_SIZE (sizeof(struct isis_csnp_header))
67398527Sfenner#define ISIS_PSNP_HEADER_SIZE (sizeof(struct isis_psnp_header))
67432149Spst
675127675Sbmsvoid isoclns_print(const u_int8_t *p, u_int length, u_int caplen)
67617680Spst{
677146778Ssam        if (caplen <= 1) { /* enough bytes on the wire ? */
678146778Ssam            printf("|OSI");
679146778Ssam            return;
680146778Ssam        }
68117680Spst
682146778Ssam        if (eflag)
683146778Ssam            printf("OSI NLPID %s (0x%02x): ",
684146778Ssam                   tok2str(nlpid_values,"Unknown",*p),
685146778Ssam                   *p);
686146778Ssam
68717680Spst	switch (*p) {
68817680Spst
689146778Ssam	case NLPID_CLNP:
690146778Ssam		if (!clnp_print(p, length))
691146778Ssam                        print_unknown_data(p,"\n\t",caplen);
69217680Spst		break;
69317680Spst
69417688Spst	case NLPID_ESIS:
69517680Spst		esis_print(p, length);
69617680Spst		return;
69717680Spst
69817688Spst	case NLPID_ISIS:
69917751Spst		if (!isis_print(p, length))
700127675Sbms                        print_unknown_data(p,"\n\t",caplen);
70117680Spst		break;
70217680Spst
70317688Spst	case NLPID_NULLNS:
704147904Ssam		(void)printf("%slength: %u",
705147904Ssam		             eflag ? "" : ", ",
706147904Ssam                             length);
70717680Spst		break;
70817680Spst
709146778Ssam        case NLPID_Q933:
710146778Ssam                q933_print(p+1, length-1);
711146778Ssam                break;
712146778Ssam
713146778Ssam        case NLPID_IP:
714146778Ssam		ip_print(gndo, p+1, length-1);
715146778Ssam                break;
716146778Ssam
717146778Ssam#ifdef INET6
718146778Ssam        case NLPID_IP6:
719236192Sdelphij                ip6_print(gndo, p+1, length-1);
720146778Ssam                break;
721146778Ssam#endif
722146778Ssam
723146778Ssam        case NLPID_PPP:
724146778Ssam                ppp_print(p+1, length-1);
725146778Ssam                break;
726146778Ssam
72717680Spst	default:
728146778Ssam                if (!eflag)
729146778Ssam                    printf("OSI NLPID 0x%02x unknown",*p);
730147904Ssam		(void)printf("%slength: %u",
731147904Ssam		             eflag ? "" : ", ",
732147904Ssam                             length);
73317680Spst		if (caplen > 1)
734127675Sbms                        print_unknown_data(p,"\n\t",caplen);
73517680Spst		break;
73617680Spst	}
73717680Spst}
73817680Spst
739146778Ssam#define	CLNP_PDU_ER	 1
740146778Ssam#define	CLNP_PDU_DT	28
741146778Ssam#define	CLNP_PDU_MD	29
742146778Ssam#define	CLNP_PDU_ERQ	30
743146778Ssam#define	CLNP_PDU_ERP	31
74417680Spst
745146778Ssamstatic struct tok clnp_pdu_values[] = {
746146778Ssam    { CLNP_PDU_ER,  "Error Report"},
747146778Ssam    { CLNP_PDU_MD,  "MD"},
748146778Ssam    { CLNP_PDU_DT,  "Data"},
749146778Ssam    { CLNP_PDU_ERQ, "Echo Request"},
750146778Ssam    { CLNP_PDU_ERP, "Echo Response"},
751127675Sbms    { 0, NULL }
752127675Sbms};
753127675Sbms
754146778Ssamstruct clnp_header_t {
755146778Ssam    u_int8_t nlpid;
756146778Ssam    u_int8_t length_indicator;
757146778Ssam    u_int8_t version;
758146778Ssam    u_int8_t lifetime; /* units of 500ms */
759146778Ssam    u_int8_t type;
760146778Ssam    u_int8_t segment_length[2];
761146778Ssam    u_int8_t cksum[2];
762146778Ssam};
763146778Ssam
764146778Ssamstruct clnp_segment_header_t {
765146778Ssam    u_int8_t data_unit_id[2];
766146778Ssam    u_int8_t segment_offset[2];
767146778Ssam    u_int8_t total_length[2];
768146778Ssam};
769146778Ssam
770146778Ssam/*
771146778Ssam * clnp_print
772146778Ssam * Decode CLNP packets.  Return 0 on error.
773146778Ssam */
774146778Ssam
775146778Ssamstatic int clnp_print (const u_int8_t *pptr, u_int length)
776146778Ssam{
777146778Ssam	const u_int8_t *optr,*source_address,*dest_address;
778147904Ssam        u_int li,tlen,nsap_offset,source_address_length,dest_address_length, clnp_pdu_type, clnp_flags;
779146778Ssam	const struct clnp_header_t *clnp_header;
780146778Ssam	const struct clnp_segment_header_t *clnp_segment_header;
781146778Ssam        u_int8_t rfd_error_major,rfd_error_minor;
782146778Ssam
783146778Ssam	clnp_header = (const struct clnp_header_t *) pptr;
784146778Ssam        TCHECK(*clnp_header);
785146778Ssam
786146778Ssam        li = clnp_header->length_indicator;
787146778Ssam        optr = pptr;
788146778Ssam
789146778Ssam        if (!eflag)
790146778Ssam            printf("CLNP");
791146778Ssam
792146778Ssam        /*
793146778Ssam         * Sanity checking of the header.
794146778Ssam         */
795146778Ssam
796146778Ssam        if (clnp_header->version != CLNP_VERSION) {
797146778Ssam            printf("version %d packet not supported", clnp_header->version);
798146778Ssam            return (0);
799146778Ssam        }
800146778Ssam
801146778Ssam        /* FIXME further header sanity checking */
802146778Ssam
803146778Ssam        clnp_pdu_type = clnp_header->type & CLNP_PDU_TYPE_MASK;
804146778Ssam        clnp_flags = clnp_header->type & CLNP_FLAG_MASK;
805146778Ssam
806146778Ssam        pptr += sizeof(struct clnp_header_t);
807146778Ssam        li -= sizeof(struct clnp_header_t);
808146778Ssam        dest_address_length = *pptr;
809146778Ssam        dest_address = pptr + 1;
810146778Ssam
811146778Ssam        pptr += (1 + dest_address_length);
812146778Ssam        li -= (1 + dest_address_length);
813146778Ssam        source_address_length = *pptr;
814146778Ssam        source_address = pptr +1;
815146778Ssam
816146778Ssam        pptr += (1 + source_address_length);
817146778Ssam        li -= (1 + source_address_length);
818146778Ssam
819146778Ssam        if (vflag < 1) {
820146778Ssam            printf("%s%s > %s, %s, length %u",
821146778Ssam                   eflag ? "" : ", ",
822146778Ssam                   isonsap_string(source_address, source_address_length),
823146778Ssam                   isonsap_string(dest_address, dest_address_length),
824146778Ssam                   tok2str(clnp_pdu_values,"unknown (%u)",clnp_pdu_type),
825146778Ssam                   length);
826146778Ssam            return (1);
827146778Ssam        }
828146778Ssam        printf("%slength %u",eflag ? "" : ", ",length);
829146778Ssam
830190207Srpaulo        printf("\n\t%s PDU, hlen: %u, v: %u, lifetime: %u.%us, Segment PDU length: %u, checksum: 0x%04x",
831146778Ssam               tok2str(clnp_pdu_values, "unknown (%u)",clnp_pdu_type),
832146778Ssam               clnp_header->length_indicator,
833146778Ssam               clnp_header->version,
834146778Ssam               clnp_header->lifetime/2,
835146778Ssam               (clnp_header->lifetime%2)*5,
836146778Ssam               EXTRACT_16BITS(clnp_header->segment_length),
837146778Ssam               EXTRACT_16BITS(clnp_header->cksum));
838146778Ssam
839190207Srpaulo        osi_print_cksum(optr, EXTRACT_16BITS(clnp_header->cksum), 7,
840190207Srpaulo                        clnp_header->length_indicator);
841146778Ssam
842146778Ssam        printf("\n\tFlags [%s]",
843146778Ssam               bittok2str(clnp_flag_values,"none",clnp_flags));
844146778Ssam
845146778Ssam        printf("\n\tsource address (length %u): %s\n\tdest   address (length %u): %s",
846146778Ssam               source_address_length,
847146778Ssam               isonsap_string(source_address, source_address_length),
848146778Ssam               dest_address_length,
849146778Ssam               isonsap_string(dest_address,dest_address_length));
850146778Ssam
851146778Ssam        if (clnp_flags & CLNP_SEGMENT_PART) {
852146778Ssam            	clnp_segment_header = (const struct clnp_segment_header_t *) pptr;
853162021Ssam                TCHECK(*clnp_segment_header);
854146778Ssam                printf("\n\tData Unit ID: 0x%04x, Segment Offset: %u, Total PDU Length: %u",
855146778Ssam                       EXTRACT_16BITS(clnp_segment_header->data_unit_id),
856146778Ssam                       EXTRACT_16BITS(clnp_segment_header->segment_offset),
857146778Ssam                       EXTRACT_16BITS(clnp_segment_header->total_length));
858146778Ssam                pptr+=sizeof(const struct clnp_segment_header_t);
859146778Ssam                li-=sizeof(const struct clnp_segment_header_t);
860146778Ssam        }
861146778Ssam
862146778Ssam        /* now walk the options */
863146778Ssam        while (li >= 2) {
864146778Ssam            u_int op, opli;
865146778Ssam            const u_int8_t *tptr;
866146778Ssam
867147904Ssam            TCHECK2(*pptr, 2);
868146778Ssam            if (li < 2) {
869146778Ssam                printf(", bad opts/li");
870146778Ssam                return (0);
871146778Ssam            }
872146778Ssam            op = *pptr++;
873146778Ssam            opli = *pptr++;
874146778Ssam            li -= 2;
875147904Ssam            TCHECK2(*pptr, opli);
876146778Ssam            if (opli > li) {
877146778Ssam                printf(", opt (%d) too long", op);
878146778Ssam                return (0);
879146778Ssam            }
880146778Ssam            li -= opli;
881146778Ssam            tptr = pptr;
882147904Ssam            tlen = opli;
883146778Ssam
884146778Ssam            printf("\n\t  %s Option #%u, length %u, value: ",
885146778Ssam                   tok2str(clnp_option_values,"Unknown",op),
886146778Ssam                   op,
887146778Ssam                   opli);
888146778Ssam
889146778Ssam            switch (op) {
890146778Ssam
891147904Ssam
892147904Ssam            case CLNP_OPTION_ROUTE_RECORDING: /* those two options share the format */
893147904Ssam            case CLNP_OPTION_SOURCE_ROUTING:
894147904Ssam                    printf("%s %s",
895147904Ssam                           tok2str(clnp_option_sr_rr_values,"Unknown",*tptr),
896147904Ssam                           tok2str(clnp_option_sr_rr_string_values,"Unknown Option %u",op));
897147904Ssam                    nsap_offset=*(tptr+1);
898147904Ssam                    if (nsap_offset == 0) {
899147904Ssam                            printf(" Bad NSAP offset (0)");
900147904Ssam                            break;
901147904Ssam                    }
902147904Ssam                    nsap_offset-=1; /* offset to nsap list */
903147904Ssam                    if (nsap_offset > tlen) {
904147904Ssam                            printf(" Bad NSAP offset (past end of option)");
905147904Ssam                            break;
906147904Ssam                    }
907147904Ssam                    tptr+=nsap_offset;
908147904Ssam                    tlen-=nsap_offset;
909147904Ssam                    while (tlen > 0) {
910147904Ssam                            source_address_length=*tptr;
911147904Ssam                            if (tlen < source_address_length+1) {
912147904Ssam                                    printf("\n\t    NSAP address goes past end of option");
913147904Ssam                                    break;
914162021Ssam                            }
915147904Ssam                            if (source_address_length > 0) {
916147904Ssam                                    source_address=(tptr+1);
917147904Ssam                                    TCHECK2(*source_address, source_address_length);
918147904Ssam                                    printf("\n\t    NSAP address (length %u): %s",
919147904Ssam                                           source_address_length,
920147904Ssam                                           isonsap_string(source_address, source_address_length));
921147904Ssam                            }
922147904Ssam                            tlen-=source_address_length+1;
923147904Ssam                    }
924147904Ssam                    break;
925147904Ssam
926146778Ssam            case CLNP_OPTION_PRIORITY:
927147904Ssam                    printf("0x%1x", *tptr&0x0f);
928147904Ssam                    break;
929146778Ssam
930147904Ssam            case CLNP_OPTION_QOS_MAINTENANCE:
931147904Ssam                    printf("\n\t    Format Code: %s",
932147904Ssam                           tok2str(clnp_option_scope_values,"Reserved",*tptr&CLNP_OPTION_SCOPE_MASK));
933147904Ssam
934147904Ssam                    if ((*tptr&CLNP_OPTION_SCOPE_MASK) == CLNP_OPTION_SCOPE_GLOBAL)
935147904Ssam                            printf("\n\t    QoS Flags [%s]",
936147904Ssam                                   bittok2str(clnp_option_qos_global_values,
937147904Ssam                                              "none",
938147904Ssam                                              *tptr&CLNP_OPTION_OPTION_QOS_MASK));
939147904Ssam                    break;
940147904Ssam
941147904Ssam            case CLNP_OPTION_SECURITY:
942147904Ssam                    printf("\n\t    Format Code: %s, Security-Level %u",
943147904Ssam                           tok2str(clnp_option_scope_values,"Reserved",*tptr&CLNP_OPTION_SCOPE_MASK),
944147904Ssam                           *(tptr+1));
945147904Ssam                    break;
946147904Ssam
947146778Ssam            case CLNP_OPTION_DISCARD_REASON:
948146778Ssam                rfd_error_major = (*tptr&0xf0) >> 4;
949146778Ssam                rfd_error_minor = *tptr&0x0f;
950146778Ssam                printf("\n\t    Class: %s Error (0x%01x), %s (0x%01x)",
951146778Ssam                       tok2str(clnp_option_rfd_class_values,"Unknown",rfd_error_major),
952146778Ssam                       rfd_error_major,
953146778Ssam                       tok2str(clnp_option_rfd_error_class[rfd_error_major],"Unknown",rfd_error_minor),
954146778Ssam                       rfd_error_minor);
955146778Ssam                break;
956146778Ssam
957147904Ssam            case CLNP_OPTION_PADDING:
958147904Ssam                    printf("padding data");
959147904Ssam                break;
960147904Ssam
961146778Ssam                /*
962146778Ssam                 * FIXME those are the defined Options that lack a decoder
963146778Ssam                 * you are welcome to contribute code ;-)
964146778Ssam                 */
965146778Ssam
966146778Ssam            default:
967146778Ssam                print_unknown_data(tptr,"\n\t  ",opli);
968146778Ssam                break;
969146778Ssam            }
970146778Ssam            if (vflag > 1)
971146778Ssam                print_unknown_data(pptr,"\n\t  ",opli);
972146778Ssam            pptr += opli;
973146778Ssam        }
974146778Ssam
975146778Ssam        switch (clnp_pdu_type) {
976146778Ssam
977146778Ssam        case    CLNP_PDU_ER: /* fall through */
978146778Ssam        case 	CLNP_PDU_ERP:
979147904Ssam            TCHECK(*pptr);
980146778Ssam            if (*(pptr) == NLPID_CLNP) {
981146778Ssam                printf("\n\t-----original packet-----\n\t");
982146778Ssam                /* FIXME recursion protection */
983146778Ssam                clnp_print(pptr, length-clnp_header->length_indicator);
984146778Ssam                break;
985146778Ssam            }
986146778Ssam
987146778Ssam        case 	CLNP_PDU_DT:
988146778Ssam        case 	CLNP_PDU_MD:
989146778Ssam        case 	CLNP_PDU_ERQ:
990146778Ssam
991146778Ssam        default:
992146778Ssam            /* dump the PDU specific data */
993146778Ssam            if (length-(pptr-optr) > 0) {
994146778Ssam                printf("\n\t  undecoded non-header data, length %u",length-clnp_header->length_indicator);
995146778Ssam                print_unknown_data(pptr,"\n\t  ",length-(pptr-optr));
996146778Ssam            }
997146778Ssam        }
998146778Ssam
999146778Ssam        return (1);
1000146778Ssam
1001146778Ssam trunc:
1002146778Ssam    fputs("[|clnp]", stdout);
1003146778Ssam    return (1);
1004146778Ssam
1005146778Ssam}
1006146778Ssam
1007146778Ssam
1008146778Ssam#define	ESIS_PDU_REDIRECT	6
1009146778Ssam#define	ESIS_PDU_ESH	        2
1010146778Ssam#define	ESIS_PDU_ISH	        4
1011146778Ssam
1012146778Ssamstatic struct tok esis_pdu_values[] = {
1013146778Ssam    { ESIS_PDU_REDIRECT, "redirect"},
1014146778Ssam    { ESIS_PDU_ESH,      "ESH"},
1015146778Ssam    { ESIS_PDU_ISH,      "ISH"},
1016146778Ssam    { 0, NULL }
1017146778Ssam};
1018146778Ssam
1019146778Ssamstruct esis_header_t {
1020146778Ssam	u_int8_t nlpid;
1021146778Ssam	u_int8_t length_indicator;
1022127675Sbms	u_int8_t version;
1023127675Sbms	u_int8_t reserved;
1024127675Sbms	u_int8_t type;
1025146778Ssam	u_int8_t holdtime[2];
1026127675Sbms	u_int8_t cksum[2];
102717680Spst};
102817680Spst
102917680Spststatic void
1030146778Ssamesis_print(const u_int8_t *pptr, u_int length)
103117680Spst{
1032146778Ssam	const u_int8_t *optr;
1033146778Ssam	u_int li,esis_pdu_type,source_address_length, source_address_number;
1034146778Ssam	const struct esis_header_t *esis_header;
103517680Spst
1036146778Ssam        if (!eflag)
1037146778Ssam            printf("ES-IS");
1038146778Ssam
103998527Sfenner	if (length <= 2) {
104017680Spst		if (qflag)
1041146778Ssam			printf("bad pkt!");
104217680Spst		else
1043146778Ssam			printf("no header at all!");
104417680Spst		return;
104517680Spst	}
1046146778Ssam
1047146778Ssam	esis_header = (const struct esis_header_t *) pptr;
1048147904Ssam        TCHECK(*esis_header);
1049146778Ssam        li = esis_header->length_indicator;
1050146778Ssam        optr = pptr;
1051146778Ssam
1052146778Ssam        /*
1053146778Ssam         * Sanity checking of the header.
1054146778Ssam         */
1055146778Ssam
1056146778Ssam        if (esis_header->nlpid != NLPID_ESIS) {
1057146778Ssam            printf(" nlpid 0x%02x packet not supported", esis_header->nlpid);
1058146778Ssam            return;
1059146778Ssam        }
1060146778Ssam
1061146778Ssam        if (esis_header->version != ESIS_VERSION) {
1062146778Ssam            printf(" version %d packet not supported", esis_header->version);
1063146778Ssam            return;
1064146778Ssam        }
1065146778Ssam
106617680Spst	if (li > length) {
1067146778Ssam            printf(" length indicator(%d) > PDU size (%d)!", li, length);
1068146778Ssam            return;
106917680Spst	}
1070146778Ssam
1071146778Ssam	if (li < sizeof(struct esis_header_t) + 2) {
1072146778Ssam            printf(" length indicator < min PDU size %d:", li);
1073146778Ssam            while (--length != 0)
1074146778Ssam                printf("%02X", *pptr++);
1075146778Ssam            return;
107617680Spst	}
107717680Spst
1078146778Ssam        esis_pdu_type = esis_header->type & ESIS_PDU_TYPE_MASK;
107917680Spst
1080146778Ssam        if (vflag < 1) {
1081146778Ssam            printf("%s%s, length %u",
1082146778Ssam                   eflag ? "" : ", ",
1083146778Ssam                   tok2str(esis_pdu_values,"unknown type (%u)",esis_pdu_type),
1084146778Ssam                   length);
1085146778Ssam            return;
1086146778Ssam        } else
1087146778Ssam            printf("%slength %u\n\t%s (%u)",
1088146778Ssam                   eflag ? "" : ", ",
1089146778Ssam                   length,
1090146778Ssam                   tok2str(esis_pdu_values,"unknown type: %u", esis_pdu_type),
1091146778Ssam                   esis_pdu_type);
109217680Spst
1093146778Ssam        printf(", v: %u%s", esis_header->version, esis_header->version == ESIS_VERSION ? "" : "unsupported" );
1094190207Srpaulo        printf(", checksum: 0x%04x", EXTRACT_16BITS(esis_header->cksum));
109517680Spst
1096190207Srpaulo        osi_print_cksum(pptr, EXTRACT_16BITS(esis_header->cksum), 7, li);
1097190207Srpaulo
1098146778Ssam        printf(", holding time: %us, length indicator: %u",EXTRACT_16BITS(esis_header->holdtime),li);
109917680Spst
1100146778Ssam        if (vflag > 1)
1101146778Ssam            print_unknown_data(optr,"\n\t",sizeof(struct esis_header_t));
1102146778Ssam
1103146778Ssam	pptr += sizeof(struct esis_header_t);
1104146778Ssam	li -= sizeof(struct esis_header_t);
1105146778Ssam
1106146778Ssam	switch (esis_pdu_type) {
1107146778Ssam	case ESIS_PDU_REDIRECT: {
1108147904Ssam		const u_int8_t *dst, *snpa, *neta;
1109147904Ssam		u_int dstl, snpal, netal;
1110146778Ssam
1111147904Ssam		TCHECK(*pptr);
1112147904Ssam		if (li < 1) {
1113147904Ssam			printf(", bad redirect/li");
111417680Spst			return;
1115147904Ssam		}
1116147904Ssam		dstl = *pptr;
1117147904Ssam		pptr++;
1118147904Ssam		li--;
1119147904Ssam		TCHECK2(*pptr, dstl);
1120147904Ssam		if (li < dstl) {
1121147904Ssam			printf(", bad redirect/li");
112217680Spst			return;
1123147904Ssam		}
1124147904Ssam		dst = pptr;
1125147904Ssam		pptr += dstl;
1126147904Ssam                li -= dstl;
1127147904Ssam		printf("\n\t  %s", isonsap_string(dst,dstl));
1128146778Ssam
1129147904Ssam		TCHECK(*pptr);
1130147904Ssam		if (li < 1) {
1131147904Ssam			printf(", bad redirect/li");
1132147904Ssam			return;
1133147904Ssam		}
1134147904Ssam		snpal = *pptr;
1135147904Ssam		pptr++;
1136147904Ssam		li--;
1137147904Ssam		TCHECK2(*pptr, snpal);
1138147904Ssam		if (li < snpal) {
1139147904Ssam			printf(", bad redirect/li");
1140147904Ssam			return;
1141147904Ssam		}
1142147904Ssam		snpa = pptr;
1143147904Ssam		pptr += snpal;
1144147904Ssam                li -= snpal;
1145147904Ssam		TCHECK(*pptr);
1146147904Ssam		if (li < 1) {
1147147904Ssam			printf(", bad redirect/li");
1148147904Ssam			return;
1149147904Ssam		}
1150147904Ssam		netal = *pptr;
1151147904Ssam		pptr++;
1152147904Ssam		TCHECK2(*pptr, netal);
1153147904Ssam		if (li < netal) {
1154147904Ssam			printf(", bad redirect/li");
1155147904Ssam			return;
1156147904Ssam		}
1157147904Ssam		neta = pptr;
1158147904Ssam		pptr += netal;
1159147904Ssam                li -= netal;
1160147904Ssam
1161147904Ssam		if (netal == 0)
1162147904Ssam			printf("\n\t  %s", etheraddr_string(snpa));
116317680Spst		else
1164147904Ssam			printf("\n\t  %s", isonsap_string(neta,netal));
116517680Spst		break;
116617680Spst	}
1167127675Sbms
1168146778Ssam	case ESIS_PDU_ESH:
1169147904Ssam            TCHECK(*pptr);
1170147904Ssam            if (li < 1) {
1171147904Ssam                printf(", bad esh/li");
1172147904Ssam                return;
1173147904Ssam            }
1174146778Ssam            source_address_number = *pptr;
1175146778Ssam            pptr++;
1176146778Ssam            li--;
1177127675Sbms
1178146778Ssam            printf("\n\t  Number of Source Addresses: %u", source_address_number);
1179146778Ssam
1180146778Ssam            while (source_address_number > 0) {
1181147904Ssam                TCHECK(*pptr);
1182147904Ssam            	if (li < 1) {
1183147904Ssam                    printf(", bad esh/li");
1184147904Ssam            	    return;
1185147904Ssam            	}
1186146778Ssam                source_address_length = *pptr;
1187147904Ssam                pptr++;
1188147904Ssam            	li--;
1189147904Ssam
1190147904Ssam                TCHECK2(*pptr, source_address_length);
1191147904Ssam            	if (li < source_address_length) {
1192147904Ssam                    printf(", bad esh/li");
1193147904Ssam            	    return;
1194147904Ssam            	}
1195146778Ssam                printf("\n\t  NET (length: %u): %s",
1196146778Ssam                       source_address_length,
1197147904Ssam                       isonsap_string(pptr,source_address_length));
1198147904Ssam                pptr += source_address_length;
1199147904Ssam                li -= source_address_length;
1200146778Ssam                source_address_number--;
1201146778Ssam            }
1202146778Ssam
1203146778Ssam            break;
1204146778Ssam
1205146778Ssam	case ESIS_PDU_ISH: {
1206147904Ssam            TCHECK(*pptr);
1207147904Ssam            if (li < 1) {
1208147904Ssam                printf(", bad ish/li");
1209147904Ssam                return;
1210147904Ssam            }
1211146778Ssam            source_address_length = *pptr;
1212147904Ssam            pptr++;
1213147904Ssam            li--;
1214147904Ssam            TCHECK2(*pptr, source_address_length);
1215147904Ssam            if (li < source_address_length) {
1216147904Ssam                printf(", bad ish/li");
1217147904Ssam                return;
1218147904Ssam            }
1219147904Ssam            printf("\n\t  NET (length: %u): %s", source_address_length, isonsap_string(pptr, source_address_length));
1220147904Ssam            pptr += source_address_length;
1221147904Ssam            li -= source_address_length;
1222146778Ssam            break;
122317680Spst	}
122417680Spst
122517680Spst	default:
1226127675Sbms            if (vflag <= 1) {
1227146778Ssam		    if (pptr < snapend)
1228146778Ssam                            print_unknown_data(pptr,"\n\t  ",snapend-pptr);
1229127675Sbms            }
1230127675Sbms            return;
123117680Spst	}
1232127675Sbms
1233146778Ssam        /* now walk the options */
1234236192Sdelphij        while (li != 0) {
1235146778Ssam            u_int op, opli;
1236146778Ssam            const u_int8_t *tptr;
1237146778Ssam
1238146778Ssam            if (li < 2) {
1239146778Ssam                printf(", bad opts/li");
1240146778Ssam                return;
1241146778Ssam            }
1242236192Sdelphij            TCHECK2(*pptr, 2);
1243146778Ssam            op = *pptr++;
1244146778Ssam            opli = *pptr++;
1245146778Ssam            li -= 2;
1246146778Ssam            if (opli > li) {
1247146778Ssam                printf(", opt (%d) too long", op);
1248146778Ssam                return;
1249146778Ssam            }
1250146778Ssam            li -= opli;
1251146778Ssam            tptr = pptr;
1252146778Ssam
1253146778Ssam            printf("\n\t  %s Option #%u, length %u, value: ",
1254146778Ssam                   tok2str(esis_option_values,"Unknown",op),
1255146778Ssam                   op,
1256146778Ssam                   opli);
125717680Spst
1258146778Ssam            switch (op) {
1259127675Sbms
1260146778Ssam            case ESIS_OPTION_ES_CONF_TIME:
1261236192Sdelphij                if (opli == 2) {
1262236192Sdelphij                    TCHECK2(*pptr, 2);
1263236192Sdelphij                    printf("%us", EXTRACT_16BITS(tptr));
1264236192Sdelphij                } else
1265236192Sdelphij                    printf("(bad length)");
1266146778Ssam                break;
1267127675Sbms
1268146778Ssam            case ESIS_OPTION_PROTOCOLS:
1269146778Ssam                while (opli>0) {
1270147904Ssam                    TCHECK(*pptr);
1271146778Ssam                    printf("%s (0x%02x)",
1272146778Ssam                           tok2str(nlpid_values,
1273146778Ssam                                   "unknown",
1274146778Ssam                                   *tptr),
1275146778Ssam                           *tptr);
1276146778Ssam                    if (opli>1) /* further NPLIDs ? - put comma */
1277146778Ssam                        printf(", ");
1278146778Ssam                    tptr++;
1279146778Ssam                    opli--;
1280146778Ssam                }
1281146778Ssam                break;
1282127675Sbms
1283146778Ssam                /*
1284146778Ssam                 * FIXME those are the defined Options that lack a decoder
1285146778Ssam                 * you are welcome to contribute code ;-)
1286146778Ssam                 */
1287127675Sbms
1288146778Ssam            case ESIS_OPTION_QOS_MAINTENANCE:
1289146778Ssam            case ESIS_OPTION_SECURITY:
1290146778Ssam            case ESIS_OPTION_PRIORITY:
1291146778Ssam            case ESIS_OPTION_ADDRESS_MASK:
1292146778Ssam            case ESIS_OPTION_SNPA_MASK:
129317680Spst
1294146778Ssam            default:
1295146778Ssam                print_unknown_data(tptr,"\n\t  ",opli);
1296146778Ssam                break;
1297146778Ssam            }
1298146778Ssam            if (vflag > 1)
1299146778Ssam                print_unknown_data(pptr,"\n\t  ",opli);
1300146778Ssam            pptr += opli;
1301146778Ssam        }
1302147904Ssamtrunc:
1303147904Ssam	return;
1304146778Ssam}
1305146778Ssam
1306252283Sdelphij
1307252283Sdelphijstatic void
1308252283Sdelphijisis_print_mcid (const struct isis_spb_mcid *mcid)
1309252283Sdelphij{
1310252283Sdelphij  int i;
1311252283Sdelphij
1312252283Sdelphij  printf( "ID: %d, Name: ", mcid->format_id);
1313252283Sdelphij
1314252283Sdelphij  for(i=0; i<32; i++)
1315252283Sdelphij  {
1316252283Sdelphij    printf("%c", mcid->name[i]);
1317252283Sdelphij    if(mcid->name[i] == '\0')
1318252283Sdelphij        break;
1319252283Sdelphij  }
1320252283Sdelphij
1321252283Sdelphij  printf("\n\t              Lvl: %d",
1322252283Sdelphij          EXTRACT_16BITS(mcid->revision_lvl));
1323252283Sdelphij
1324252283Sdelphij  printf( ", Digest: ");
1325252283Sdelphij
1326252283Sdelphij  for(i=0;i<16;i++)
1327252283Sdelphij    printf("%.2x ",mcid->digest[i]);
1328252283Sdelphij}
1329252283Sdelphij
1330252283Sdelphijstatic int
1331252283Sdelphijisis_print_mt_port_cap_subtlv (const u_int8_t *tptr, int len)
1332252283Sdelphij{
1333252283Sdelphij  int stlv_type, stlv_len;
1334252283Sdelphij  const struct isis_subtlv_spb_mcid *subtlv_spb_mcid;
1335252283Sdelphij  int i;
1336252283Sdelphij
1337252283Sdelphij  while (len > 0)
1338252283Sdelphij  {
1339252283Sdelphij    stlv_type = *(tptr++);
1340252283Sdelphij    stlv_len  = *(tptr++);
1341252283Sdelphij
1342252283Sdelphij    /* first lets see if we know the subTLVs name*/
1343252283Sdelphij    printf("\n\t       %s subTLV #%u, length: %u",
1344252283Sdelphij               tok2str(isis_mt_port_cap_subtlv_values, "unknown", stlv_type),
1345252283Sdelphij               stlv_type,
1346252283Sdelphij               stlv_len);
1347252283Sdelphij
1348252283Sdelphij    /*len -= TLV_TYPE_LEN_OFFSET;*/
1349252283Sdelphij    len = len -2;
1350252283Sdelphij
1351252283Sdelphij    switch (stlv_type)
1352252283Sdelphij    {
1353252283Sdelphij      case ISIS_SUBTLV_SPB_MCID:
1354252283Sdelphij      {
1355252283Sdelphij        if (!TTEST2(*(tptr), ISIS_SUBTLV_SPB_MCID_MIN_LEN))
1356252283Sdelphij          goto trunctlv;
1357252283Sdelphij
1358252283Sdelphij        subtlv_spb_mcid = (struct isis_subtlv_spb_mcid *)tptr;
1359252283Sdelphij
1360252283Sdelphij        printf( "\n\t         MCID: ");
1361252283Sdelphij        isis_print_mcid (&(subtlv_spb_mcid->mcid));
1362252283Sdelphij
1363252283Sdelphij          /*tptr += SPB_MCID_MIN_LEN;
1364252283Sdelphij            len -= SPB_MCID_MIN_LEN; */
1365252283Sdelphij
1366252283Sdelphij        printf( "\n\t         AUX-MCID: ");
1367252283Sdelphij        isis_print_mcid (&(subtlv_spb_mcid->aux_mcid));
1368252283Sdelphij
1369252283Sdelphij          /*tptr += SPB_MCID_MIN_LEN;
1370252283Sdelphij            len -= SPB_MCID_MIN_LEN; */
1371252283Sdelphij        tptr = tptr + sizeof(struct isis_subtlv_spb_mcid);
1372252283Sdelphij        len = len - sizeof(struct isis_subtlv_spb_mcid);
1373252283Sdelphij
1374252283Sdelphij        break;
1375252283Sdelphij      }
1376252283Sdelphij
1377252283Sdelphij      case ISIS_SUBTLV_SPB_DIGEST:
1378252283Sdelphij      {
1379252283Sdelphij        if (!TTEST2(*(tptr), ISIS_SUBTLV_SPB_DIGEST_MIN_LEN))
1380252283Sdelphij          goto trunctlv;
1381252283Sdelphij
1382252283Sdelphij        printf ("\n\t        RES: %d V: %d A: %d D: %d",
1383252283Sdelphij                        (*(tptr) >> 5), (((*tptr)>> 4) & 0x01),
1384252283Sdelphij                        ((*(tptr) >> 2) & 0x03), ((*tptr) & 0x03));
1385252283Sdelphij
1386252283Sdelphij        tptr++;
1387252283Sdelphij
1388252283Sdelphij        printf( "\n\t         Digest: ");
1389252283Sdelphij
1390252283Sdelphij        for(i=1;i<=8; i++)
1391252283Sdelphij        {
1392252283Sdelphij            printf("%08x ", EXTRACT_32BITS(tptr));
1393252283Sdelphij            if (i%4 == 0 && i != 8)
1394252283Sdelphij              printf("\n\t                 ");
1395252283Sdelphij            tptr = tptr + 4;
1396252283Sdelphij        }
1397252283Sdelphij
1398252283Sdelphij        len = len - ISIS_SUBTLV_SPB_DIGEST_MIN_LEN;
1399252283Sdelphij
1400252283Sdelphij        break;
1401252283Sdelphij      }
1402252283Sdelphij
1403252283Sdelphij      case ISIS_SUBTLV_SPB_BVID:
1404252283Sdelphij      {
1405252283Sdelphij        if (!TTEST2(*(tptr), stlv_len))
1406252283Sdelphij          goto trunctlv;
1407252283Sdelphij
1408252283Sdelphij        while (len)
1409252283Sdelphij        {
1410252283Sdelphij          if (!TTEST2(*(tptr), ISIS_SUBTLV_SPB_BVID_MIN_LEN))
1411252283Sdelphij            goto trunctlv;
1412252283Sdelphij
1413252283Sdelphij          printf("\n\t           ECT: %08x",
1414252283Sdelphij                      EXTRACT_32BITS(tptr));
1415252283Sdelphij
1416252283Sdelphij          tptr = tptr+4;
1417252283Sdelphij
1418252283Sdelphij          printf(" BVID: %d, U:%01x M:%01x ",
1419252283Sdelphij                     (EXTRACT_16BITS (tptr) >> 4) ,
1420252283Sdelphij                     (EXTRACT_16BITS (tptr) >> 3) & 0x01,
1421252283Sdelphij                     (EXTRACT_16BITS (tptr) >> 2) & 0x01);
1422252283Sdelphij
1423252283Sdelphij          tptr = tptr + 2;
1424252283Sdelphij          len = len - ISIS_SUBTLV_SPB_BVID_MIN_LEN;
1425252283Sdelphij        }
1426252283Sdelphij
1427252283Sdelphij        break;
1428252283Sdelphij      }
1429252283Sdelphij
1430252283Sdelphij      default:
1431252283Sdelphij          break;
1432252283Sdelphij    }
1433252283Sdelphij  }
1434252283Sdelphij
1435252283Sdelphij  return 0;
1436252283Sdelphij
1437252283Sdelphij  trunctlv:
1438252283Sdelphij    printf("\n\t\t packet exceeded snapshot");
1439252283Sdelphij    return(1);
1440252283Sdelphij}
1441252283Sdelphij
1442252283Sdelphijstatic int
1443252283Sdelphijisis_print_mt_capability_subtlv (const u_int8_t *tptr, int len)
1444252283Sdelphij{
1445252283Sdelphij  int stlv_type, stlv_len, tmp;
1446252283Sdelphij
1447252283Sdelphij  while (len > 0)
1448252283Sdelphij  {
1449252283Sdelphij    stlv_type = *(tptr++);
1450252283Sdelphij    stlv_len  = *(tptr++);
1451252283Sdelphij
1452252283Sdelphij    /* first lets see if we know the subTLVs name*/
1453252283Sdelphij    printf("\n\t      %s subTLV #%u, length: %u",
1454252283Sdelphij               tok2str(isis_mt_capability_subtlv_values, "unknown", stlv_type),
1455252283Sdelphij               stlv_type,
1456252283Sdelphij               stlv_len);
1457252283Sdelphij
1458252283Sdelphij    len = len - 2;
1459252283Sdelphij
1460252283Sdelphij    switch (stlv_type)
1461252283Sdelphij    {
1462252283Sdelphij      case ISIS_SUBTLV_SPB_INSTANCE:
1463252283Sdelphij
1464252283Sdelphij          if (!TTEST2(*(tptr), ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN))
1465252283Sdelphij            goto trunctlv;
1466252283Sdelphij
1467252283Sdelphij          printf("\n\t        CIST Root-ID: %08x", EXTRACT_32BITS(tptr));
1468252283Sdelphij          tptr = tptr+4;
1469252283Sdelphij          printf(" %08x", EXTRACT_32BITS(tptr));
1470252283Sdelphij          tptr = tptr+4;
1471252283Sdelphij          printf(", Path Cost: %08x", EXTRACT_32BITS(tptr));
1472252283Sdelphij          tptr = tptr+4;
1473252283Sdelphij          printf(", Prio: %d", EXTRACT_16BITS(tptr));
1474252283Sdelphij          tptr = tptr + 2;
1475252283Sdelphij          printf("\n\t        RES: %d",
1476252283Sdelphij                    EXTRACT_16BITS(tptr) >> 5);
1477252283Sdelphij          printf(", V: %d",
1478252283Sdelphij                    (EXTRACT_16BITS(tptr) >> 4) & 0x0001);
1479252283Sdelphij          printf(", SPSource-ID: %d",
1480252283Sdelphij                    (EXTRACT_32BITS(tptr) & 0x000fffff));
1481252283Sdelphij          tptr = tptr+4;
1482252283Sdelphij          printf(", No of Trees: %x", *(tptr));
1483252283Sdelphij
1484252283Sdelphij          tmp = *(tptr++);
1485252283Sdelphij
1486252283Sdelphij          len = len - ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN;
1487252283Sdelphij
1488252283Sdelphij          while (tmp)
1489252283Sdelphij          {
1490252283Sdelphij            if (!TTEST2(*(tptr), ISIS_SUBTLV_SPB_INSTANCE_VLAN_TUPLE_LEN))
1491252283Sdelphij              goto trunctlv;
1492252283Sdelphij
1493252283Sdelphij            printf ("\n\t         U:%d, M:%d, A:%d, RES:%d",
1494252283Sdelphij                      *(tptr) >> 7, (*(tptr) >> 6) & 0x01,
1495252283Sdelphij                      (*(tptr) >> 5) & 0x01, (*(tptr) & 0x1f));
1496252283Sdelphij
1497252283Sdelphij            tptr++;
1498252283Sdelphij
1499252283Sdelphij            printf (", ECT: %08x", EXTRACT_32BITS(tptr));
1500252283Sdelphij
1501252283Sdelphij            tptr = tptr + 4;
1502252283Sdelphij
1503252283Sdelphij            printf (", BVID: %d, SPVID: %d",
1504252283Sdelphij                      (EXTRACT_24BITS(tptr) >> 12) & 0x000fff,
1505252283Sdelphij                      EXTRACT_24BITS(tptr) & 0x000fff);
1506252283Sdelphij
1507252283Sdelphij            tptr = tptr + 3;
1508252283Sdelphij            len = len - ISIS_SUBTLV_SPB_INSTANCE_VLAN_TUPLE_LEN;
1509252283Sdelphij            tmp--;
1510252283Sdelphij          }
1511252283Sdelphij
1512252283Sdelphij          break;
1513252283Sdelphij
1514252283Sdelphij      case ISIS_SUBTLV_SPBM_SI:
1515252283Sdelphij
1516252283Sdelphij          if (!TTEST2(*(tptr), 6))
1517252283Sdelphij            goto trunctlv;
1518252283Sdelphij
1519252283Sdelphij          printf("\n\t        BMAC: %08x", EXTRACT_32BITS(tptr));
1520252283Sdelphij          tptr = tptr+4;
1521252283Sdelphij          printf("%04x", EXTRACT_16BITS(tptr));
1522252283Sdelphij          tptr = tptr+2;
1523252283Sdelphij
1524252283Sdelphij          printf (", RES: %d, VID: %d", EXTRACT_16BITS(tptr) >> 12,
1525252283Sdelphij                    (EXTRACT_16BITS(tptr)) & 0x0fff);
1526252283Sdelphij
1527252283Sdelphij          tptr = tptr+2;
1528252283Sdelphij          len = len - 8;
1529252283Sdelphij          stlv_len = stlv_len - 8;
1530252283Sdelphij
1531252283Sdelphij          while (stlv_len)
1532252283Sdelphij          {
1533252283Sdelphij            printf("\n\t        T: %d, R: %d, RES: %d, ISID: %d",
1534252283Sdelphij                    (EXTRACT_32BITS(tptr) >> 31),
1535252283Sdelphij                    (EXTRACT_32BITS(tptr) >> 30) & 0x01,
1536252283Sdelphij                    (EXTRACT_32BITS(tptr) >> 24) & 0x03f,
1537252283Sdelphij                    (EXTRACT_32BITS(tptr)) & 0x0ffffff);
1538252283Sdelphij
1539252283Sdelphij            tptr = tptr + 4;
1540252283Sdelphij            len = len - 4;
1541252283Sdelphij            stlv_len = stlv_len - 4;
1542252283Sdelphij          }
1543252283Sdelphij
1544252283Sdelphij        break;
1545252283Sdelphij
1546252283Sdelphij      default:
1547252283Sdelphij        break;
1548252283Sdelphij    }
1549252283Sdelphij  }
1550252283Sdelphij  return 0;
1551252283Sdelphij
1552252283Sdelphij  trunctlv:
1553252283Sdelphij    printf("\n\t\t packet exceeded snapshot");
1554252283Sdelphij    return(1);
1555252283Sdelphij}
1556252283Sdelphij
1557252283Sdelphij
1558127675Sbms/* shared routine for printing system, node and lsp-ids */
1559127675Sbmsstatic char *
1560127675Sbmsisis_print_id(const u_int8_t *cp, int id_len)
156198527Sfenner{
1562127675Sbms    int i;
1563127675Sbms    static char id[sizeof("xxxx.xxxx.xxxx.yy-zz")];
1564127675Sbms    char *pos = id;
156517688Spst
1566127675Sbms    for (i = 1; i <= SYSTEM_ID_LEN; i++) {
1567127675Sbms        snprintf(pos, sizeof(id) - (pos - id), "%02x", *cp++);
1568127675Sbms	pos += strlen(pos);
1569127675Sbms	if (i == 2 || i == 4)
1570127675Sbms	    *pos++ = '.';
157198527Sfenner	}
1572127675Sbms    if (id_len >= NODE_ID_LEN) {
1573127675Sbms        snprintf(pos, sizeof(id) - (pos - id), ".%02x", *cp++);
1574127675Sbms	pos += strlen(pos);
1575127675Sbms    }
1576127675Sbms    if (id_len == LSP_ID_LEN)
1577127675Sbms        snprintf(pos, sizeof(id) - (pos - id), "-%02x", *cp);
1578127675Sbms    return (id);
157998527Sfenner}
158098527Sfenner
1581127675Sbms/* print the 4-byte metric block which is common found in the old-style TLVs */
158298527Sfennerstatic int
1583127675Sbmsisis_print_metric_block (const struct isis_metric_block *isis_metric_block)
158498527Sfenner{
1585127675Sbms    printf(", Default Metric: %d, %s",
1586127675Sbms           ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_default),
1587127675Sbms           ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_default) ? "External" : "Internal");
1588127675Sbms    if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_delay))
1589127675Sbms        printf("\n\t\t  Delay Metric: %d, %s",
1590127675Sbms               ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_delay),
1591127675Sbms               ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_delay) ? "External" : "Internal");
1592127675Sbms    if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_expense))
1593127675Sbms        printf("\n\t\t  Expense Metric: %d, %s",
1594127675Sbms               ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_expense),
1595127675Sbms               ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_expense) ? "External" : "Internal");
1596127675Sbms    if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_error))
1597127675Sbms        printf("\n\t\t  Error Metric: %d, %s",
1598127675Sbms               ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_error),
1599127675Sbms               ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_error) ? "External" : "Internal");
160098527Sfenner
1601127675Sbms    return(1); /* everything is ok */
160298527Sfenner}
160398527Sfenner
160498527Sfennerstatic int
1605127675Sbmsisis_print_tlv_ip_reach (const u_int8_t *cp, const char *ident, int length)
160698527Sfenner{
1607127675Sbms	int prefix_len;
1608127675Sbms	const struct isis_tlv_ip_reach *tlv_ip_reach;
160998527Sfenner
1610127675Sbms	tlv_ip_reach = (const struct isis_tlv_ip_reach *)cp;
1611127675Sbms
1612127675Sbms	while (length > 0) {
1613127675Sbms		if ((size_t)length < sizeof(*tlv_ip_reach)) {
1614127675Sbms			printf("short IPv4 Reachability (%d vs %lu)",
1615127675Sbms                               length,
1616127675Sbms                               (unsigned long)sizeof(*tlv_ip_reach));
161798527Sfenner			return (0);
161898527Sfenner		}
1619127675Sbms
1620127675Sbms		if (!TTEST(*tlv_ip_reach))
1621127675Sbms		    return (0);
1622127675Sbms
1623127675Sbms		prefix_len = mask2plen(EXTRACT_32BITS(tlv_ip_reach->mask));
1624127675Sbms
1625127675Sbms		if (prefix_len == -1)
1626127675Sbms			printf("%sIPv4 prefix: %s mask %s",
1627127675Sbms                               ident,
1628127675Sbms			       ipaddr_string((tlv_ip_reach->prefix)),
1629127675Sbms			       ipaddr_string((tlv_ip_reach->mask)));
1630127675Sbms		else
1631127675Sbms			printf("%sIPv4 prefix: %15s/%u",
1632127675Sbms                               ident,
1633127675Sbms			       ipaddr_string((tlv_ip_reach->prefix)),
1634127675Sbms			       prefix_len);
1635127675Sbms
1636127675Sbms		printf(", Distribution: %s, Metric: %u, %s",
1637127675Sbms                       ISIS_LSP_TLV_METRIC_UPDOWN(tlv_ip_reach->isis_metric_block.metric_default) ? "down" : "up",
1638127675Sbms                       ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_default),
1639127675Sbms                       ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_default) ? "External" : "Internal");
1640127675Sbms
1641127675Sbms		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_delay))
1642127675Sbms                    printf("%s  Delay Metric: %u, %s",
1643127675Sbms                           ident,
1644127675Sbms                           ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_delay),
1645127675Sbms                           ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_delay) ? "External" : "Internal");
1646127675Sbms
1647127675Sbms		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_expense))
1648127675Sbms                    printf("%s  Expense Metric: %u, %s",
1649127675Sbms                           ident,
1650127675Sbms                           ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_expense),
1651127675Sbms                           ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_expense) ? "External" : "Internal");
1652127675Sbms
1653127675Sbms		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_error))
1654127675Sbms                    printf("%s  Error Metric: %u, %s",
1655127675Sbms                           ident,
1656127675Sbms                           ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_error),
1657127675Sbms                           ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_error) ? "External" : "Internal");
1658127675Sbms
1659127675Sbms		length -= sizeof(struct isis_tlv_ip_reach);
1660127675Sbms		tlv_ip_reach++;
166198527Sfenner	}
166298527Sfenner	return (1);
166398527Sfenner}
166498527Sfenner
1665127675Sbms/*
1666127675Sbms * this is the common IP-REACH subTLV decoder it is called
1667127675Sbms * from various EXTD-IP REACH TLVs (135,235,236,237)
1668127675Sbms */
166998527Sfenner
1670127675Sbmsstatic int
1671127675Sbmsisis_print_ip_reach_subtlv (const u_int8_t *tptr,int subt,int subl,const char *ident) {
1672127675Sbms
1673127675Sbms        /* first lets see if we know the subTLVs name*/
1674127675Sbms	printf("%s%s subTLV #%u, length: %u",
1675127675Sbms	       ident,
1676127675Sbms               tok2str(isis_ext_ip_reach_subtlv_values,
1677127675Sbms                       "unknown",
1678127675Sbms                       subt),
1679127675Sbms               subt,
1680127675Sbms               subl);
1681127675Sbms
1682127675Sbms	if (!TTEST2(*tptr,subl))
1683127675Sbms	    goto trunctlv;
1684127675Sbms
1685127675Sbms    switch(subt) {
1686146778Ssam    case ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR: /* fall through */
1687146778Ssam    case ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32:
1688127675Sbms        while (subl >= 4) {
1689127675Sbms	    printf(", 0x%08x (=%u)",
1690127675Sbms		   EXTRACT_32BITS(tptr),
1691127675Sbms		   EXTRACT_32BITS(tptr));
1692127675Sbms	    tptr+=4;
1693127675Sbms	    subl-=4;
169417688Spst	}
1695127675Sbms	break;
1696146778Ssam    case ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64:
1697127675Sbms        while (subl >= 8) {
1698127675Sbms	    printf(", 0x%08x%08x",
1699127675Sbms		   EXTRACT_32BITS(tptr),
1700127675Sbms		   EXTRACT_32BITS(tptr+4));
1701127675Sbms	    tptr+=8;
1702127675Sbms	    subl-=8;
1703127675Sbms	}
1704127675Sbms	break;
1705127675Sbms    default:
1706127675Sbms	if(!print_unknown_data(tptr,"\n\t\t    ",
1707127675Sbms			       subl))
1708127675Sbms	  return(0);
1709127675Sbms	break;
1710127675Sbms    }
1711127675Sbms    return(1);
1712127675Sbms
1713127675Sbmstrunctlv:
1714127675Sbms    printf("%spacket exceeded snapshot",ident);
1715127675Sbms    return(0);
171698527Sfenner}
171717688Spst
1718127675Sbms/*
1719127675Sbms * this is the common IS-REACH subTLV decoder it is called
1720127675Sbms * from isis_print_ext_is_reach()
1721127675Sbms */
1722127675Sbms
172398527Sfennerstatic int
1724162021Ssamisis_print_is_reach_subtlv (const u_int8_t *tptr,u_int subt,u_int subl,const char *ident) {
172598527Sfenner
1726190207Srpaulo        u_int te_class,priority_level,gmpls_switch_cap;
1727127675Sbms        union { /* int to float conversion buffer for several subTLVs */
1728127675Sbms            float f;
1729127675Sbms            u_int32_t i;
1730127675Sbms        } bw;
173198527Sfenner
1732127675Sbms        /* first lets see if we know the subTLVs name*/
1733127675Sbms	printf("%s%s subTLV #%u, length: %u",
1734127675Sbms	       ident,
1735127675Sbms               tok2str(isis_ext_is_reach_subtlv_values,
1736127675Sbms                       "unknown",
1737127675Sbms                       subt),
1738127675Sbms               subt,
1739127675Sbms               subl);
174098527Sfenner
1741127675Sbms	if (!TTEST2(*tptr,subl))
1742127675Sbms	    goto trunctlv;
174398527Sfenner
1744127675Sbms        switch(subt) {
1745146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP:
1746146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID:
1747146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID:
1748127675Sbms	    if (subl >= 4) {
1749127675Sbms	      printf(", 0x%08x", EXTRACT_32BITS(tptr));
1750190207Srpaulo	      if (subl == 8) /* rfc4205 */
1751127675Sbms	        printf(", 0x%08x", EXTRACT_32BITS(tptr+4));
1752127675Sbms	    }
1753127675Sbms	    break;
1754146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR:
1755146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR:
1756162021Ssam            if (subl >= sizeof(struct in_addr))
1757127675Sbms              printf(", %s", ipaddr_string(tptr));
1758127675Sbms            break;
1759146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW :
1760146778Ssam	case ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW:
1761127675Sbms            if (subl >= 4) {
1762127675Sbms              bw.i = EXTRACT_32BITS(tptr);
1763127675Sbms              printf(", %.3f Mbps", bw.f*8/1000000 );
1764127675Sbms            }
1765127675Sbms            break;
1766146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW :
1767127675Sbms            if (subl >= 32) {
1768162021Ssam              for (te_class = 0; te_class < 8; te_class++) {
1769127675Sbms                bw.i = EXTRACT_32BITS(tptr);
1770162021Ssam                printf("%s  TE-Class %u: %.3f Mbps",
1771127675Sbms                       ident,
1772162021Ssam                       te_class,
1773127675Sbms                       bw.f*8/1000000 );
1774127675Sbms		tptr+=4;
1775127675Sbms	      }
1776127675Sbms            }
1777127675Sbms            break;
1778162021Ssam        case ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS: /* fall through */
1779162021Ssam        case ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS_OLD:
1780146778Ssam            printf("%sBandwidth Constraints Model ID: %s (%u)",
1781146778Ssam                   ident,
1782146778Ssam                   tok2str(diffserv_te_bc_values, "unknown", *tptr),
1783146778Ssam                   *tptr);
1784146778Ssam            tptr++;
1785146778Ssam            /* decode BCs until the subTLV ends */
1786162021Ssam            for (te_class = 0; te_class < (subl-1)/4; te_class++) {
1787146778Ssam                bw.i = EXTRACT_32BITS(tptr);
1788162021Ssam                printf("%s  Bandwidth constraint CT%u: %.3f Mbps",
1789146778Ssam                       ident,
1790162021Ssam                       te_class,
1791146778Ssam                       bw.f*8/1000000 );
1792146778Ssam		tptr+=4;
1793146778Ssam            }
1794146778Ssam            break;
1795146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC:
1796127675Sbms            if (subl >= 3)
1797127675Sbms              printf(", %u", EXTRACT_24BITS(tptr));
1798127675Sbms            break;
1799190207Srpaulo        case ISIS_SUBTLV_EXT_IS_REACH_LINK_ATTRIBUTE:
1800190207Srpaulo            if (subl == 2) {
1801190207Srpaulo               printf(", [ %s ] (0x%04x)",
1802190207Srpaulo                      bittok2str(isis_subtlv_link_attribute_values,
1803190207Srpaulo                                 "Unknown",
1804190207Srpaulo                                 EXTRACT_16BITS(tptr)),
1805190207Srpaulo                      EXTRACT_16BITS(tptr));
1806190207Srpaulo            }
1807190207Srpaulo            break;
1808146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE:
1809127675Sbms            if (subl >= 2) {
1810127675Sbms              printf(", %s, Priority %u",
1811127675Sbms		   bittok2str(gmpls_link_prot_values, "none", *tptr),
1812127675Sbms                   *(tptr+1));
1813127675Sbms            }
1814127675Sbms            break;
1815252283Sdelphij        case ISIS_SUBTLV_SPB_METRIC:
1816252283Sdelphij            if (subl >= 6) {
1817252283Sdelphij              printf (", LM: %u", EXTRACT_24BITS(tptr));
1818252283Sdelphij              tptr=tptr+3;
1819252283Sdelphij              printf (", P: %u", *(tptr));
1820252283Sdelphij              printf (", P-ID: %u", EXTRACT_16BITS(++tptr));
1821252283Sdelphij            }
1822252283Sdelphij            break;
1823146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR:
1824127675Sbms            if (subl >= 36) {
1825190207Srpaulo              gmpls_switch_cap = *tptr;
1826127675Sbms              printf("%s  Interface Switching Capability:%s",
1827127675Sbms                   ident,
1828190207Srpaulo                   tok2str(gmpls_switch_cap_values, "Unknown", gmpls_switch_cap));
1829127675Sbms              printf(", LSP Encoding: %s",
1830127675Sbms                   tok2str(gmpls_encoding_values, "Unknown", *(tptr+1)));
1831127675Sbms	      tptr+=4;
1832127675Sbms              printf("%s  Max LSP Bandwidth:",ident);
1833127675Sbms              for (priority_level = 0; priority_level < 8; priority_level++) {
1834127675Sbms                bw.i = EXTRACT_32BITS(tptr);
1835127675Sbms                printf("%s    priority level %d: %.3f Mbps",
1836127675Sbms                       ident,
1837127675Sbms                       priority_level,
1838127675Sbms                       bw.f*8/1000000 );
1839127675Sbms		tptr+=4;
1840127675Sbms              }
1841127675Sbms              subl-=36;
1842190207Srpaulo              switch (gmpls_switch_cap) {
1843190207Srpaulo              case GMPLS_PSC1:
1844190207Srpaulo              case GMPLS_PSC2:
1845190207Srpaulo              case GMPLS_PSC3:
1846190207Srpaulo              case GMPLS_PSC4:
1847190207Srpaulo                bw.i = EXTRACT_32BITS(tptr);
1848190207Srpaulo                printf("%s  Min LSP Bandwidth: %.3f Mbps", ident, bw.f*8/1000000);
1849190207Srpaulo                printf("%s  Interface MTU: %u", ident, EXTRACT_16BITS(tptr+4));
1850190207Srpaulo                break;
1851190207Srpaulo              case GMPLS_TSC:
1852190207Srpaulo                bw.i = EXTRACT_32BITS(tptr);
1853190207Srpaulo                printf("%s  Min LSP Bandwidth: %.3f Mbps", ident, bw.f*8/1000000);
1854190207Srpaulo                printf("%s  Indication %s", ident,
1855190207Srpaulo                       tok2str(gmpls_switch_cap_tsc_indication_values, "Unknown (%u)", *(tptr+4)));
1856190207Srpaulo                break;
1857190207Srpaulo              default:
1858190207Srpaulo                /* there is some optional stuff left to decode but this is as of yet
1859190207Srpaulo                   not specified so just lets hexdump what is left */
1860190207Srpaulo                if(subl>0){
1861190207Srpaulo                  if(!print_unknown_data(tptr,"\n\t\t    ",
1862190207Srpaulo                                         subl))
1863127675Sbms                    return(0);
1864190207Srpaulo                }
1865127675Sbms              }
1866127675Sbms            }
1867127675Sbms            break;
1868127675Sbms        default:
1869127675Sbms            if(!print_unknown_data(tptr,"\n\t\t    ",
1870127675Sbms				   subl))
1871127675Sbms                return(0);
1872127675Sbms            break;
1873127675Sbms        }
1874127675Sbms        return(1);
187598527Sfenner
1876127675Sbmstrunctlv:
1877127675Sbms    printf("%spacket exceeded snapshot",ident);
1878127675Sbms    return(0);
1879127675Sbms}
188098527Sfenner
188198527Sfenner
1882127675Sbms/*
1883127675Sbms * this is the common IS-REACH decoder it is called
1884127675Sbms * from various EXTD-IS REACH style TLVs (22,24,222)
1885127675Sbms */
188698527Sfenner
1887127675Sbmsstatic int
1888127675Sbmsisis_print_ext_is_reach (const u_int8_t *tptr,const char *ident, int tlv_type) {
188998527Sfenner
1890127675Sbms    char ident_buffer[20];
1891127675Sbms    int subtlv_type,subtlv_len,subtlv_sum_len;
1892127675Sbms    int proc_bytes = 0; /* how many bytes did we process ? */
1893127675Sbms
1894127675Sbms    if (!TTEST2(*tptr, NODE_ID_LEN))
1895127675Sbms        return(0);
189698527Sfenner
1897127675Sbms    printf("%sIS Neighbor: %s", ident, isis_print_id(tptr, NODE_ID_LEN));
1898127675Sbms    tptr+=(NODE_ID_LEN);
189998527Sfenner
1900146778Ssam    if (tlv_type != ISIS_TLV_IS_ALIAS_ID) { /* the Alias TLV Metric field is implicit 0 */
1901127675Sbms        if (!TTEST2(*tptr, 3))    /* and is therefore skipped */
1902127675Sbms	    return(0);
1903127675Sbms	printf(", Metric: %d",EXTRACT_24BITS(tptr));
1904127675Sbms	tptr+=3;
1905127675Sbms    }
1906127675Sbms
1907127675Sbms    if (!TTEST2(*tptr, 1))
1908127675Sbms        return(0);
1909127675Sbms    subtlv_sum_len=*(tptr++); /* read out subTLV length */
1910127675Sbms    proc_bytes=NODE_ID_LEN+3+1;
1911127675Sbms    printf(", %ssub-TLVs present",subtlv_sum_len ? "" : "no ");
1912127675Sbms    if (subtlv_sum_len) {
1913127675Sbms        printf(" (%u)",subtlv_sum_len);
1914127675Sbms        while (subtlv_sum_len>0) {
1915127675Sbms            if (!TTEST2(*tptr,2))
1916127675Sbms                return(0);
1917127675Sbms            subtlv_type=*(tptr++);
1918127675Sbms            subtlv_len=*(tptr++);
1919127675Sbms            /* prepend the ident string */
1920127675Sbms            snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
1921127675Sbms            if(!isis_print_is_reach_subtlv(tptr,subtlv_type,subtlv_len,ident_buffer))
1922127675Sbms                return(0);
1923127675Sbms            tptr+=subtlv_len;
1924127675Sbms            subtlv_sum_len-=(subtlv_len+2);
1925127675Sbms            proc_bytes+=(subtlv_len+2);
1926127675Sbms        }
1927127675Sbms    }
1928127675Sbms    return(proc_bytes);
192917688Spst}
193017688Spst
193117688Spst/*
1932127675Sbms * this is the common Multi Topology ID decoder
1933127675Sbms * it is called from various MT-TLVs (222,229,235,237)
1934127675Sbms */
1935127675Sbms
1936127675Sbmsstatic int
1937127675Sbmsisis_print_mtid (const u_int8_t *tptr,const char *ident) {
1938127675Sbms
1939127675Sbms    if (!TTEST2(*tptr, 2))
1940127675Sbms        return(0);
1941127675Sbms
1942127675Sbms    printf("%s%s",
1943127675Sbms           ident,
1944127675Sbms           tok2str(isis_mt_values,
1945127675Sbms                   "Reserved for IETF Consensus",
1946127675Sbms                   ISIS_MASK_MTID(EXTRACT_16BITS(tptr))));
1947127675Sbms
1948127675Sbms    printf(" Topology (0x%03x), Flags: [%s]",
1949127675Sbms           ISIS_MASK_MTID(EXTRACT_16BITS(tptr)),
1950127675Sbms           bittok2str(isis_mt_flag_values, "none",ISIS_MASK_MTFLAGS(EXTRACT_16BITS(tptr))));
1951127675Sbms
1952127675Sbms    return(2);
1953127675Sbms}
1954127675Sbms
1955127675Sbms/*
1956127675Sbms * this is the common extended IP reach decoder
1957127675Sbms * it is called from TLVs (135,235,236,237)
1958127675Sbms * we process the TLV and optional subTLVs and return
1959127675Sbms * the amount of processed bytes
1960127675Sbms */
1961127675Sbms
1962127675Sbmsstatic int
1963127675Sbmsisis_print_extd_ip_reach (const u_int8_t *tptr, const char *ident, u_int16_t afi) {
1964127675Sbms
1965127675Sbms    char ident_buffer[20];
1966172686Smlaier#ifdef INET6
1967162021Ssam    u_int8_t prefix[sizeof(struct in6_addr)]; /* shared copy buffer for IPv4 and IPv6 prefixes */
1968172686Smlaier#else
1969172686Smlaier    u_int8_t prefix[sizeof(struct in_addr)]; /* shared copy buffer for IPv4 prefixes */
1970172686Smlaier#endif
1971127675Sbms    u_int metric, status_byte, bit_length, byte_length, sublen, processed, subtlvtype, subtlvlen;
1972127675Sbms
1973127675Sbms    if (!TTEST2(*tptr, 4))
1974127675Sbms        return (0);
1975127675Sbms    metric = EXTRACT_32BITS(tptr);
1976127675Sbms    processed=4;
1977127675Sbms    tptr+=4;
1978127675Sbms
1979190207Srpaulo    if (afi == AF_INET) {
1980127675Sbms        if (!TTEST2(*tptr, 1)) /* fetch status byte */
1981127675Sbms            return (0);
1982127675Sbms        status_byte=*(tptr++);
1983127675Sbms        bit_length = status_byte&0x3f;
1984172686Smlaier        if (bit_length > 32) {
1985172686Smlaier            printf("%sIPv4 prefix: bad bit length %u",
1986172686Smlaier                   ident,
1987172686Smlaier                   bit_length);
1988172686Smlaier            return (0);
1989172686Smlaier        }
1990127675Sbms        processed++;
1991127675Sbms#ifdef INET6
1992190207Srpaulo    } else if (afi == AF_INET6) {
1993127675Sbms        if (!TTEST2(*tptr, 1)) /* fetch status & prefix_len byte */
1994127675Sbms            return (0);
1995127675Sbms        status_byte=*(tptr++);
1996127675Sbms        bit_length=*(tptr++);
1997172686Smlaier        if (bit_length > 128) {
1998172686Smlaier            printf("%sIPv6 prefix: bad bit length %u",
1999172686Smlaier                   ident,
2000172686Smlaier                   bit_length);
2001172686Smlaier            return (0);
2002172686Smlaier        }
2003127675Sbms        processed+=2;
2004127675Sbms#endif
2005127675Sbms    } else
2006127675Sbms        return (0); /* somebody is fooling us */
2007127675Sbms
2008127675Sbms    byte_length = (bit_length + 7) / 8; /* prefix has variable length encoding */
2009127675Sbms
2010127675Sbms    if (!TTEST2(*tptr, byte_length))
2011127675Sbms        return (0);
2012172686Smlaier    memset(prefix, 0, sizeof prefix);   /* clear the copy buffer */
2013127675Sbms    memcpy(prefix,tptr,byte_length);    /* copy as much as is stored in the TLV */
2014127675Sbms    tptr+=byte_length;
2015127675Sbms    processed+=byte_length;
2016127675Sbms
2017190207Srpaulo    if (afi == AF_INET)
2018127675Sbms        printf("%sIPv4 prefix: %15s/%u",
2019127675Sbms               ident,
2020127675Sbms               ipaddr_string(prefix),
2021127675Sbms               bit_length);
2022127675Sbms#ifdef INET6
2023190207Srpaulo    if (afi == AF_INET6)
2024127675Sbms        printf("%sIPv6 prefix: %s/%u",
2025127675Sbms               ident,
2026127675Sbms               ip6addr_string(prefix),
2027127675Sbms               bit_length);
2028127675Sbms#endif
2029127675Sbms
2030127675Sbms    printf(", Distribution: %s, Metric: %u",
2031127675Sbms           ISIS_MASK_TLV_EXTD_IP_UPDOWN(status_byte) ? "down" : "up",
2032127675Sbms           metric);
2033127675Sbms
2034190207Srpaulo    if (afi == AF_INET && ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte))
2035127675Sbms        printf(", sub-TLVs present");
2036127675Sbms#ifdef INET6
2037190207Srpaulo    if (afi == AF_INET6)
2038127675Sbms        printf(", %s%s",
2039127675Sbms               ISIS_MASK_TLV_EXTD_IP6_IE(status_byte) ? "External" : "Internal",
2040127675Sbms               ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte) ? ", sub-TLVs present" : "");
2041127675Sbms#endif
2042127675Sbms
2043190207Srpaulo    if ((afi == AF_INET  && ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte))
2044190207Srpaulo#ifdef INET6
2045190207Srpaulo     || (afi == AF_INET6 && ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte))
2046190207Srpaulo#endif
2047190207Srpaulo	) {
2048127675Sbms        /* assume that one prefix can hold more
2049127675Sbms           than one subTLV - therefore the first byte must reflect
2050127675Sbms           the aggregate bytecount of the subTLVs for this prefix
2051127675Sbms        */
2052127675Sbms        if (!TTEST2(*tptr, 1))
2053127675Sbms            return (0);
2054127675Sbms        sublen=*(tptr++);
2055127675Sbms        processed+=sublen+1;
2056127675Sbms        printf(" (%u)",sublen);   /* print out subTLV length */
2057127675Sbms
2058127675Sbms        while (sublen>0) {
2059127675Sbms            if (!TTEST2(*tptr,2))
2060127675Sbms                return (0);
2061127675Sbms            subtlvtype=*(tptr++);
2062127675Sbms            subtlvlen=*(tptr++);
2063127675Sbms            /* prepend the ident string */
2064127675Sbms            snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
2065127675Sbms            if(!isis_print_ip_reach_subtlv(tptr,subtlvtype,subtlvlen,ident_buffer))
2066127675Sbms                return(0);
2067127675Sbms            tptr+=subtlvlen;
2068127675Sbms            sublen-=(subtlvlen+2);
2069127675Sbms        }
2070127675Sbms    }
2071127675Sbms    return (processed);
2072127675Sbms}
2073127675Sbms
2074127675Sbms/*
207517688Spst * isis_print
207617688Spst * Decode IS-IS packets.  Return 0 on error.
207717688Spst */
207817688Spst
2079127675Sbmsstatic int isis_print (const u_int8_t *p, u_int length)
208017688Spst{
2081146778Ssam    const struct isis_common_header *isis_header;
208217688Spst
208398527Sfenner    const struct isis_iih_lan_header *header_iih_lan;
208498527Sfenner    const struct isis_iih_ptp_header *header_iih_ptp;
2085214478Srpaulo    struct isis_lsp_header *header_lsp;
208698527Sfenner    const struct isis_csnp_header *header_csnp;
208798527Sfenner    const struct isis_psnp_header *header_psnp;
208817688Spst
208998527Sfenner    const struct isis_tlv_lsp *tlv_lsp;
209098527Sfenner    const struct isis_tlv_ptp_adj *tlv_ptp_adj;
209198527Sfenner    const struct isis_tlv_is_reach *tlv_is_reach;
2092127675Sbms    const struct isis_tlv_es_reach *tlv_es_reach;
209398527Sfenner
2094127675Sbms    u_int8_t pdu_type, max_area, id_length, tlv_type, tlv_len, tmp, alen, lan_alen, prefix_len;
2095127675Sbms    u_int8_t ext_is_len, ext_ip_len, mt_len;
2096127675Sbms    const u_int8_t *optr, *pptr, *tptr;
2097236192Sdelphij    u_short packet_len,pdu_len, key_id;
2098146778Ssam    u_int i,vendor_id;
2099214478Srpaulo    int sigcheck;
210098527Sfenner
210198527Sfenner    packet_len=length;
2102127675Sbms    optr = p; /* initialize the _o_riginal pointer to the packet start -
2103214478Srpaulo                 need it for parsing the checksum TLV and authentication
2104214478Srpaulo                 TLV verification */
2105146778Ssam    isis_header = (const struct isis_common_header *)p;
2106146778Ssam    TCHECK(*isis_header);
2107127675Sbms    pptr = p+(ISIS_COMMON_HEADER_SIZE);
210898527Sfenner    header_iih_lan = (const struct isis_iih_lan_header *)pptr;
210998527Sfenner    header_iih_ptp = (const struct isis_iih_ptp_header *)pptr;
2110214478Srpaulo    header_lsp = (struct isis_lsp_header *)pptr;
211198527Sfenner    header_csnp = (const struct isis_csnp_header *)pptr;
211298527Sfenner    header_psnp = (const struct isis_psnp_header *)pptr;
2113127675Sbms
2114146778Ssam    if (!eflag)
2115146778Ssam        printf("IS-IS");
2116146778Ssam
211717688Spst    /*
211817688Spst     * Sanity checking of the header.
211917688Spst     */
212017688Spst
2121146778Ssam    if (isis_header->version != ISIS_VERSION) {
2122146778Ssam	printf("version %d packet not supported", isis_header->version);
212398527Sfenner	return (0);
212417688Spst    }
212517688Spst
2126146778Ssam    if ((isis_header->id_length != SYSTEM_ID_LEN) && (isis_header->id_length != 0)) {
2127146778Ssam	printf("system ID length of %d is not supported",
2128146778Ssam	       isis_header->id_length);
212998527Sfenner	return (0);
213017688Spst    }
2131127675Sbms
2132146778Ssam    if (isis_header->pdu_version != ISIS_VERSION) {
2133146778Ssam	printf("version %d packet not supported", isis_header->pdu_version);
213498527Sfenner	return (0);
213517688Spst    }
213617688Spst
2137146778Ssam    max_area = isis_header->max_area;
213817688Spst    switch(max_area) {
213917688Spst    case 0:
2140127675Sbms	max_area = 3;	 /* silly shit */
214117688Spst	break;
214217688Spst    case 255:
2143146778Ssam	printf("bad packet -- 255 areas");
214498527Sfenner	return (0);
214517688Spst    default:
214617688Spst	break;
214717688Spst    }
214817688Spst
2149146778Ssam    id_length = isis_header->id_length;
2150127675Sbms    switch(id_length) {
2151127675Sbms    case 0:
2152127675Sbms        id_length = 6;	 /* silly shit again */
2153127675Sbms	break;
2154127675Sbms    case 1:              /* 1-8 are valid sys-ID lenghts */
2155127675Sbms    case 2:
2156127675Sbms    case 3:
2157127675Sbms    case 4:
2158127675Sbms    case 5:
2159127675Sbms    case 6:
2160127675Sbms    case 7:
2161127675Sbms    case 8:
2162127675Sbms        break;
2163127675Sbms    case 255:
2164127675Sbms        id_length = 0;   /* entirely useless */
2165127675Sbms	break;
2166127675Sbms    default:
2167127675Sbms        break;
2168127675Sbms    }
2169127675Sbms
2170127675Sbms    /* toss any non 6-byte sys-ID len PDUs */
2171127675Sbms    if (id_length != 6 ) {
2172146778Ssam	printf("bad packet -- illegal sys-ID length (%u)", id_length);
2173127675Sbms	return (0);
2174127675Sbms    }
2175127675Sbms
2176146778Ssam    pdu_type=isis_header->pdu_type;
2177127675Sbms
2178127675Sbms    /* in non-verbose mode print the basic PDU Type plus PDU specific brief information*/
2179127675Sbms    if (vflag < 1) {
2180146778Ssam        printf("%s%s",
2181146778Ssam               eflag ? "" : ", ",
2182127675Sbms               tok2str(isis_pdu_values,"unknown PDU-Type %u",pdu_type));
2183127675Sbms
2184127675Sbms	switch (pdu_type) {
2185127675Sbms
2186146778Ssam	case ISIS_PDU_L1_LAN_IIH:
2187146778Ssam	case ISIS_PDU_L2_LAN_IIH:
2188127675Sbms	    printf(", src-id %s",
2189127675Sbms                   isis_print_id(header_iih_lan->source_id,SYSTEM_ID_LEN));
2190127675Sbms	    printf(", lan-id %s, prio %u",
2191127675Sbms                   isis_print_id(header_iih_lan->lan_id,NODE_ID_LEN),
2192127675Sbms                   header_iih_lan->priority);
2193127675Sbms	    break;
2194146778Ssam	case ISIS_PDU_PTP_IIH:
2195127675Sbms	    printf(", src-id %s", isis_print_id(header_iih_ptp->source_id,SYSTEM_ID_LEN));
2196127675Sbms	    break;
2197146778Ssam	case ISIS_PDU_L1_LSP:
2198146778Ssam	case ISIS_PDU_L2_LSP:
2199127675Sbms	    printf(", lsp-id %s, seq 0x%08x, lifetime %5us",
2200127675Sbms		   isis_print_id(header_lsp->lsp_id, LSP_ID_LEN),
2201127675Sbms		   EXTRACT_32BITS(header_lsp->sequence_number),
2202127675Sbms		   EXTRACT_16BITS(header_lsp->remaining_lifetime));
2203127675Sbms	    break;
2204146778Ssam	case ISIS_PDU_L1_CSNP:
2205146778Ssam	case ISIS_PDU_L2_CSNP:
2206146778Ssam	    printf(", src-id %s", isis_print_id(header_csnp->source_id,NODE_ID_LEN));
2207127675Sbms	    break;
2208146778Ssam	case ISIS_PDU_L1_PSNP:
2209146778Ssam	case ISIS_PDU_L2_PSNP:
2210146778Ssam	    printf(", src-id %s", isis_print_id(header_psnp->source_id,NODE_ID_LEN));
2211127675Sbms	    break;
2212127675Sbms
2213127675Sbms	}
2214127675Sbms	printf(", length %u", length);
2215127675Sbms
2216127675Sbms        return(1);
2217127675Sbms    }
2218127675Sbms
2219127675Sbms    /* ok they seem to want to know everything - lets fully decode it */
2220146778Ssam    printf("%slength %u", eflag ? "" : ", ",length);
2221127675Sbms
2222127675Sbms    printf("\n\t%s, hlen: %u, v: %u, pdu-v: %u, sys-id-len: %u (%u), max-area: %u (%u)",
2223127675Sbms           tok2str(isis_pdu_values,
2224127675Sbms                   "unknown, type %u",
2225127675Sbms                   pdu_type),
2226146778Ssam           isis_header->fixed_len,
2227146778Ssam           isis_header->version,
2228146778Ssam           isis_header->pdu_version,
2229127675Sbms	   id_length,
2230146778Ssam	   isis_header->id_length,
223198527Sfenner           max_area,
2232146778Ssam           isis_header->max_area);
2233127675Sbms
2234127675Sbms    if (vflag > 1) {
2235127675Sbms        if(!print_unknown_data(optr,"\n\t",8)) /* provide the _o_riginal pointer */
2236127675Sbms            return(0);                         /* for optionally debugging the common header */
2237127675Sbms    }
2238127675Sbms
223998527Sfenner    switch (pdu_type) {
224098527Sfenner
2241146778Ssam    case ISIS_PDU_L1_LAN_IIH:
2242146778Ssam    case ISIS_PDU_L2_LAN_IIH:
2243146778Ssam	if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE)) {
224498527Sfenner	    printf(", bogus fixed header length %u should be %lu",
2245146778Ssam		   isis_header->fixed_len, (unsigned long)ISIS_IIH_LAN_HEADER_SIZE);
224698527Sfenner	    return (0);
224717688Spst	}
224898527Sfenner
224998527Sfenner	pdu_len=EXTRACT_16BITS(header_iih_lan->pdu_len);
225098527Sfenner	if (packet_len>pdu_len) {
2251127675Sbms            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
2252127675Sbms            length=pdu_len;
225398527Sfenner	}
225498527Sfenner
225598527Sfenner	TCHECK(*header_iih_lan);
2256127675Sbms	printf("\n\t  source-id: %s,  holding time: %us, Flags: [%s]",
2257127675Sbms               isis_print_id(header_iih_lan->source_id,SYSTEM_ID_LEN),
2258127675Sbms               EXTRACT_16BITS(header_iih_lan->holding_time),
2259127675Sbms               tok2str(isis_iih_circuit_type_values,
2260127675Sbms                       "unknown circuit type 0x%02x",
2261127675Sbms                       header_iih_lan->circuit_type));
226298527Sfenner
2263127675Sbms	printf("\n\t  lan-id:    %s, Priority: %u, PDU length: %u",
2264127675Sbms               isis_print_id(header_iih_lan->lan_id, NODE_ID_LEN),
2265146778Ssam               (header_iih_lan->priority) & ISIS_LAN_PRIORITY_MASK,
2266127675Sbms               pdu_len);
226798527Sfenner
2268127675Sbms        if (vflag > 1) {
2269127675Sbms            if(!print_unknown_data(pptr,"\n\t  ",ISIS_IIH_LAN_HEADER_SIZE))
2270127675Sbms                return(0);
2271127675Sbms        }
227298527Sfenner
227398527Sfenner	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
227498527Sfenner	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
227517688Spst	break;
227698527Sfenner
2277146778Ssam    case ISIS_PDU_PTP_IIH:
2278146778Ssam	if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE)) {
227998527Sfenner	    printf(", bogus fixed header length %u should be %lu",
2280146778Ssam		   isis_header->fixed_len, (unsigned long)ISIS_IIH_PTP_HEADER_SIZE);
228198527Sfenner	    return (0);
228217688Spst	}
2283127675Sbms
228498527Sfenner	pdu_len=EXTRACT_16BITS(header_iih_ptp->pdu_len);
228598527Sfenner	if (packet_len>pdu_len) {
2286127675Sbms            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
2287127675Sbms            length=pdu_len;
228898527Sfenner	}
2289127675Sbms
229098527Sfenner	TCHECK(*header_iih_ptp);
2291127675Sbms	printf("\n\t  source-id: %s, holding time: %us, Flags: [%s]",
2292127675Sbms               isis_print_id(header_iih_ptp->source_id,SYSTEM_ID_LEN),
2293127675Sbms               EXTRACT_16BITS(header_iih_ptp->holding_time),
2294127675Sbms               tok2str(isis_iih_circuit_type_values,
2295127675Sbms                       "unknown circuit type 0x%02x",
2296127675Sbms                       header_iih_ptp->circuit_type));
229798527Sfenner
2298127675Sbms	printf("\n\t  circuit-id: 0x%02x, PDU length: %u",
2299127675Sbms               header_iih_ptp->circuit_id,
2300127675Sbms               pdu_len);
230198527Sfenner
2302127675Sbms        if (vflag > 1) {
2303127675Sbms            if(!print_unknown_data(pptr,"\n\t  ",ISIS_IIH_PTP_HEADER_SIZE))
2304127675Sbms                return(0);
2305127675Sbms        }
230698527Sfenner
230798527Sfenner	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
230898527Sfenner	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
230917688Spst	break;
231098527Sfenner
2311146778Ssam    case ISIS_PDU_L1_LSP:
2312146778Ssam    case ISIS_PDU_L2_LSP:
2313146778Ssam	if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE)) {
231498527Sfenner	    printf(", bogus fixed header length %u should be %lu",
2315146778Ssam		   isis_header->fixed_len, (unsigned long)ISIS_LSP_HEADER_SIZE);
231698527Sfenner	    return (0);
231798527Sfenner	}
2318127675Sbms
231998527Sfenner	pdu_len=EXTRACT_16BITS(header_lsp->pdu_len);
232098527Sfenner	if (packet_len>pdu_len) {
2321127675Sbms            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
2322127675Sbms            length=pdu_len;
232398527Sfenner	}
232498527Sfenner
232598527Sfenner	TCHECK(*header_lsp);
2326127675Sbms	printf("\n\t  lsp-id: %s, seq: 0x%08x, lifetime: %5us\n\t  chksum: 0x%04x",
2327127675Sbms               isis_print_id(header_lsp->lsp_id, LSP_ID_LEN),
2328127675Sbms               EXTRACT_32BITS(header_lsp->sequence_number),
2329127675Sbms               EXTRACT_16BITS(header_lsp->remaining_lifetime),
2330127675Sbms               EXTRACT_16BITS(header_lsp->checksum));
233198527Sfenner
2332127675Sbms
2333190207Srpaulo        osi_print_cksum((u_int8_t *)header_lsp->lsp_id,
2334190207Srpaulo                        EXTRACT_16BITS(header_lsp->checksum), 12, length-12);
2335190207Srpaulo
2336214478Srpaulo        /*
2337214478Srpaulo         * Clear checksum and lifetime prior to signature verification.
2338214478Srpaulo         */
2339214478Srpaulo        header_lsp->checksum[0] = 0;
2340214478Srpaulo        header_lsp->checksum[1] = 0;
2341214478Srpaulo        header_lsp->remaining_lifetime[0] = 0;
2342214478Srpaulo        header_lsp->remaining_lifetime[1] = 0;
2343214478Srpaulo
2344214478Srpaulo
2345127675Sbms	printf(", PDU length: %u, Flags: [ %s",
2346127675Sbms               pdu_len,
2347127675Sbms               ISIS_MASK_LSP_OL_BIT(header_lsp->typeblock) ? "Overload bit set, " : "");
2348127675Sbms
234998527Sfenner	if (ISIS_MASK_LSP_ATT_BITS(header_lsp->typeblock)) {
235098527Sfenner	    printf("%s", ISIS_MASK_LSP_ATT_DEFAULT_BIT(header_lsp->typeblock) ? "default " : "");
235198527Sfenner	    printf("%s", ISIS_MASK_LSP_ATT_DELAY_BIT(header_lsp->typeblock) ? "delay " : "");
235298527Sfenner	    printf("%s", ISIS_MASK_LSP_ATT_EXPENSE_BIT(header_lsp->typeblock) ? "expense " : "");
235398527Sfenner	    printf("%s", ISIS_MASK_LSP_ATT_ERROR_BIT(header_lsp->typeblock) ? "error " : "");
235498527Sfenner	    printf("ATT bit set, ");
235598527Sfenner	}
235698527Sfenner	printf("%s", ISIS_MASK_LSP_PARTITION_BIT(header_lsp->typeblock) ? "P bit set, " : "");
2357127675Sbms	printf("%s ]", tok2str(isis_lsp_istype_values,"Unknown(0x%x)",ISIS_MASK_LSP_ISTYPE_BITS(header_lsp->typeblock)));
235898527Sfenner
2359127675Sbms        if (vflag > 1) {
2360127675Sbms            if(!print_unknown_data(pptr,"\n\t  ",ISIS_LSP_HEADER_SIZE))
2361127675Sbms                return(0);
2362127675Sbms        }
2363127675Sbms
236498527Sfenner	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
236598527Sfenner	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
236617688Spst	break;
236798527Sfenner
2368146778Ssam    case ISIS_PDU_L1_CSNP:
2369146778Ssam    case ISIS_PDU_L2_CSNP:
2370146778Ssam	if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE)) {
237198527Sfenner	    printf(", bogus fixed header length %u should be %lu",
2372146778Ssam		   isis_header->fixed_len, (unsigned long)ISIS_CSNP_HEADER_SIZE);
237398527Sfenner	    return (0);
237498527Sfenner	}
2375127675Sbms
237698527Sfenner	pdu_len=EXTRACT_16BITS(header_csnp->pdu_len);
237798527Sfenner	if (packet_len>pdu_len) {
2378127675Sbms            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
2379127675Sbms            length=pdu_len;
238098527Sfenner	}
238117688Spst
238298527Sfenner	TCHECK(*header_csnp);
2383127675Sbms	printf("\n\t  source-id:    %s, PDU length: %u",
2384127675Sbms               isis_print_id(header_csnp->source_id, NODE_ID_LEN),
2385127675Sbms               pdu_len);
2386127675Sbms	printf("\n\t  start lsp-id: %s",
2387127675Sbms               isis_print_id(header_csnp->start_lsp_id, LSP_ID_LEN));
2388127675Sbms	printf("\n\t  end lsp-id:   %s",
2389127675Sbms               isis_print_id(header_csnp->end_lsp_id, LSP_ID_LEN));
239017688Spst
2391127675Sbms        if (vflag > 1) {
2392127675Sbms            if(!print_unknown_data(pptr,"\n\t  ",ISIS_CSNP_HEADER_SIZE))
2393127675Sbms                return(0);
2394127675Sbms        }
2395127675Sbms
239698527Sfenner	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
239798527Sfenner	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
239898527Sfenner        break;
239917688Spst
2400146778Ssam    case ISIS_PDU_L1_PSNP:
2401146778Ssam    case ISIS_PDU_L2_PSNP:
2402146778Ssam	if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE)) {
240398527Sfenner	    printf("- bogus fixed header length %u should be %lu",
2404146778Ssam		   isis_header->fixed_len, (unsigned long)ISIS_PSNP_HEADER_SIZE);
240598527Sfenner	    return (0);
240698527Sfenner	}
240798527Sfenner
240898527Sfenner	pdu_len=EXTRACT_16BITS(header_psnp->pdu_len);
240998527Sfenner	if (packet_len>pdu_len) {
2410127675Sbms            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
2411127675Sbms            length=pdu_len;
241298527Sfenner	}
241398527Sfenner
241498527Sfenner	TCHECK(*header_psnp);
2415127675Sbms	printf("\n\t  source-id:    %s, PDU length: %u",
2416127675Sbms               isis_print_id(header_psnp->source_id, NODE_ID_LEN),
2417127675Sbms               pdu_len);
2418127675Sbms
2419127675Sbms        if (vflag > 1) {
2420127675Sbms            if(!print_unknown_data(pptr,"\n\t  ",ISIS_PSNP_HEADER_SIZE))
2421127675Sbms                return(0);
2422127675Sbms        }
2423127675Sbms
242498527Sfenner	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
242598527Sfenner	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
242617688Spst	break;
242717688Spst
242898527Sfenner    default:
2429127675Sbms	if(!print_unknown_data(pptr,"\n\t  ",length))
2430127675Sbms	    return(0);
2431127675Sbms	return (0);
243217688Spst    }
243317688Spst
243417688Spst    /*
243517688Spst     * Now print the TLV's.
243617688Spst     */
2437127675Sbms
243817688Spst    while (packet_len >= 2) {
243998527Sfenner        if (pptr == snapend) {
244098527Sfenner	    return (1);
244198527Sfenner        }
244298527Sfenner
244398527Sfenner	if (!TTEST2(*pptr, 2)) {
2444127675Sbms	    printf("\n\t\t packet exceeded snapshot (%ld) bytes",
2445127675Sbms                   (long)(pptr-snapend));
244698527Sfenner	    return (1);
244717688Spst	}
2448127675Sbms	tlv_type = *pptr++;
2449127675Sbms	tlv_len = *pptr++;
2450127675Sbms        tmp =tlv_len; /* copy temporary len & pointer to packet data */
2451127675Sbms        tptr = pptr;
245217688Spst	packet_len -= 2;
2453127675Sbms	if (tlv_len > packet_len) {
245417688Spst	    break;
245517688Spst	}
245617688Spst
2457127675Sbms        /* first lets see if we know the TLVs name*/
2458127675Sbms	printf("\n\t    %s TLV #%u, length: %u",
2459127675Sbms               tok2str(isis_tlv_values,
2460127675Sbms                       "unknown",
2461127675Sbms                       tlv_type),
2462127675Sbms               tlv_type,
2463127675Sbms               tlv_len);
2464127675Sbms
2465147175Ssam        if (tlv_len == 0) /* something is malformed */
2466172686Smlaier	    continue;
2467147175Ssam
2468127675Sbms        /* now check if we have a decoder otherwise do a hexdump at the end*/
2469127675Sbms	switch (tlv_type) {
2470146778Ssam	case ISIS_TLV_AREA_ADDR:
247198527Sfenner	    if (!TTEST2(*tptr, 1))
247298527Sfenner		goto trunctlv;
247317688Spst	    alen = *tptr++;
247417688Spst	    while (tmp && alen < tmp) {
2475127675Sbms		printf("\n\t      Area address (length: %u): %s",
2476127675Sbms                       alen,
2477146778Ssam                       isonsap_string(tptr,alen));
247817688Spst		tptr += alen;
247917688Spst		tmp -= alen + 1;
248098527Sfenner		if (tmp==0) /* if this is the last area address do not attemt a boundary check */
2481127675Sbms                    break;
248298527Sfenner		if (!TTEST2(*tptr, 1))
248398527Sfenner		    goto trunctlv;
248417688Spst		alen = *tptr++;
248517688Spst	    }
248617688Spst	    break;
2487146778Ssam	case ISIS_TLV_ISNEIGH:
248875118Sfenner	    while (tmp >= ETHER_ADDR_LEN) {
2489127675Sbms                if (!TTEST2(*tptr, ETHER_ADDR_LEN))
2490127675Sbms                    goto trunctlv;
2491127675Sbms                printf("\n\t      SNPA: %s",isis_print_id(tptr,ETHER_ADDR_LEN));
2492127675Sbms                tmp -= ETHER_ADDR_LEN;
2493127675Sbms                tptr += ETHER_ADDR_LEN;
249417688Spst	    }
249517688Spst	    break;
249698527Sfenner
2497146778Ssam        case ISIS_TLV_ISNEIGH_VARLEN:
2498147175Ssam            if (!TTEST2(*tptr, 1) || tmp < 3) /* min. TLV length */
2499127675Sbms		goto trunctlv;
2500147904Ssam	    lan_alen = *tptr++; /* LAN address length */
2501147904Ssam	    if (lan_alen == 0) {
2502147904Ssam                printf("\n\t      LAN address length 0 bytes (invalid)");
2503147904Ssam                break;
2504147904Ssam            }
2505127675Sbms            tmp --;
2506127675Sbms            printf("\n\t      LAN address length %u bytes ",lan_alen);
2507127675Sbms	    while (tmp >= lan_alen) {
2508127675Sbms                if (!TTEST2(*tptr, lan_alen))
2509127675Sbms                    goto trunctlv;
2510127675Sbms                printf("\n\t\tIS Neighbor: %s",isis_print_id(tptr,lan_alen));
2511127675Sbms                tmp -= lan_alen;
2512127675Sbms                tptr +=lan_alen;
2513127675Sbms            }
2514127675Sbms            break;
2515127675Sbms
2516146778Ssam	case ISIS_TLV_PADDING:
251717688Spst	    break;
251898527Sfenner
2519146778Ssam        case ISIS_TLV_MT_IS_REACH:
2520214478Srpaulo            mt_len = isis_print_mtid(tptr, "\n\t      ");
2521214478Srpaulo            if (mt_len == 0) /* did something go wrong ? */
2522214478Srpaulo                goto trunctlv;
2523214478Srpaulo            tptr+=mt_len;
2524214478Srpaulo            tmp-=mt_len;
2525127675Sbms            while (tmp >= 2+NODE_ID_LEN+3+1) {
2526127675Sbms                ext_is_len = isis_print_ext_is_reach(tptr,"\n\t      ",tlv_type);
2527127675Sbms                if (ext_is_len == 0) /* did something go wrong ? */
252898527Sfenner                    goto trunctlv;
2529127675Sbms
2530127675Sbms                tmp-=ext_is_len;
2531127675Sbms                tptr+=ext_is_len;
253298527Sfenner            }
253398527Sfenner            break;
253498527Sfenner
2535146778Ssam        case ISIS_TLV_IS_ALIAS_ID:
2536127675Sbms	    while (tmp >= NODE_ID_LEN+1) { /* is it worth attempting a decode ? */
2537127675Sbms	        ext_is_len = isis_print_ext_is_reach(tptr,"\n\t      ",tlv_type);
2538127675Sbms		if (ext_is_len == 0) /* did something go wrong ? */
2539127675Sbms	            goto trunctlv;
2540127675Sbms		tmp-=ext_is_len;
2541127675Sbms		tptr+=ext_is_len;
2542127675Sbms	    }
2543127675Sbms	    break;
2544127675Sbms
2545146778Ssam        case ISIS_TLV_EXT_IS_REACH:
2546127675Sbms            while (tmp >= NODE_ID_LEN+3+1) { /* is it worth attempting a decode ? */
2547127675Sbms                ext_is_len = isis_print_ext_is_reach(tptr,"\n\t      ",tlv_type);
2548127675Sbms                if (ext_is_len == 0) /* did something go wrong ? */
2549127675Sbms                    goto trunctlv;
2550127675Sbms                tmp-=ext_is_len;
2551127675Sbms                tptr+=ext_is_len;
255298527Sfenner            }
255398527Sfenner            break;
2554146778Ssam        case ISIS_TLV_IS_REACH:
255598527Sfenner	    if (!TTEST2(*tptr,1))  /* check if there is one byte left to read out the virtual flag */
2556127675Sbms                goto trunctlv;
2557127675Sbms            printf("\n\t      %s",
2558127675Sbms                   tok2str(isis_is_reach_virtual_values,
2559127675Sbms                           "bogus virtual flag 0x%02x",
2560127675Sbms                           *tptr++));
256198527Sfenner	    tlv_is_reach = (const struct isis_tlv_is_reach *)tptr;
256298527Sfenner            while (tmp >= sizeof(struct isis_tlv_is_reach)) {
256398527Sfenner		if (!TTEST(*tlv_is_reach))
256498527Sfenner		    goto trunctlv;
2565127675Sbms		printf("\n\t      IS Neighbor: %s",
2566127675Sbms		       isis_print_id(tlv_is_reach->neighbor_nodeid, NODE_ID_LEN));
2567127675Sbms                isis_print_metric_block(&tlv_is_reach->isis_metric_block);
256898527Sfenner		tmp -= sizeof(struct isis_tlv_is_reach);
256998527Sfenner		tlv_is_reach++;
257098527Sfenner	    }
257198527Sfenner            break;
257298527Sfenner
2573146778Ssam        case ISIS_TLV_ESNEIGH:
2574127675Sbms	    tlv_es_reach = (const struct isis_tlv_es_reach *)tptr;
2575127675Sbms            while (tmp >= sizeof(struct isis_tlv_es_reach)) {
2576127675Sbms		if (!TTEST(*tlv_es_reach))
2577127675Sbms		    goto trunctlv;
2578127675Sbms		printf("\n\t      ES Neighbor: %s",
2579127675Sbms                       isis_print_id(tlv_es_reach->neighbor_sysid,SYSTEM_ID_LEN));
2580127675Sbms                isis_print_metric_block(&tlv_es_reach->isis_metric_block);
2581127675Sbms		tmp -= sizeof(struct isis_tlv_es_reach);
2582127675Sbms		tlv_es_reach++;
2583127675Sbms	    }
2584127675Sbms            break;
2585127675Sbms
2586127675Sbms            /* those two TLVs share the same format */
2587146778Ssam	case ISIS_TLV_INT_IP_REACH:
2588146778Ssam	case ISIS_TLV_EXT_IP_REACH:
2589127675Sbms	    if (!isis_print_tlv_ip_reach(pptr, "\n\t      ", tlv_len))
259098527Sfenner		return (1);
259117688Spst	    break;
259298527Sfenner
2593146778Ssam	case ISIS_TLV_EXTD_IP_REACH:
2594127675Sbms	    while (tmp>0) {
2595190207Srpaulo                ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", AF_INET);
2596127675Sbms                if (ext_ip_len == 0) /* did something go wrong ? */
2597127675Sbms                    goto trunctlv;
2598127675Sbms                tptr+=ext_ip_len;
2599127675Sbms		tmp-=ext_ip_len;
2600127675Sbms	    }
260198527Sfenner	    break;
260298527Sfenner
2603146778Ssam        case ISIS_TLV_MT_IP_REACH:
2604172686Smlaier            mt_len = isis_print_mtid(tptr, "\n\t      ");
2605172686Smlaier            if (mt_len == 0) { /* did something go wrong ? */
2606172686Smlaier                goto trunctlv;
2607172686Smlaier            }
2608172686Smlaier            tptr+=mt_len;
2609172686Smlaier            tmp-=mt_len;
261098527Sfenner
2611172686Smlaier            while (tmp>0) {
2612190207Srpaulo                ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", AF_INET);
2613127675Sbms                if (ext_ip_len == 0) /* did something go wrong ? */
2614127675Sbms                    goto trunctlv;
2615127675Sbms                tptr+=ext_ip_len;
2616127675Sbms		tmp-=ext_ip_len;
261798527Sfenner	    }
261898527Sfenner	    break;
261998527Sfenner
262098527Sfenner#ifdef INET6
2621146778Ssam	case ISIS_TLV_IP6_REACH:
2622127675Sbms	    while (tmp>0) {
2623190207Srpaulo                ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", AF_INET6);
2624127675Sbms                if (ext_ip_len == 0) /* did something go wrong ? */
2625127675Sbms                    goto trunctlv;
2626127675Sbms                tptr+=ext_ip_len;
2627127675Sbms		tmp-=ext_ip_len;
2628127675Sbms	    }
2629127675Sbms	    break;
263098527Sfenner
2631146778Ssam	case ISIS_TLV_MT_IP6_REACH:
2632172686Smlaier            mt_len = isis_print_mtid(tptr, "\n\t      ");
2633172686Smlaier            if (mt_len == 0) { /* did something go wrong ? */
2634172686Smlaier                goto trunctlv;
2635172686Smlaier            }
2636172686Smlaier            tptr+=mt_len;
2637172686Smlaier            tmp-=mt_len;
2638172686Smlaier
2639127675Sbms	    while (tmp>0) {
2640190207Srpaulo                ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", AF_INET6);
2641127675Sbms                if (ext_ip_len == 0) /* did something go wrong ? */
2642127675Sbms                    goto trunctlv;
2643127675Sbms                tptr+=ext_ip_len;
2644127675Sbms		tmp-=ext_ip_len;
264598527Sfenner	    }
264698527Sfenner	    break;
264798527Sfenner
2648146778Ssam	case ISIS_TLV_IP6ADDR:
2649162021Ssam	    while (tmp>=sizeof(struct in6_addr)) {
2650162021Ssam		if (!TTEST2(*tptr, sizeof(struct in6_addr)))
265198527Sfenner		    goto trunctlv;
265298527Sfenner
2653127675Sbms                printf("\n\t      IPv6 interface address: %s",
265498527Sfenner		       ip6addr_string(tptr));
265598527Sfenner
2656162021Ssam		tptr += sizeof(struct in6_addr);
2657162021Ssam		tmp -= sizeof(struct in6_addr);
265898527Sfenner	    }
265998527Sfenner	    break;
266098527Sfenner#endif
2661146778Ssam	case ISIS_TLV_AUTH:
2662127675Sbms	    if (!TTEST2(*tptr, 1))
266398527Sfenner		goto trunctlv;
2664127675Sbms
2665127675Sbms            printf("\n\t      %s: ",
2666127675Sbms                   tok2str(isis_subtlv_auth_values,
2667127675Sbms                           "unknown Authentication type 0x%02x",
2668127675Sbms                           *tptr));
2669127675Sbms
2670127675Sbms	    switch (*tptr) {
2671146778Ssam	    case ISIS_SUBTLV_AUTH_SIMPLE:
2672127675Sbms		for(i=1;i<tlv_len;i++) {
2673127675Sbms		    if (!TTEST2(*(tptr+i), 1))
267498527Sfenner			goto trunctlv;
2675127675Sbms		    printf("%c",*(tptr+i));
267698527Sfenner		}
2677127675Sbms		break;
2678146778Ssam	    case ISIS_SUBTLV_AUTH_MD5:
2679127675Sbms		for(i=1;i<tlv_len;i++) {
2680127675Sbms		    if (!TTEST2(*(tptr+i), 1))
268198527Sfenner			goto trunctlv;
2682127675Sbms		    printf("%02x",*(tptr+i));
268398527Sfenner		}
2684146778Ssam		if (tlv_len != ISIS_SUBTLV_AUTH_MD5_LEN+1)
2685127675Sbms                    printf(", (malformed subTLV) ");
2686214478Srpaulo
2687214478Srpaulo#ifdef HAVE_LIBCRYPTO
2688214478Srpaulo                sigcheck = signature_verify(optr, length,
2689214478Srpaulo                                            (unsigned char *)tptr + 1);
2690214478Srpaulo#else
2691214478Srpaulo                sigcheck = CANT_CHECK_SIGNATURE;
2692214478Srpaulo#endif
2693214478Srpaulo                printf(" (%s)", tok2str(signature_check_values, "Unknown", sigcheck));
2694214478Srpaulo
2695127675Sbms		break;
2696236192Sdelphij            case ISIS_SUBTLV_AUTH_GENERIC:
2697236192Sdelphij                key_id = EXTRACT_16BITS((tptr+1));
2698236192Sdelphij                printf("%u, password: ", key_id);
2699236192Sdelphij                for(i=1 + sizeof(u_int16_t);i<tlv_len;i++) {
2700236192Sdelphij                    if (!TTEST2(*(tptr+i), 1))
2701236192Sdelphij                        goto trunctlv;
2702236192Sdelphij                    printf("%02x",*(tptr+i));
2703236192Sdelphij                }
2704236192Sdelphij                break;
2705146778Ssam	    case ISIS_SUBTLV_AUTH_PRIVATE:
2706127675Sbms	    default:
2707127675Sbms		if(!print_unknown_data(tptr+1,"\n\t\t  ",tlv_len-1))
2708127675Sbms		    return(0);
2709127675Sbms		break;
271098527Sfenner	    }
271198527Sfenner	    break;
271298527Sfenner
2713146778Ssam	case ISIS_TLV_PTP_ADJ:
2714127675Sbms	    tlv_ptp_adj = (const struct isis_tlv_ptp_adj *)tptr;
2715127675Sbms	    if(tmp>=1) {
2716127675Sbms		if (!TTEST2(*tptr, 1))
271798527Sfenner		    goto trunctlv;
2718127675Sbms		printf("\n\t      Adjacency State: %s (%u)",
2719127675Sbms		       tok2str(isis_ptp_adjancey_values, "unknown", *tptr),
2720127675Sbms                        *tptr);
2721127675Sbms		tmp--;
272298527Sfenner	    }
2723127675Sbms	    if(tmp>sizeof(tlv_ptp_adj->extd_local_circuit_id)) {
2724127675Sbms		if (!TTEST2(tlv_ptp_adj->extd_local_circuit_id,
2725127675Sbms                            sizeof(tlv_ptp_adj->extd_local_circuit_id)))
272698527Sfenner		    goto trunctlv;
2727127675Sbms		printf("\n\t      Extended Local circuit-ID: 0x%08x",
2728127675Sbms		       EXTRACT_32BITS(tlv_ptp_adj->extd_local_circuit_id));
2729127675Sbms		tmp-=sizeof(tlv_ptp_adj->extd_local_circuit_id);
273098527Sfenner	    }
2731127675Sbms	    if(tmp>=SYSTEM_ID_LEN) {
2732127675Sbms		if (!TTEST2(tlv_ptp_adj->neighbor_sysid, SYSTEM_ID_LEN))
273398527Sfenner		    goto trunctlv;
2734127675Sbms		printf("\n\t      Neighbor System-ID: %s",
2735127675Sbms		       isis_print_id(tlv_ptp_adj->neighbor_sysid,SYSTEM_ID_LEN));
2736127675Sbms		tmp-=SYSTEM_ID_LEN;
273798527Sfenner	    }
2738127675Sbms	    if(tmp>=sizeof(tlv_ptp_adj->neighbor_extd_local_circuit_id)) {
2739127675Sbms		if (!TTEST2(tlv_ptp_adj->neighbor_extd_local_circuit_id,
2740127675Sbms                            sizeof(tlv_ptp_adj->neighbor_extd_local_circuit_id)))
274198527Sfenner		    goto trunctlv;
2742127675Sbms		printf("\n\t      Neighbor Extended Local circuit-ID: 0x%08x",
2743127675Sbms		       EXTRACT_32BITS(tlv_ptp_adj->neighbor_extd_local_circuit_id));
274498527Sfenner	    }
274532149Spst	    break;
274698527Sfenner
2747146778Ssam	case ISIS_TLV_PROTOCOLS:
2748127675Sbms	    printf("\n\t      NLPID(s): ");
2749127675Sbms	    while (tmp>0) {
2750127675Sbms		if (!TTEST2(*(tptr), 1))
275198527Sfenner		    goto trunctlv;
2752127675Sbms		printf("%s (0x%02x)",
2753146778Ssam                       tok2str(nlpid_values,
2754127675Sbms                               "unknown",
2755127675Sbms                               *tptr),
2756127675Sbms                       *tptr);
2757127675Sbms		if (tmp>1) /* further NPLIDs ? - put comma */
275898527Sfenner		    printf(", ");
2759127675Sbms                tptr++;
2760127675Sbms                tmp--;
276198527Sfenner	    }
276232149Spst	    break;
276398527Sfenner
2764252283Sdelphij    case ISIS_TLV_MT_PORT_CAP:
2765252283Sdelphij    {
2766252283Sdelphij      if (!TTEST2(*(tptr), 2))
2767252283Sdelphij        goto trunctlv;
2768252283Sdelphij
2769252283Sdelphij      printf("\n\t       RES: %d, MTID(s): %d",
2770252283Sdelphij              (EXTRACT_16BITS (tptr) >> 12),
2771252283Sdelphij              (EXTRACT_16BITS (tptr) & 0x0fff));
2772252283Sdelphij
2773252283Sdelphij      tmp = tmp-2;
2774252283Sdelphij      tptr = tptr+2;
2775252283Sdelphij
2776252283Sdelphij      if (tmp)
2777252283Sdelphij        isis_print_mt_port_cap_subtlv (tptr, tmp);
2778252283Sdelphij
2779252283Sdelphij      break;
2780252283Sdelphij    }
2781252283Sdelphij
2782252283Sdelphij    case ISIS_TLV_MT_CAPABILITY:
2783252283Sdelphij
2784252283Sdelphij      if (!TTEST2(*(tptr), 2))
2785252283Sdelphij        goto trunctlv;
2786252283Sdelphij
2787252283Sdelphij      printf("\n\t      O: %d, RES: %d, MTID(s): %d",
2788252283Sdelphij                (EXTRACT_16BITS(tptr) >> 15) & 0x01,
2789252283Sdelphij                (EXTRACT_16BITS(tptr) >> 12) & 0x07,
2790252283Sdelphij                EXTRACT_16BITS(tptr) & 0x0fff);
2791252283Sdelphij
2792252283Sdelphij      tmp = tmp-2;
2793252283Sdelphij      tptr = tptr+2;
2794252283Sdelphij
2795252283Sdelphij      if (tmp)
2796252283Sdelphij        isis_print_mt_capability_subtlv (tptr, tmp);
2797252283Sdelphij
2798252283Sdelphij      break;
2799252283Sdelphij
2800146778Ssam	case ISIS_TLV_TE_ROUTER_ID:
2801162021Ssam	    if (!TTEST2(*pptr, sizeof(struct in_addr)))
280298527Sfenner		goto trunctlv;
2803127675Sbms	    printf("\n\t      Traffic Engineering Router ID: %s", ipaddr_string(pptr));
280498527Sfenner	    break;
280598527Sfenner
2806146778Ssam	case ISIS_TLV_IPADDR:
2807162021Ssam	    while (tmp>=sizeof(struct in_addr)) {
2808162021Ssam		if (!TTEST2(*tptr, sizeof(struct in_addr)))
280998527Sfenner		    goto trunctlv;
2810127675Sbms		printf("\n\t      IPv4 interface address: %s", ipaddr_string(tptr));
2811162021Ssam		tptr += sizeof(struct in_addr);
2812162021Ssam		tmp -= sizeof(struct in_addr);
281398527Sfenner	    }
281432149Spst	    break;
281598527Sfenner
2816146778Ssam	case ISIS_TLV_HOSTNAME:
2817127675Sbms	    printf("\n\t      Hostname: ");
2818127675Sbms	    while (tmp>0) {
2819127675Sbms		if (!TTEST2(*tptr, 1))
282098527Sfenner		    goto trunctlv;
2821127675Sbms		printf("%c",*tptr++);
2822127675Sbms                tmp--;
282398527Sfenner	    }
282498527Sfenner	    break;
282598527Sfenner
2826146778Ssam	case ISIS_TLV_SHARED_RISK_GROUP:
2827147904Ssam	    if (tmp < NODE_ID_LEN)
2828147904Ssam	        break;
2829127675Sbms	    if (!TTEST2(*tptr, NODE_ID_LEN))
2830127675Sbms                goto trunctlv;
2831127675Sbms	    printf("\n\t      IS Neighbor: %s", isis_print_id(tptr, NODE_ID_LEN));
2832127675Sbms	    tptr+=(NODE_ID_LEN);
2833127675Sbms	    tmp-=(NODE_ID_LEN);
2834127675Sbms
2835147904Ssam	    if (tmp < 1)
2836147904Ssam	        break;
2837127675Sbms	    if (!TTEST2(*tptr, 1))
2838127675Sbms                goto trunctlv;
2839127675Sbms	    printf(", Flags: [%s]", ISIS_MASK_TLV_SHARED_RISK_GROUP(*tptr++) ? "numbered" : "unnumbered");
2840127675Sbms	    tmp--;
2841127675Sbms
2842162021Ssam	    if (tmp < sizeof(struct in_addr))
2843147904Ssam	        break;
2844162021Ssam	    if (!TTEST2(*tptr,sizeof(struct in_addr)))
2845127675Sbms                goto trunctlv;
2846127675Sbms	    printf("\n\t      IPv4 interface address: %s", ipaddr_string(tptr));
2847162021Ssam	    tptr+=sizeof(struct in_addr);
2848162021Ssam	    tmp-=sizeof(struct in_addr);
2849127675Sbms
2850162021Ssam	    if (tmp < sizeof(struct in_addr))
2851147904Ssam	        break;
2852162021Ssam	    if (!TTEST2(*tptr,sizeof(struct in_addr)))
2853127675Sbms                goto trunctlv;
2854127675Sbms	    printf("\n\t      IPv4 neighbor address: %s", ipaddr_string(tptr));
2855162021Ssam	    tptr+=sizeof(struct in_addr);
2856162021Ssam	    tmp-=sizeof(struct in_addr);
2857127675Sbms
2858147904Ssam	    while (tmp>=4) {
2859127675Sbms                if (!TTEST2(*tptr, 4))
2860127675Sbms                    goto trunctlv;
2861127675Sbms                printf("\n\t      Link-ID: 0x%08x", EXTRACT_32BITS(tptr));
2862127675Sbms                tptr+=4;
2863127675Sbms                tmp-=4;
2864127675Sbms	    }
2865127675Sbms	    break;
2866127675Sbms
2867146778Ssam	case ISIS_TLV_LSP:
2868127675Sbms	    tlv_lsp = (const struct isis_tlv_lsp *)tptr;
2869147904Ssam	    while(tmp>=sizeof(struct isis_tlv_lsp)) {
2870127675Sbms		if (!TTEST((tlv_lsp->lsp_id)[LSP_ID_LEN-1]))
287198527Sfenner		    goto trunctlv;
2872127675Sbms		printf("\n\t      lsp-id: %s",
2873127675Sbms                       isis_print_id(tlv_lsp->lsp_id, LSP_ID_LEN));
287498527Sfenner		if (!TTEST2(tlv_lsp->sequence_number, 4))
287598527Sfenner		    goto trunctlv;
2876127675Sbms		printf(", seq: 0x%08x",EXTRACT_32BITS(tlv_lsp->sequence_number));
287798527Sfenner		if (!TTEST2(tlv_lsp->remaining_lifetime, 2))
287898527Sfenner		    goto trunctlv;
2879127675Sbms		printf(", lifetime: %5ds",EXTRACT_16BITS(tlv_lsp->remaining_lifetime));
288098527Sfenner		if (!TTEST2(tlv_lsp->checksum, 2))
288198527Sfenner		    goto trunctlv;
2882127675Sbms		printf(", chksum: 0x%04x",EXTRACT_16BITS(tlv_lsp->checksum));
2883127675Sbms		tmp-=sizeof(struct isis_tlv_lsp);
288498527Sfenner		tlv_lsp++;
288598527Sfenner	    }
288698527Sfenner	    break;
288798527Sfenner
2888146778Ssam	case ISIS_TLV_CHECKSUM:
2889162021Ssam	    if (tmp < ISIS_TLV_CHECKSUM_MINLEN)
2890147904Ssam	        break;
2891162021Ssam	    if (!TTEST2(*tptr, ISIS_TLV_CHECKSUM_MINLEN))
289298527Sfenner		goto trunctlv;
2893127675Sbms	    printf("\n\t      checksum: 0x%04x ", EXTRACT_16BITS(tptr));
2894127675Sbms            /* do not attempt to verify the checksum if it is zero
2895127675Sbms             * most likely a HMAC-MD5 TLV is also present and
2896127675Sbms             * to avoid conflicts the checksum TLV is zeroed.
2897127675Sbms             * see rfc3358 for details
2898127675Sbms             */
2899190207Srpaulo            osi_print_cksum(optr, EXTRACT_16BITS(tptr), tptr-optr, length);
290098527Sfenner	    break;
290198527Sfenner
2902146778Ssam	case ISIS_TLV_MT_SUPPORTED:
2903162021Ssam            if (tmp < ISIS_TLV_MT_SUPPORTED_MINLEN)
2904162021Ssam                break;
2905127675Sbms	    while (tmp>1) {
2906127675Sbms		/* length can only be a multiple of 2, otherwise there is
290798527Sfenner		   something broken -> so decode down until length is 1 */
2908127675Sbms		if (tmp!=1) {
2909127675Sbms                    mt_len = isis_print_mtid(tptr, "\n\t      ");
2910127675Sbms                    if (mt_len == 0) /* did something go wrong ? */
2911127675Sbms                        goto trunctlv;
2912127675Sbms                    tptr+=mt_len;
2913127675Sbms                    tmp-=mt_len;
291498527Sfenner		} else {
2915127675Sbms		    printf("\n\t      malformed MT-ID");
291698527Sfenner		    break;
291798527Sfenner		}
291898527Sfenner	    }
291998527Sfenner	    break;
292098527Sfenner
2921146778Ssam	case ISIS_TLV_RESTART_SIGNALING:
2922162021Ssam            /* first attempt to decode the flags */
2923162021Ssam            if (tmp < ISIS_TLV_RESTART_SIGNALING_FLAGLEN)
2924162021Ssam                break;
2925162021Ssam            if (!TTEST2(*tptr, ISIS_TLV_RESTART_SIGNALING_FLAGLEN))
2926127675Sbms                goto trunctlv;
2927162021Ssam            printf("\n\t      Flags [%s]",
2928162021Ssam                   bittok2str(isis_restart_flag_values, "none", *tptr));
2929162021Ssam            tptr+=ISIS_TLV_RESTART_SIGNALING_FLAGLEN;
2930162021Ssam            tmp-=ISIS_TLV_RESTART_SIGNALING_FLAGLEN;
2931162021Ssam
2932162021Ssam            /* is there anything other than the flags field? */
2933162021Ssam            if (tmp == 0)
2934162021Ssam                break;
2935162021Ssam
2936162021Ssam            if (tmp < ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN)
2937162021Ssam                break;
2938162021Ssam            if (!TTEST2(*tptr, ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN))
2939162021Ssam                goto trunctlv;
2940162021Ssam
2941172686Smlaier            printf(", Remaining holding time %us", EXTRACT_16BITS(tptr));
2942162021Ssam            tptr+=ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN;
2943162021Ssam            tmp-=ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN;
2944162021Ssam
2945162021Ssam            /* is there an additional sysid field present ?*/
2946147904Ssam            if (tmp == SYSTEM_ID_LEN) {
2947147904Ssam                    if (!TTEST2(*tptr, SYSTEM_ID_LEN))
2948147904Ssam                            goto trunctlv;
2949147904Ssam                    printf(", for %s",isis_print_id(tptr,SYSTEM_ID_LEN));
2950162021Ssam            }
295198527Sfenner	    break;
295298527Sfenner
2953146778Ssam        case ISIS_TLV_IDRP_INFO:
2954162021Ssam	    if (tmp < ISIS_TLV_IDRP_INFO_MINLEN)
2955147904Ssam	        break;
2956162021Ssam            if (!TTEST2(*tptr, ISIS_TLV_IDRP_INFO_MINLEN))
2957127675Sbms                goto trunctlv;
2958127675Sbms            printf("\n\t      Inter-Domain Information Type: %s",
2959127675Sbms                   tok2str(isis_subtlv_idrp_values,
2960127675Sbms                           "Unknown (0x%02x)",
2961127675Sbms                           *tptr));
2962127675Sbms            switch (*tptr++) {
2963146778Ssam            case ISIS_SUBTLV_IDRP_ASN:
2964127675Sbms                if (!TTEST2(*tptr, 2)) /* fetch AS number */
2965127675Sbms                    goto trunctlv;
2966127675Sbms                printf("AS Number: %u",EXTRACT_16BITS(tptr));
2967127675Sbms                break;
2968146778Ssam            case ISIS_SUBTLV_IDRP_LOCAL:
2969146778Ssam            case ISIS_SUBTLV_IDRP_RES:
2970127675Sbms            default:
2971127675Sbms                if(!print_unknown_data(tptr,"\n\t      ",tlv_len-1))
2972127675Sbms                    return(0);
2973127675Sbms                break;
2974127675Sbms            }
2975127675Sbms            break;
2976127675Sbms
2977146778Ssam        case ISIS_TLV_LSP_BUFFERSIZE:
2978162021Ssam	    if (tmp < ISIS_TLV_LSP_BUFFERSIZE_MINLEN)
2979147904Ssam	        break;
2980162021Ssam            if (!TTEST2(*tptr, ISIS_TLV_LSP_BUFFERSIZE_MINLEN))
2981127675Sbms                goto trunctlv;
2982127675Sbms            printf("\n\t      LSP Buffersize: %u",EXTRACT_16BITS(tptr));
2983127675Sbms            break;
2984127675Sbms
2985146778Ssam        case ISIS_TLV_PART_DIS:
2986127675Sbms            while (tmp >= SYSTEM_ID_LEN) {
2987127675Sbms                if (!TTEST2(*tptr, SYSTEM_ID_LEN))
2988127675Sbms                    goto trunctlv;
2989127675Sbms                printf("\n\t      %s",isis_print_id(tptr,SYSTEM_ID_LEN));
2990127675Sbms                tptr+=SYSTEM_ID_LEN;
2991127675Sbms                tmp-=SYSTEM_ID_LEN;
2992127675Sbms            }
2993127675Sbms            break;
2994127675Sbms
2995146778Ssam        case ISIS_TLV_PREFIX_NEIGH:
2996147904Ssam	    if (tmp < sizeof(struct isis_metric_block))
2997147904Ssam	        break;
2998127675Sbms            if (!TTEST2(*tptr, sizeof(struct isis_metric_block)))
2999127675Sbms                goto trunctlv;
3000127675Sbms            printf("\n\t      Metric Block");
3001127675Sbms            isis_print_metric_block((const struct isis_metric_block *)tptr);
3002127675Sbms            tptr+=sizeof(struct isis_metric_block);
3003127675Sbms            tmp-=sizeof(struct isis_metric_block);
3004127675Sbms
3005127675Sbms            while(tmp>0) {
3006127675Sbms                if (!TTEST2(*tptr, 1))
3007127675Sbms                    goto trunctlv;
3008127675Sbms                prefix_len=*tptr++; /* read out prefix length in semioctets*/
3009147904Ssam                if (prefix_len < 2) {
3010147904Ssam                    printf("\n\t\tAddress: prefix length %u < 2", prefix_len);
3011147904Ssam                    break;
3012147904Ssam                }
3013127675Sbms                tmp--;
3014147904Ssam                if (tmp < prefix_len/2)
3015147904Ssam                    break;
3016127675Sbms                if (!TTEST2(*tptr, prefix_len/2))
3017127675Sbms                    goto trunctlv;
3018127675Sbms                printf("\n\t\tAddress: %s/%u",
3019146778Ssam                       isonsap_string(tptr,prefix_len/2),
3020127675Sbms                       prefix_len*4);
3021127675Sbms                tptr+=prefix_len/2;
3022127675Sbms                tmp-=prefix_len/2;
3023127675Sbms            }
3024127675Sbms            break;
3025127675Sbms
3026146778Ssam        case ISIS_TLV_IIH_SEQNR:
3027162021Ssam	    if (tmp < ISIS_TLV_IIH_SEQNR_MINLEN)
3028147904Ssam	        break;
3029162021Ssam            if (!TTEST2(*tptr, ISIS_TLV_IIH_SEQNR_MINLEN)) /* check if four bytes are on the wire */
3030127675Sbms                goto trunctlv;
3031127675Sbms            printf("\n\t      Sequence number: %u", EXTRACT_32BITS(tptr) );
3032127675Sbms            break;
3033127675Sbms
3034146778Ssam        case ISIS_TLV_VENDOR_PRIVATE:
3035162021Ssam	    if (tmp < ISIS_TLV_VENDOR_PRIVATE_MINLEN)
3036147904Ssam	        break;
3037162021Ssam            if (!TTEST2(*tptr, ISIS_TLV_VENDOR_PRIVATE_MINLEN)) /* check if enough byte for a full oui */
3038127675Sbms                goto trunctlv;
3039146778Ssam            vendor_id = EXTRACT_24BITS(tptr);
3040146778Ssam            printf("\n\t      Vendor: %s (%u)",
3041146778Ssam                   tok2str(oui_values,"Unknown",vendor_id),
3042146778Ssam                   vendor_id);
3043127675Sbms            tptr+=3;
3044127675Sbms            tmp-=3;
3045127675Sbms            if (tmp > 0) /* hexdump the rest */
3046127675Sbms                if(!print_unknown_data(tptr,"\n\t\t",tmp))
3047127675Sbms                    return(0);
3048127675Sbms            break;
3049127675Sbms            /*
3050127675Sbms             * FIXME those are the defined TLVs that lack a decoder
3051127675Sbms             * you are welcome to contribute code ;-)
3052127675Sbms             */
3053127675Sbms
3054146778Ssam        case ISIS_TLV_DECNET_PHASE4:
3055146778Ssam        case ISIS_TLV_LUCENT_PRIVATE:
3056146778Ssam        case ISIS_TLV_IPAUTH:
3057146778Ssam        case ISIS_TLV_NORTEL_PRIVATE1:
3058146778Ssam        case ISIS_TLV_NORTEL_PRIVATE2:
3059127675Sbms
306017688Spst	default:
3061127675Sbms            if (vflag <= 1) {
3062127675Sbms                if(!print_unknown_data(pptr,"\n\t\t",tlv_len))
3063127675Sbms                    return(0);
3064127675Sbms            }
306517688Spst	    break;
306617688Spst	}
3067127675Sbms        /* do we want to see an additionally hexdump ? */
3068127675Sbms        if (vflag> 1) {
3069127675Sbms	    if(!print_unknown_data(pptr,"\n\t      ",tlv_len))
3070127675Sbms	        return(0);
3071127675Sbms        }
307217688Spst
3073127675Sbms	pptr += tlv_len;
3074127675Sbms	packet_len -= tlv_len;
307517688Spst    }
307617688Spst
307717688Spst    if (packet_len != 0) {
3078127675Sbms	printf("\n\t      %u straggler bytes", packet_len);
307917688Spst    }
308098527Sfenner    return (1);
308198527Sfenner
3082127675Sbms trunc:
308398527Sfenner    fputs("[|isis]", stdout);
308498527Sfenner    return (1);
308598527Sfenner
3086127675Sbms trunctlv:
3087127675Sbms    printf("\n\t\t packet exceeded snapshot");
308817688Spst    return(1);
308917688Spst}
309017688Spst
3091190207Srpaulostatic void
3092190207Srpauloosi_print_cksum (const u_int8_t *pptr, u_int16_t checksum,
3093190207Srpaulo                    u_int checksum_offset, u_int length)
309417680Spst{
3095190207Srpaulo        u_int16_t calculated_checksum;
309617680Spst
3097190207Srpaulo        /* do not attempt to verify the checksum if it is zero */
3098190207Srpaulo        if (!checksum) {
3099190207Srpaulo                printf("(unverified)");
3100190207Srpaulo        } else {
3101190207Srpaulo                calculated_checksum = create_osi_cksum(pptr, checksum_offset, length);
3102190207Srpaulo                if (checksum == calculated_checksum) {
3103190207Srpaulo                        printf(" (correct)");
3104190207Srpaulo                } else {
3105190207Srpaulo                        printf(" (incorrect should be 0x%04x)", calculated_checksum);
3106190207Srpaulo                }
3107190207Srpaulo        }
310817680Spst}
3109146778Ssam
3110146778Ssam/*
3111146778Ssam * Local Variables:
3112146778Ssam * c-style: whitesmith
3113146778Ssam * c-basic-offset: 8
3114146778Ssam * End:
3115146778Ssam */
3116