print-isoclns.c revision 147904
117680Spst/*
217680Spst * Copyright (c) 1992, 1993, 1994, 1995, 1996
317680Spst *	The Regents of the University of California.  All rights reserved.
417680Spst *
517680Spst * Redistribution and use in source and binary forms, with or without
617680Spst * modification, are permitted provided that: (1) source code distributions
717680Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817680Spst * distributions including binary code include the above copyright notice and
917680Spst * this paragraph in its entirety in the documentation or other materials
1017680Spst * provided with the distribution, and (3) all advertising materials mentioning
1117680Spst * features or use of this software display the following acknowledgement:
1217680Spst * ``This product includes software developed by the University of California,
1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417680Spst * the University nor the names of its contributors may be used to endorse
1517680Spst * or promote products derived from this software without specific prior
1617680Spst * written permission.
1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2026183Sfenner *
2117680Spst * Original code by Matt Thomas, Digital Equipment Corporation
2256896Sfenner *
2398527Sfenner * Extensively modified by Hannes Gredler (hannes@juniper.net) for more
24146778Ssam * complete IS-IS & CLNP support.
2598527Sfenner *
2656896Sfenner * $FreeBSD: head/contrib/tcpdump/print-isoclns.c 147904 2005-07-11 04:14:02Z sam $
2717680Spst */
2817680Spst
2917680Spst#ifndef lint
30127675Sbmsstatic const char rcsid[] _U_ =
31147904Ssam    "@(#) $Header: /tcpdump/master/tcpdump/print-isoclns.c,v 1.133.2.12 2005/06/16 01:14:52 guy Exp $ (LBL)";
3217680Spst#endif
3317680Spst
3456896Sfenner#ifdef HAVE_CONFIG_H
3556896Sfenner#include "config.h"
3656896Sfenner#endif
3756896Sfenner
38127675Sbms#include <tcpdump-stdinc.h>
3917680Spst
4017680Spst#include <stdio.h>
4198527Sfenner#include <string.h>
4217680Spst
4317680Spst#include "interface.h"
4417680Spst#include "addrtoname.h"
4517680Spst#include "ethertype.h"
4675118Sfenner#include "ether.h"
47146778Ssam#include "nlpid.h"
4817688Spst#include "extract.h"
49127675Sbms#include "gmpls.h"
50146778Ssam#include "oui.h"
5117680Spst
52127675Sbms#define IPV4            1       /* AFI value */
53127675Sbms#define IPV6            2       /* AFI value */
54127675Sbms
5532149Spst/*
5632149Spst * IS-IS is defined in ISO 10589.  Look there for protocol definitions.
5732149Spst */
5832149Spst
5975118Sfenner#define SYSTEM_ID_LEN	ETHER_ADDR_LEN
60127675Sbms#define NODE_ID_LEN     SYSTEM_ID_LEN+1
61127675Sbms#define LSP_ID_LEN      SYSTEM_ID_LEN+2
62127675Sbms
6332149Spst#define ISIS_VERSION	1
64146778Ssam#define ESIS_VERSION	1
65146778Ssam#define CLNP_VERSION	1
6632149Spst
67146778Ssam#define ISIS_PDU_TYPE_MASK      0x1F
68146778Ssam#define ESIS_PDU_TYPE_MASK      0x1F
69146778Ssam#define CLNP_PDU_TYPE_MASK      0x1F
70146778Ssam#define CLNP_FLAG_MASK          0xE0
71146778Ssam#define ISIS_LAN_PRIORITY_MASK  0x7F
7232149Spst
73146778Ssam#define ISIS_PDU_L1_LAN_IIH	15
74146778Ssam#define ISIS_PDU_L2_LAN_IIH	16
75146778Ssam#define ISIS_PDU_PTP_IIH	17
76146778Ssam#define ISIS_PDU_L1_LSP       	18
77146778Ssam#define ISIS_PDU_L2_LSP       	20
78146778Ssam#define ISIS_PDU_L1_CSNP  	24
79146778Ssam#define ISIS_PDU_L2_CSNP  	25
80146778Ssam#define ISIS_PDU_L1_PSNP        26
81146778Ssam#define ISIS_PDU_L2_PSNP        27
82146778Ssam
83127675Sbmsstatic struct tok isis_pdu_values[] = {
84146778Ssam    { ISIS_PDU_L1_LAN_IIH,       "L1 Lan IIH"},
85146778Ssam    { ISIS_PDU_L2_LAN_IIH,       "L2 Lan IIH"},
86146778Ssam    { ISIS_PDU_PTP_IIH,          "p2p IIH"},
87146778Ssam    { ISIS_PDU_L1_LSP,           "L1 LSP"},
88146778Ssam    { ISIS_PDU_L2_LSP,           "L2 LSP"},
89146778Ssam    { ISIS_PDU_L1_CSNP,          "L1 CSNP"},
90146778Ssam    { ISIS_PDU_L2_CSNP,          "L2 CSNP"},
91146778Ssam    { ISIS_PDU_L1_PSNP,          "L1 PSNP"},
92146778Ssam    { ISIS_PDU_L2_PSNP,          "L2 PSNP"},
93127675Sbms    { 0, NULL}
94127675Sbms};
9598527Sfenner
9632149Spst/*
9732149Spst * A TLV is a tuple of a type, length and a value and is normally used for
9832149Spst * encoding information in all sorts of places.  This is an enumeration of
9932149Spst * the well known types.
100127675Sbms *
101127675Sbms * list taken from rfc3359 plus some memory from veterans ;-)
10232149Spst */
10332149Spst
104146778Ssam#define ISIS_TLV_AREA_ADDR           1   /* iso10589 */
105146778Ssam#define ISIS_TLV_IS_REACH            2   /* iso10589 */
106146778Ssam#define ISIS_TLV_ESNEIGH             3   /* iso10589 */
107146778Ssam#define ISIS_TLV_PART_DIS            4   /* iso10589 */
108146778Ssam#define ISIS_TLV_PREFIX_NEIGH        5   /* iso10589 */
109146778Ssam#define ISIS_TLV_ISNEIGH             6   /* iso10589 */
110146778Ssam#define ISIS_TLV_ISNEIGH_VARLEN      7   /* iso10589 */
111146778Ssam#define ISIS_TLV_PADDING             8   /* iso10589 */
112146778Ssam#define ISIS_TLV_LSP                 9   /* iso10589 */
113146778Ssam#define ISIS_TLV_AUTH                10  /* iso10589, rfc3567 */
114146778Ssam#define ISIS_TLV_CHECKSUM            12  /* rfc3358 */
115146778Ssam#define ISIS_TLV_LSP_BUFFERSIZE      14  /* iso10589 rev2 */
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 */
124146778Ssam#define ISIS_TLV_IPADDR              132 /* rfc1195 */
125146778Ssam#define ISIS_TLV_IPAUTH              133 /* rfc1195 */
126146778Ssam#define ISIS_TLV_TE_ROUTER_ID        134 /* draft-ietf-isis-traffic-05 */
127146778Ssam#define ISIS_TLV_EXTD_IP_REACH       135 /* draft-ietf-isis-traffic-05 */
128146778Ssam#define ISIS_TLV_HOSTNAME            137 /* rfc2763 */
129146778Ssam#define ISIS_TLV_SHARED_RISK_GROUP   138 /* draft-ietf-isis-gmpls-extensions */
130146778Ssam#define ISIS_TLV_NORTEL_PRIVATE1     176
131146778Ssam#define ISIS_TLV_NORTEL_PRIVATE2     177
132147904Ssam#define ISIS_TLV_RESTART_SIGNALING   211 /* rfc3847 */
133146778Ssam#define ISIS_TLV_MT_IS_REACH         222 /* draft-ietf-isis-wg-multi-topology-05 */
134146778Ssam#define ISIS_TLV_MT_SUPPORTED        229 /* draft-ietf-isis-wg-multi-topology-05 */
135146778Ssam#define ISIS_TLV_IP6ADDR             232 /* draft-ietf-isis-ipv6-02 */
136146778Ssam#define ISIS_TLV_MT_IP_REACH         235 /* draft-ietf-isis-wg-multi-topology-05 */
137146778Ssam#define ISIS_TLV_IP6_REACH           236 /* draft-ietf-isis-ipv6-02 */
138146778Ssam#define ISIS_TLV_MT_IP6_REACH        237 /* draft-ietf-isis-wg-multi-topology-05 */
139146778Ssam#define ISIS_TLV_PTP_ADJ             240 /* rfc3373 */
140146778Ssam#define ISIS_TLV_IIH_SEQNR           241 /* draft-shen-isis-iih-sequence-00 */
141146778Ssam#define ISIS_TLV_VENDOR_PRIVATE      250 /* draft-ietf-isis-experimental-tlv-01 */
14232149Spst
143127675Sbmsstatic struct tok isis_tlv_values[] = {
144146778Ssam    { ISIS_TLV_AREA_ADDR,	   "Area address(es)"},
145146778Ssam    { ISIS_TLV_IS_REACH,           "IS Reachability"},
146146778Ssam    { ISIS_TLV_ESNEIGH,            "ES Neighbor(s)"},
147146778Ssam    { ISIS_TLV_PART_DIS,           "Partition DIS"},
148146778Ssam    { ISIS_TLV_PREFIX_NEIGH,       "Prefix Neighbors"},
149146778Ssam    { ISIS_TLV_ISNEIGH,            "IS Neighbor(s)"},
150146778Ssam    { ISIS_TLV_ISNEIGH_VARLEN,     "IS Neighbor(s) (variable length)"},
151146778Ssam    { ISIS_TLV_PADDING,            "Padding"},
152146778Ssam    { ISIS_TLV_LSP,                "LSP entries"},
153146778Ssam    { ISIS_TLV_AUTH,               "Authentication"},
154146778Ssam    { ISIS_TLV_CHECKSUM,           "Checksum"},
155146778Ssam    { ISIS_TLV_LSP_BUFFERSIZE,     "LSP Buffersize"},
156146778Ssam    { ISIS_TLV_EXT_IS_REACH,       "Extended IS Reachability"},
157146778Ssam    { ISIS_TLV_IS_ALIAS_ID,        "IS Alias ID"},
158146778Ssam    { ISIS_TLV_DECNET_PHASE4,      "DECnet Phase IV"},
159146778Ssam    { ISIS_TLV_LUCENT_PRIVATE,     "Lucent Proprietary"},
160146778Ssam    { ISIS_TLV_INT_IP_REACH,       "IPv4 Internal Reachability"},
161146778Ssam    { ISIS_TLV_PROTOCOLS,          "Protocols supported"},
162146778Ssam    { ISIS_TLV_EXT_IP_REACH,       "IPv4 External Reachability"},
163146778Ssam    { ISIS_TLV_IDRP_INFO,          "Inter-Domain Information Type"},
164146778Ssam    { ISIS_TLV_IPADDR,             "IPv4 Interface address(es)"},
165146778Ssam    { ISIS_TLV_IPAUTH,             "IPv4 authentication (deprecated)"},
166146778Ssam    { ISIS_TLV_TE_ROUTER_ID,       "Traffic Engineering Router ID"},
167146778Ssam    { ISIS_TLV_EXTD_IP_REACH,      "Extended IPv4 Reachability"},
168146778Ssam    { ISIS_TLV_SHARED_RISK_GROUP,  "Shared Risk Link Group"},
169146778Ssam    { ISIS_TLV_NORTEL_PRIVATE1,    "Nortel Proprietary"},
170146778Ssam    { ISIS_TLV_NORTEL_PRIVATE2,    "Nortel Proprietary"},
171146778Ssam    { ISIS_TLV_HOSTNAME,           "Hostname"},
172146778Ssam    { ISIS_TLV_RESTART_SIGNALING,  "Restart Signaling"},
173146778Ssam    { ISIS_TLV_MT_IS_REACH,        "Multi Topology IS Reachability"},
174146778Ssam    { ISIS_TLV_MT_SUPPORTED,       "Multi Topology"},
175146778Ssam    { ISIS_TLV_IP6ADDR,            "IPv6 Interface address(es)"},
176146778Ssam    { ISIS_TLV_MT_IP_REACH,        "Multi-Topology IPv4 Reachability"},
177146778Ssam    { ISIS_TLV_IP6_REACH,          "IPv6 reachability"},
178146778Ssam    { ISIS_TLV_MT_IP6_REACH,       "Multi-Topology IP6 Reachability"},
179146778Ssam    { ISIS_TLV_PTP_ADJ,            "Point-to-point Adjacency State"},
180146778Ssam    { ISIS_TLV_IIH_SEQNR,          "Hello PDU Sequence Number"},
181146778Ssam    { ISIS_TLV_VENDOR_PRIVATE,     "Vendor Private"},
182127675Sbms    { 0, NULL }
183127675Sbms};
18498527Sfenner
185146778Ssam#define ESIS_OPTION_PROTOCOLS        129
186146778Ssam#define ESIS_OPTION_QOS_MAINTENANCE  195 /* iso9542 */
187146778Ssam#define ESIS_OPTION_SECURITY         197 /* iso9542 */
188146778Ssam#define ESIS_OPTION_ES_CONF_TIME     198 /* iso9542 */
189146778Ssam#define ESIS_OPTION_PRIORITY         205 /* iso9542 */
190146778Ssam#define ESIS_OPTION_ADDRESS_MASK     225 /* iso9542 */
191146778Ssam#define ESIS_OPTION_SNPA_MASK        226 /* iso9542 */
19298527Sfenner
193146778Ssamstatic struct tok esis_option_values[] = {
194146778Ssam    { ESIS_OPTION_PROTOCOLS,       "Protocols supported"},
195146778Ssam    { ESIS_OPTION_QOS_MAINTENANCE, "QoS Maintenance" },
196146778Ssam    { ESIS_OPTION_SECURITY,        "Security" },
197146778Ssam    { ESIS_OPTION_ES_CONF_TIME,    "ES Configuration Time" },
198146778Ssam    { ESIS_OPTION_PRIORITY,        "Priority" },
199146778Ssam    { ESIS_OPTION_ADDRESS_MASK,    "Addressk Mask" },
200146778Ssam    { ESIS_OPTION_SNPA_MASK,       "SNPA Mask" },
201146778Ssam    { 0, NULL }
202146778Ssam};
203146778Ssam
204146778Ssam#define CLNP_OPTION_DISCARD_REASON   193
205146778Ssam#define CLNP_OPTION_QOS_MAINTENANCE  195 /* iso8473 */
206147904Ssam#define CLNP_OPTION_SECURITY         197 /* iso8473 */
207147904Ssam#define CLNP_OPTION_SOURCE_ROUTING   200 /* iso8473 */
208147904Ssam#define CLNP_OPTION_ROUTE_RECORDING  203 /* iso8473 */
209147904Ssam#define CLNP_OPTION_PADDING          204 /* iso8473 */
210146778Ssam#define CLNP_OPTION_PRIORITY         205 /* iso8473 */
211146778Ssam
212146778Ssamstatic struct tok clnp_option_values[] = {
213146778Ssam    { CLNP_OPTION_DISCARD_REASON,  "Discard Reason"},
214146778Ssam    { CLNP_OPTION_PRIORITY,        "Priority"},
215146778Ssam    { CLNP_OPTION_QOS_MAINTENANCE, "QoS Maintenance"},
216147904Ssam    { CLNP_OPTION_SECURITY, "Security"},
217147904Ssam    { CLNP_OPTION_SOURCE_ROUTING, "Source Routing"},
218147904Ssam    { CLNP_OPTION_ROUTE_RECORDING, "Route Recording"},
219147904Ssam    { CLNP_OPTION_PADDING, "Padding"},
220146778Ssam    { 0, NULL }
221146778Ssam};
222146778Ssam
223146778Ssamstatic struct tok clnp_option_rfd_class_values[] = {
224146778Ssam    { 0x0, "General"},
225146778Ssam    { 0x8, "Address"},
226146778Ssam    { 0x9, "Source Routeing"},
227146778Ssam    { 0xa, "Lifetime"},
228146778Ssam    { 0xb, "PDU Discarded"},
229146778Ssam    { 0xc, "Reassembly"},
230146778Ssam    { 0, NULL }
231146778Ssam};
232146778Ssam
233146778Ssamstatic struct tok clnp_option_rfd_general_values[] = {
234146778Ssam    { 0x0, "Reason not specified"},
235146778Ssam    { 0x1, "Protocol procedure error"},
236146778Ssam    { 0x2, "Incorrect checksum"},
237146778Ssam    { 0x3, "PDU discarded due to congestion"},
238146778Ssam    { 0x4, "Header syntax error (cannot be parsed)"},
239146778Ssam    { 0x5, "Segmentation needed but not permitted"},
240146778Ssam    { 0x6, "Incomplete PDU received"},
241146778Ssam    { 0x7, "Duplicate option"},
242146778Ssam    { 0, NULL }
243146778Ssam};
244146778Ssam
245146778Ssamstatic struct tok clnp_option_rfd_address_values[] = {
246146778Ssam    { 0x0, "Destination address unreachable"},
247146778Ssam    { 0x1, "Destination address unknown"},
248146778Ssam    { 0, NULL }
249146778Ssam};
250146778Ssam
251146778Ssamstatic struct tok clnp_option_rfd_source_routeing_values[] = {
252146778Ssam    { 0x0, "Unspecified source routeing error"},
253146778Ssam    { 0x1, "Syntax error in source routeing field"},
254146778Ssam    { 0x2, "Unknown address in source routeing field"},
255146778Ssam    { 0x3, "Path not acceptable"},
256146778Ssam    { 0, NULL }
257146778Ssam};
258146778Ssam
259146778Ssamstatic struct tok clnp_option_rfd_lifetime_values[] = {
260146778Ssam    { 0x0, "Lifetime expired while data unit in transit"},
261146778Ssam    { 0x1, "Lifetime expired during reassembly"},
262146778Ssam    { 0, NULL }
263146778Ssam};
264146778Ssam
265146778Ssamstatic struct tok clnp_option_rfd_pdu_discard_values[] = {
266146778Ssam    { 0x0, "Unsupported option not specified"},
267146778Ssam    { 0x1, "Unsupported protocol version"},
268146778Ssam    { 0x2, "Unsupported security option"},
269146778Ssam    { 0x3, "Unsupported source routeing option"},
270146778Ssam    { 0x4, "Unsupported recording of route option"},
271146778Ssam    { 0, NULL }
272146778Ssam};
273146778Ssam
274146778Ssamstatic struct tok clnp_option_rfd_reassembly_values[] = {
275146778Ssam    { 0x0, "Reassembly interference"},
276146778Ssam    { 0, NULL }
277146778Ssam};
278146778Ssam
279146778Ssam/* array of 16 error-classes */
280146778Ssamstatic struct tok *clnp_option_rfd_error_class[] = {
281146778Ssam    clnp_option_rfd_general_values,
282146778Ssam    NULL,
283146778Ssam    NULL,
284146778Ssam    NULL,
285146778Ssam    NULL,
286146778Ssam    NULL,
287146778Ssam    NULL,
288146778Ssam    NULL,
289146778Ssam    clnp_option_rfd_address_values,
290146778Ssam    clnp_option_rfd_source_routeing_values,
291146778Ssam    clnp_option_rfd_lifetime_values,
292146778Ssam    clnp_option_rfd_pdu_discard_values,
293146778Ssam    clnp_option_rfd_reassembly_values,
294146778Ssam    NULL,
295146778Ssam    NULL,
296146778Ssam    NULL
297146778Ssam};
298146778Ssam
299147904Ssam#define CLNP_OPTION_OPTION_QOS_MASK 0x3f
300147904Ssam#define CLNP_OPTION_SCOPE_MASK      0xc0
301147904Ssam#define CLNP_OPTION_SCOPE_SA_SPEC   0x40
302147904Ssam#define CLNP_OPTION_SCOPE_DA_SPEC   0x80
303147904Ssam#define CLNP_OPTION_SCOPE_GLOBAL    0xc0
304146778Ssam
305147904Ssamstatic struct tok clnp_option_scope_values[] = {
306147904Ssam    { CLNP_OPTION_SCOPE_SA_SPEC, "Source Address Specific"},
307147904Ssam    { CLNP_OPTION_SCOPE_DA_SPEC, "Destination Address Specific"},
308147904Ssam    { CLNP_OPTION_SCOPE_GLOBAL, "Globally unique"},
309147904Ssam    { 0, NULL }
310147904Ssam};
311147904Ssam
312147904Ssamstatic struct tok clnp_option_sr_rr_values[] = {
313147904Ssam    { 0x0, "partial"},
314147904Ssam    { 0x1, "complete"},
315147904Ssam    { 0, NULL }
316147904Ssam};
317147904Ssam
318147904Ssamstatic struct tok clnp_option_sr_rr_string_values[] = {
319147904Ssam    { CLNP_OPTION_SOURCE_ROUTING, "source routing"},
320147904Ssam    { CLNP_OPTION_ROUTE_RECORDING, "recording of route in progress"},
321147904Ssam    { 0, NULL }
322147904Ssam};
323147904Ssam
324147904Ssamstatic struct tok clnp_option_qos_global_values[] = {
325147904Ssam    { 0x20, "reserved"},
326147904Ssam    { 0x10, "sequencing vs. delay"},
327147904Ssam    { 0x08, "congested"},
328147904Ssam    { 0x04, "delay vs. cost"},
329147904Ssam    { 0x02, "error vs. delay"},
330147904Ssam    { 0x01, "error vs. cost"},
331147904Ssam    { 0, NULL }
332147904Ssam};
333147904Ssam
334146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP           3 /* draft-ietf-isis-traffic-05 */
335146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID  4 /* draft-ietf-isis-gmpls-extensions */
336146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID        5 /* draft-ietf-isis-traffic-05 */
337146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR        6 /* draft-ietf-isis-traffic-05 */
338146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR    8 /* draft-ietf-isis-traffic-05 */
339146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW           9 /* draft-ietf-isis-traffic-05 */
340146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW        10 /* draft-ietf-isis-traffic-05 */
341146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW        11 /* draft-ietf-isis-traffic-05 */
342146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_DIFFSERV_TE          12 /* draft-ietf-tewg-diff-te-proto-06 */
343146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC            18 /* draft-ietf-isis-traffic-05 */
344146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE 20 /* draft-ietf-isis-gmpls-extensions */
345146778Ssam#define ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR    21 /* draft-ietf-isis-gmpls-extensions */
346146778Ssam
347127675Sbmsstatic struct tok isis_ext_is_reach_subtlv_values[] = {
348146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP,            "Administrative groups" },
349146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID,   "Link Local/Remote Identifier" },
350146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID,         "Link Remote Identifier" },
351146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR,         "IPv4 interface address" },
352146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR,     "IPv4 neighbor address" },
353146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW,            "Maximum link bandwidth" },
354146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW,          "Reservable link bandwidth" },
355146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW,          "Unreserved bandwidth" },
356146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_DIFFSERV_TE,            "Diffserv TE" },
357146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC,              "Traffic Engineering Metric" },
358146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE,   "Link Protection Type" },
359146778Ssam    { ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR,      "Interface Switching Capability" },
360146778Ssam    { 250,                                             "Reserved for cisco specific extensions" },
361146778Ssam    { 251,                                             "Reserved for cisco specific extensions" },
362146778Ssam    { 252,                                             "Reserved for cisco specific extensions" },
363146778Ssam    { 253,                                             "Reserved for cisco specific extensions" },
364146778Ssam    { 254,                                             "Reserved for cisco specific extensions" },
365146778Ssam    { 255,                                             "Reserved for future expansion" },
366127675Sbms    { 0, NULL }
367127675Sbms};
36898527Sfenner
369146778Ssam#define ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32          1 /* draft-ietf-isis-admin-tags-01 */
370146778Ssam#define ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64          2 /* draft-ietf-isis-admin-tags-01 */
371146778Ssam#define ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR  117 /* draft-ietf-isis-wg-multi-topology-05 */
372127675Sbms
373127675Sbmsstatic struct tok isis_ext_ip_reach_subtlv_values[] = {
374146778Ssam    { ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32,           "32-Bit Administrative tag" },
375146778Ssam    { ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64,           "64-Bit Administrative tag" },
376146778Ssam    { ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR,     "Management Prefix Color" },
377127675Sbms    { 0, NULL }
378127675Sbms};
379127675Sbms
380146778Ssam#define ISIS_SUBTLV_AUTH_SIMPLE        1
381146778Ssam#define ISIS_SUBTLV_AUTH_MD5          54
382146778Ssam#define ISIS_SUBTLV_AUTH_MD5_LEN      16
383146778Ssam#define ISIS_SUBTLV_AUTH_PRIVATE     255
384127675Sbms
385127675Sbmsstatic struct tok isis_subtlv_auth_values[] = {
386146778Ssam    { ISIS_SUBTLV_AUTH_SIMPLE,	"simple text password"},
387146778Ssam    { ISIS_SUBTLV_AUTH_MD5,	"HMAC-MD5 password"},
388146778Ssam    { ISIS_SUBTLV_AUTH_PRIVATE,	"Routing Domain private password"},
389127675Sbms    { 0, NULL }
390127675Sbms};
391127675Sbms
392146778Ssam#define ISIS_SUBTLV_IDRP_RES           0
393146778Ssam#define ISIS_SUBTLV_IDRP_LOCAL         1
394146778Ssam#define ISIS_SUBTLV_IDRP_ASN           2
395127675Sbms
396127675Sbmsstatic struct tok isis_subtlv_idrp_values[] = {
397146778Ssam    { ISIS_SUBTLV_IDRP_RES,         "Reserved"},
398146778Ssam    { ISIS_SUBTLV_IDRP_LOCAL,       "Routing-Domain Specific"},
399146778Ssam    { ISIS_SUBTLV_IDRP_ASN,         "AS Number Tag"},
400127675Sbms    { 0, NULL}
401127675Sbms};
402127675Sbms
403146778Ssam#define CLNP_SEGMENT_PART  0x80
404146778Ssam#define CLNP_MORE_SEGMENTS 0x40
405146778Ssam#define CLNP_REQUEST_ER    0x20
406127675Sbms
407146778Ssamstatic struct tok clnp_flag_values[] = {
408146778Ssam    { CLNP_SEGMENT_PART, "Segmentation permitted"},
409146778Ssam    { CLNP_MORE_SEGMENTS, "more Segments"},
410146778Ssam    { CLNP_REQUEST_ER, "request Error Report"},
411146778Ssam    { 0, NULL}
412146778Ssam};
413146778Ssam
41498527Sfenner#define ISIS_MASK_LSP_OL_BIT(x)            ((x)&0x4)
41598527Sfenner#define ISIS_MASK_LSP_ISTYPE_BITS(x)       ((x)&0x3)
41698527Sfenner#define ISIS_MASK_LSP_PARTITION_BIT(x)     ((x)&0x80)
41798527Sfenner#define ISIS_MASK_LSP_ATT_BITS(x)          ((x)&0x78)
41898527Sfenner#define ISIS_MASK_LSP_ATT_ERROR_BIT(x)     ((x)&0x40)
41998527Sfenner#define ISIS_MASK_LSP_ATT_EXPENSE_BIT(x)   ((x)&0x20)
42098527Sfenner#define ISIS_MASK_LSP_ATT_DELAY_BIT(x)     ((x)&0x10)
42198527Sfenner#define ISIS_MASK_LSP_ATT_DEFAULT_BIT(x)   ((x)&0x8)
42298527Sfenner
423127675Sbms#define ISIS_MASK_MTID(x)                  ((x)&0x0fff)
424127675Sbms#define ISIS_MASK_MTFLAGS(x)               ((x)&0xf000)
42598527Sfenner
426127675Sbmsstatic struct tok isis_mt_flag_values[] = {
427127675Sbms    { 0x4000,                  "sub-TLVs present"},
428127675Sbms    { 0x8000,                  "ATT bit set"},
429127675Sbms    { 0, NULL}
430127675Sbms};
43198527Sfenner
432127675Sbms#define ISIS_MASK_TLV_EXTD_IP_UPDOWN(x)     ((x)&0x80)
433127675Sbms#define ISIS_MASK_TLV_EXTD_IP_SUBTLV(x)     ((x)&0x40)
43498527Sfenner
435127675Sbms#define ISIS_MASK_TLV_EXTD_IP6_IE(x)        ((x)&0x40)
436127675Sbms#define ISIS_MASK_TLV_EXTD_IP6_SUBTLV(x)    ((x)&0x20)
437127675Sbms
43898527Sfenner#define ISIS_LSP_TLV_METRIC_SUPPORTED(x)   ((x)&0x80)
43998527Sfenner#define ISIS_LSP_TLV_METRIC_IE(x)          ((x)&0x40)
44098527Sfenner#define ISIS_LSP_TLV_METRIC_UPDOWN(x)      ((x)&0x80)
44198527Sfenner#define ISIS_LSP_TLV_METRIC_VALUE(x)	   ((x)&0x3f)
44298527Sfenner
443127675Sbms#define ISIS_MASK_TLV_SHARED_RISK_GROUP(x) ((x)&0x1)
444127675Sbms
445127675Sbmsstatic struct tok isis_mt_values[] = {
446127675Sbms    { 0,    "IPv4 unicast"},
447127675Sbms    { 1,    "In-Band Management"},
448127675Sbms    { 2,    "IPv6 unicast"},
449127675Sbms    { 3,    "Multicast"},
450127675Sbms    { 4095, "Development, Experimental or Proprietary"},
451127675Sbms    { 0, NULL }
452127675Sbms};
453127675Sbms
454127675Sbmsstatic struct tok isis_iih_circuit_type_values[] = {
455127675Sbms    { 1,    "Level 1 only"},
456127675Sbms    { 2,    "Level 2 only"},
457127675Sbms    { 3,    "Level 1, Level 2"},
458127675Sbms    { 0, NULL}
459127675Sbms};
460127675Sbms
46198527Sfenner#define ISIS_LSP_TYPE_UNUSED0   0
46298527Sfenner#define ISIS_LSP_TYPE_LEVEL_1   1
46398527Sfenner#define ISIS_LSP_TYPE_UNUSED2   2
46498527Sfenner#define ISIS_LSP_TYPE_LEVEL_2   3
46598527Sfenner
46698527Sfennerstatic struct tok isis_lsp_istype_values[] = {
467127675Sbms    { ISIS_LSP_TYPE_UNUSED0,	"Unused 0x0 (invalid)"},
468127675Sbms    { ISIS_LSP_TYPE_LEVEL_1,	"L1 IS"},
469127675Sbms    { ISIS_LSP_TYPE_UNUSED2,	"Unused 0x2 (invalid)"},
470127675Sbms    { ISIS_LSP_TYPE_LEVEL_2,	"L1L2 IS"},
471127675Sbms    { 0, NULL }
47298527Sfenner};
47398527Sfenner
47432149Spst/*
47532149Spst * Katz's point to point adjacency TLV uses codes to tell us the state of
47632149Spst * the remote adjacency.  Enumerate them.
47732149Spst */
47832149Spst
47932149Spst#define ISIS_PTP_ADJ_UP   0
48032149Spst#define ISIS_PTP_ADJ_INIT 1
48132149Spst#define ISIS_PTP_ADJ_DOWN 2
48232149Spst
48398527Sfennerstatic struct tok isis_ptp_adjancey_values[] = {
484127675Sbms    { ISIS_PTP_ADJ_UP,    "Up" },
485127675Sbms    { ISIS_PTP_ADJ_INIT,  "Initializing" },
486127675Sbms    { ISIS_PTP_ADJ_DOWN,  "Down" },
487127675Sbms    { 0, NULL}
48832149Spst};
48932149Spst
49098527Sfennerstruct isis_tlv_ptp_adj {
491127675Sbms    u_int8_t adjacency_state;
492127675Sbms    u_int8_t extd_local_circuit_id[4];
493127675Sbms    u_int8_t neighbor_sysid[SYSTEM_ID_LEN];
494127675Sbms    u_int8_t neighbor_extd_local_circuit_id[4];
49532149Spst};
49632149Spst
497127675Sbmsstatic int osi_cksum(const u_int8_t *, u_int);
498146778Ssamstatic int clnp_print(const u_int8_t *, u_int);
499127675Sbmsstatic void esis_print(const u_int8_t *, u_int);
500127675Sbmsstatic int isis_print(const u_int8_t *, u_int);
501127675Sbms
502127675Sbmsstruct isis_metric_block {
503127675Sbms    u_int8_t metric_default;
504127675Sbms    u_int8_t metric_delay;
505127675Sbms    u_int8_t metric_expense;
506127675Sbms    u_int8_t metric_error;
50798527Sfenner};
50898527Sfenner
50998527Sfennerstruct isis_tlv_is_reach {
510127675Sbms    struct isis_metric_block isis_metric_block;
511127675Sbms    u_int8_t neighbor_nodeid[NODE_ID_LEN];
51298527Sfenner};
51398527Sfenner
514127675Sbmsstruct isis_tlv_es_reach {
515127675Sbms    struct isis_metric_block isis_metric_block;
516127675Sbms    u_int8_t neighbor_sysid[SYSTEM_ID_LEN];
517127675Sbms};
51898527Sfenner
519127675Sbmsstruct isis_tlv_ip_reach {
520127675Sbms    struct isis_metric_block isis_metric_block;
521127675Sbms    u_int8_t prefix[4];
522127675Sbms    u_int8_t mask[4];
523127675Sbms};
524127675Sbms
525127675Sbmsstatic struct tok isis_is_reach_virtual_values[] = {
526127675Sbms    { 0,    "IsNotVirtual"},
527127675Sbms    { 1,    "IsVirtual"},
528127675Sbms    { 0, NULL }
529127675Sbms};
530127675Sbms
531127675Sbmsstatic struct tok isis_restart_flag_values[] = {
532127675Sbms    { 0x1,  "Restart Request"},
533127675Sbms    { 0x2,  "Restart Acknowledgement"},
534147904Ssam    { 0x4,  "Suppress adjacency advertisement"},
535127675Sbms    { 0, NULL }
536127675Sbms};
537127675Sbms
53832149Spststruct isis_common_header {
539127675Sbms    u_int8_t nlpid;
540127675Sbms    u_int8_t fixed_len;
541127675Sbms    u_int8_t version;			/* Protocol version */
542127675Sbms    u_int8_t id_length;
543127675Sbms    u_int8_t pdu_type;		        /* 3 MSbits are reserved */
544127675Sbms    u_int8_t pdu_version;		/* Packet format version */
545127675Sbms    u_int8_t reserved;
546127675Sbms    u_int8_t max_area;
54732149Spst};
54832149Spst
54998527Sfennerstruct isis_iih_lan_header {
550127675Sbms    u_int8_t circuit_type;
551127675Sbms    u_int8_t source_id[SYSTEM_ID_LEN];
552127675Sbms    u_int8_t holding_time[2];
553127675Sbms    u_int8_t pdu_len[2];
554127675Sbms    u_int8_t priority;
555127675Sbms    u_int8_t lan_id[NODE_ID_LEN];
55632149Spst};
55798527Sfenner
55898527Sfennerstruct isis_iih_ptp_header {
559127675Sbms    u_int8_t circuit_type;
560127675Sbms    u_int8_t source_id[SYSTEM_ID_LEN];
561127675Sbms    u_int8_t holding_time[2];
562127675Sbms    u_int8_t pdu_len[2];
563127675Sbms    u_int8_t circuit_id;
56432149Spst};
56532149Spst
56698527Sfennerstruct isis_lsp_header {
567127675Sbms    u_int8_t pdu_len[2];
568127675Sbms    u_int8_t remaining_lifetime[2];
569127675Sbms    u_int8_t lsp_id[LSP_ID_LEN];
570127675Sbms    u_int8_t sequence_number[4];
571127675Sbms    u_int8_t checksum[2];
572127675Sbms    u_int8_t typeblock;
57332149Spst};
57432149Spst
57598527Sfennerstruct isis_csnp_header {
576127675Sbms    u_int8_t pdu_len[2];
577127675Sbms    u_int8_t source_id[NODE_ID_LEN];
578127675Sbms    u_int8_t start_lsp_id[LSP_ID_LEN];
579127675Sbms    u_int8_t end_lsp_id[LSP_ID_LEN];
58098527Sfenner};
58132149Spst
58298527Sfennerstruct isis_psnp_header {
583127675Sbms    u_int8_t pdu_len[2];
584127675Sbms    u_int8_t source_id[NODE_ID_LEN];
58598527Sfenner};
58632149Spst
58798527Sfennerstruct isis_tlv_lsp {
588127675Sbms    u_int8_t remaining_lifetime[2];
589127675Sbms    u_int8_t lsp_id[LSP_ID_LEN];
590127675Sbms    u_int8_t sequence_number[4];
591127675Sbms    u_int8_t checksum[2];
59298527Sfenner};
593127675Sbms
59498527Sfenner#define ISIS_COMMON_HEADER_SIZE (sizeof(struct isis_common_header))
59598527Sfenner#define ISIS_IIH_LAN_HEADER_SIZE (sizeof(struct isis_iih_lan_header))
59698527Sfenner#define ISIS_IIH_PTP_HEADER_SIZE (sizeof(struct isis_iih_ptp_header))
59798527Sfenner#define ISIS_LSP_HEADER_SIZE (sizeof(struct isis_lsp_header))
59898527Sfenner#define ISIS_CSNP_HEADER_SIZE (sizeof(struct isis_csnp_header))
59998527Sfenner#define ISIS_PSNP_HEADER_SIZE (sizeof(struct isis_psnp_header))
60032149Spst
601127675Sbmsvoid isoclns_print(const u_int8_t *p, u_int length, u_int caplen)
60217680Spst{
60398527Sfenner	const struct isis_common_header *header;
604127675Sbms
60598527Sfenner	header = (const struct isis_common_header *)p;
60632149Spst
607146778Ssam        if (caplen <= 1) { /* enough bytes on the wire ? */
608146778Ssam            printf("|OSI");
609146778Ssam            return;
610146778Ssam        }
61117680Spst
612146778Ssam        if (eflag)
613146778Ssam            printf("OSI NLPID %s (0x%02x): ",
614146778Ssam                   tok2str(nlpid_values,"Unknown",*p),
615146778Ssam                   *p);
616146778Ssam
61717680Spst	switch (*p) {
61817680Spst
619146778Ssam	case NLPID_CLNP:
620146778Ssam		if (!clnp_print(p, length))
621146778Ssam                        print_unknown_data(p,"\n\t",caplen);
62217680Spst		break;
62317680Spst
62417688Spst	case NLPID_ESIS:
62517680Spst		esis_print(p, length);
62617680Spst		return;
62717680Spst
62817688Spst	case NLPID_ISIS:
62917751Spst		if (!isis_print(p, length))
630127675Sbms                        print_unknown_data(p,"\n\t",caplen);
63117680Spst		break;
63217680Spst
63317688Spst	case NLPID_NULLNS:
634147904Ssam		(void)printf("%slength: %u",
635147904Ssam		             eflag ? "" : ", ",
636147904Ssam                             length);
63717680Spst		break;
63817680Spst
639146778Ssam        case NLPID_Q933:
640146778Ssam                q933_print(p+1, length-1);
641146778Ssam                break;
642146778Ssam
643146778Ssam        case NLPID_IP:
644146778Ssam		ip_print(gndo, p+1, length-1);
645146778Ssam                break;
646146778Ssam
647146778Ssam#ifdef INET6
648146778Ssam        case NLPID_IP6:
649146778Ssam                ip6_print(p+1, length-1);
650146778Ssam                break;
651146778Ssam#endif
652146778Ssam
653146778Ssam        case NLPID_PPP:
654146778Ssam                ppp_print(p+1, length-1);
655146778Ssam                break;
656146778Ssam
65717680Spst	default:
658146778Ssam                if (!eflag)
659146778Ssam                    printf("OSI NLPID 0x%02x unknown",*p);
660147904Ssam		(void)printf("%slength: %u",
661147904Ssam		             eflag ? "" : ", ",
662147904Ssam                             length);
66317680Spst		if (caplen > 1)
664127675Sbms                        print_unknown_data(p,"\n\t",caplen);
66517680Spst		break;
66617680Spst	}
66717680Spst}
66817680Spst
669146778Ssam#define	CLNP_PDU_ER	 1
670146778Ssam#define	CLNP_PDU_DT	28
671146778Ssam#define	CLNP_PDU_MD	29
672146778Ssam#define	CLNP_PDU_ERQ	30
673146778Ssam#define	CLNP_PDU_ERP	31
67417680Spst
675146778Ssamstatic struct tok clnp_pdu_values[] = {
676146778Ssam    { CLNP_PDU_ER,  "Error Report"},
677146778Ssam    { CLNP_PDU_MD,  "MD"},
678146778Ssam    { CLNP_PDU_DT,  "Data"},
679146778Ssam    { CLNP_PDU_ERQ, "Echo Request"},
680146778Ssam    { CLNP_PDU_ERP, "Echo Response"},
681127675Sbms    { 0, NULL }
682127675Sbms};
683127675Sbms
684146778Ssamstruct clnp_header_t {
685146778Ssam    u_int8_t nlpid;
686146778Ssam    u_int8_t length_indicator;
687146778Ssam    u_int8_t version;
688146778Ssam    u_int8_t lifetime; /* units of 500ms */
689146778Ssam    u_int8_t type;
690146778Ssam    u_int8_t segment_length[2];
691146778Ssam    u_int8_t cksum[2];
692146778Ssam};
693146778Ssam
694146778Ssamstruct clnp_segment_header_t {
695146778Ssam    u_int8_t data_unit_id[2];
696146778Ssam    u_int8_t segment_offset[2];
697146778Ssam    u_int8_t total_length[2];
698146778Ssam};
699146778Ssam
700146778Ssam/*
701146778Ssam * clnp_print
702146778Ssam * Decode CLNP packets.  Return 0 on error.
703146778Ssam */
704146778Ssam
705146778Ssamstatic int clnp_print (const u_int8_t *pptr, u_int length)
706146778Ssam{
707146778Ssam	const u_int8_t *optr,*source_address,*dest_address;
708147904Ssam        u_int li,tlen,nsap_offset,source_address_length,dest_address_length, clnp_pdu_type, clnp_flags;
709146778Ssam	const struct clnp_header_t *clnp_header;
710146778Ssam	const struct clnp_segment_header_t *clnp_segment_header;
711146778Ssam        u_int8_t rfd_error_major,rfd_error_minor;
712146778Ssam
713146778Ssam	clnp_header = (const struct clnp_header_t *) pptr;
714146778Ssam        TCHECK(*clnp_header);
715146778Ssam
716146778Ssam        li = clnp_header->length_indicator;
717146778Ssam        optr = pptr;
718146778Ssam
719146778Ssam        if (!eflag)
720146778Ssam            printf("CLNP");
721146778Ssam
722146778Ssam        /*
723146778Ssam         * Sanity checking of the header.
724146778Ssam         */
725146778Ssam
726146778Ssam        if (clnp_header->version != CLNP_VERSION) {
727146778Ssam            printf("version %d packet not supported", clnp_header->version);
728146778Ssam            return (0);
729146778Ssam        }
730146778Ssam
731146778Ssam        /* FIXME further header sanity checking */
732146778Ssam
733146778Ssam        clnp_pdu_type = clnp_header->type & CLNP_PDU_TYPE_MASK;
734146778Ssam        clnp_flags = clnp_header->type & CLNP_FLAG_MASK;
735146778Ssam
736146778Ssam        pptr += sizeof(struct clnp_header_t);
737146778Ssam        li -= sizeof(struct clnp_header_t);
738146778Ssam        dest_address_length = *pptr;
739146778Ssam        dest_address = pptr + 1;
740146778Ssam
741146778Ssam        pptr += (1 + dest_address_length);
742146778Ssam        li -= (1 + dest_address_length);
743146778Ssam        source_address_length = *pptr;
744146778Ssam        source_address = pptr +1;
745146778Ssam
746146778Ssam        pptr += (1 + source_address_length);
747146778Ssam        li -= (1 + source_address_length);
748146778Ssam
749146778Ssam        if (vflag < 1) {
750146778Ssam            printf("%s%s > %s, %s, length %u",
751146778Ssam                   eflag ? "" : ", ",
752146778Ssam                   isonsap_string(source_address, source_address_length),
753146778Ssam                   isonsap_string(dest_address, dest_address_length),
754146778Ssam                   tok2str(clnp_pdu_values,"unknown (%u)",clnp_pdu_type),
755146778Ssam                   length);
756146778Ssam            return (1);
757146778Ssam        }
758146778Ssam        printf("%slength %u",eflag ? "" : ", ",length);
759146778Ssam
760146778Ssam        printf("\n\t%s PDU, hlen: %u, v: %u, lifetime: %u.%us, Segment PDU length: %u, checksum: 0x%04x ",
761146778Ssam               tok2str(clnp_pdu_values, "unknown (%u)",clnp_pdu_type),
762146778Ssam               clnp_header->length_indicator,
763146778Ssam               clnp_header->version,
764146778Ssam               clnp_header->lifetime/2,
765146778Ssam               (clnp_header->lifetime%2)*5,
766146778Ssam               EXTRACT_16BITS(clnp_header->segment_length),
767146778Ssam               EXTRACT_16BITS(clnp_header->cksum));
768146778Ssam
769146778Ssam        /* do not attempt to verify the checksum if it is zero */
770146778Ssam        if (EXTRACT_16BITS(clnp_header->cksum) == 0)
771146778Ssam                printf("(unverified)");
772146778Ssam            else printf("(%s)", osi_cksum(optr, clnp_header->length_indicator) ? "incorrect" : "correct");
773146778Ssam
774146778Ssam        printf("\n\tFlags [%s]",
775146778Ssam               bittok2str(clnp_flag_values,"none",clnp_flags));
776146778Ssam
777146778Ssam        printf("\n\tsource address (length %u): %s\n\tdest   address (length %u): %s",
778146778Ssam               source_address_length,
779146778Ssam               isonsap_string(source_address, source_address_length),
780146778Ssam               dest_address_length,
781146778Ssam               isonsap_string(dest_address,dest_address_length));
782146778Ssam
783146778Ssam        if (clnp_flags & CLNP_SEGMENT_PART) {
784146778Ssam            	clnp_segment_header = (const struct clnp_segment_header_t *) pptr;
785146778Ssam                printf("\n\tData Unit ID: 0x%04x, Segment Offset: %u, Total PDU Length: %u",
786146778Ssam                       EXTRACT_16BITS(clnp_segment_header->data_unit_id),
787146778Ssam                       EXTRACT_16BITS(clnp_segment_header->segment_offset),
788146778Ssam                       EXTRACT_16BITS(clnp_segment_header->total_length));
789146778Ssam                pptr+=sizeof(const struct clnp_segment_header_t);
790146778Ssam                li-=sizeof(const struct clnp_segment_header_t);
791146778Ssam        }
792146778Ssam
793146778Ssam        /* now walk the options */
794146778Ssam        while (li >= 2) {
795146778Ssam            u_int op, opli;
796146778Ssam            const u_int8_t *tptr;
797146778Ssam
798147904Ssam            TCHECK2(*pptr, 2);
799146778Ssam            if (li < 2) {
800146778Ssam                printf(", bad opts/li");
801146778Ssam                return (0);
802146778Ssam            }
803146778Ssam            op = *pptr++;
804146778Ssam            opli = *pptr++;
805146778Ssam            li -= 2;
806147904Ssam            TCHECK2(*pptr, opli);
807146778Ssam            if (opli > li) {
808146778Ssam                printf(", opt (%d) too long", op);
809146778Ssam                return (0);
810146778Ssam            }
811146778Ssam            li -= opli;
812146778Ssam            tptr = pptr;
813147904Ssam            tlen = opli;
814146778Ssam
815146778Ssam            printf("\n\t  %s Option #%u, length %u, value: ",
816146778Ssam                   tok2str(clnp_option_values,"Unknown",op),
817146778Ssam                   op,
818146778Ssam                   opli);
819146778Ssam
820146778Ssam            switch (op) {
821146778Ssam
822147904Ssam
823147904Ssam            case CLNP_OPTION_ROUTE_RECORDING: /* those two options share the format */
824147904Ssam            case CLNP_OPTION_SOURCE_ROUTING:
825147904Ssam                    printf("%s %s",
826147904Ssam                           tok2str(clnp_option_sr_rr_values,"Unknown",*tptr),
827147904Ssam                           tok2str(clnp_option_sr_rr_string_values,"Unknown Option %u",op));
828147904Ssam                    nsap_offset=*(tptr+1);
829147904Ssam                    if (nsap_offset == 0) {
830147904Ssam                            printf(" Bad NSAP offset (0)");
831147904Ssam                            break;
832147904Ssam                    }
833147904Ssam                    nsap_offset-=1; /* offset to nsap list */
834147904Ssam                    if (nsap_offset > tlen) {
835147904Ssam                            printf(" Bad NSAP offset (past end of option)");
836147904Ssam                            break;
837147904Ssam                    }
838147904Ssam                    tptr+=nsap_offset;
839147904Ssam                    tlen-=nsap_offset;
840147904Ssam                    while (tlen > 0) {
841147904Ssam                            source_address_length=*tptr;
842147904Ssam                            if (tlen < source_address_length+1) {
843147904Ssam                                    printf("\n\t    NSAP address goes past end of option");
844147904Ssam                                    break;
845147904Ssam                    	    }
846147904Ssam                            if (source_address_length > 0) {
847147904Ssam                                    source_address=(tptr+1);
848147904Ssam                                    TCHECK2(*source_address, source_address_length);
849147904Ssam                                    printf("\n\t    NSAP address (length %u): %s",
850147904Ssam                                           source_address_length,
851147904Ssam                                           isonsap_string(source_address, source_address_length));
852147904Ssam                            }
853147904Ssam                            tlen-=source_address_length+1;
854147904Ssam                    }
855147904Ssam                    break;
856147904Ssam
857146778Ssam            case CLNP_OPTION_PRIORITY:
858147904Ssam                    printf("0x%1x", *tptr&0x0f);
859147904Ssam                    break;
860146778Ssam
861147904Ssam            case CLNP_OPTION_QOS_MAINTENANCE:
862147904Ssam                    printf("\n\t    Format Code: %s",
863147904Ssam                           tok2str(clnp_option_scope_values,"Reserved",*tptr&CLNP_OPTION_SCOPE_MASK));
864147904Ssam
865147904Ssam                    if ((*tptr&CLNP_OPTION_SCOPE_MASK) == CLNP_OPTION_SCOPE_GLOBAL)
866147904Ssam                            printf("\n\t    QoS Flags [%s]",
867147904Ssam                                   bittok2str(clnp_option_qos_global_values,
868147904Ssam                                              "none",
869147904Ssam                                              *tptr&CLNP_OPTION_OPTION_QOS_MASK));
870147904Ssam                    break;
871147904Ssam
872147904Ssam            case CLNP_OPTION_SECURITY:
873147904Ssam                    printf("\n\t    Format Code: %s, Security-Level %u",
874147904Ssam                           tok2str(clnp_option_scope_values,"Reserved",*tptr&CLNP_OPTION_SCOPE_MASK),
875147904Ssam                           *(tptr+1));
876147904Ssam                    break;
877147904Ssam
878146778Ssam            case CLNP_OPTION_DISCARD_REASON:
879146778Ssam                rfd_error_major = (*tptr&0xf0) >> 4;
880146778Ssam                rfd_error_minor = *tptr&0x0f;
881146778Ssam                printf("\n\t    Class: %s Error (0x%01x), %s (0x%01x)",
882146778Ssam                       tok2str(clnp_option_rfd_class_values,"Unknown",rfd_error_major),
883146778Ssam                       rfd_error_major,
884146778Ssam                       tok2str(clnp_option_rfd_error_class[rfd_error_major],"Unknown",rfd_error_minor),
885146778Ssam                       rfd_error_minor);
886146778Ssam                break;
887146778Ssam
888147904Ssam            case CLNP_OPTION_PADDING:
889147904Ssam                    printf("padding data");
890147904Ssam                break;
891147904Ssam
892146778Ssam                /*
893146778Ssam                 * FIXME those are the defined Options that lack a decoder
894146778Ssam                 * you are welcome to contribute code ;-)
895146778Ssam                 */
896146778Ssam
897146778Ssam            default:
898146778Ssam                print_unknown_data(tptr,"\n\t  ",opli);
899146778Ssam                break;
900146778Ssam            }
901146778Ssam            if (vflag > 1)
902146778Ssam                print_unknown_data(pptr,"\n\t  ",opli);
903146778Ssam            pptr += opli;
904146778Ssam        }
905146778Ssam
906146778Ssam        switch (clnp_pdu_type) {
907146778Ssam
908146778Ssam        case    CLNP_PDU_ER: /* fall through */
909146778Ssam        case 	CLNP_PDU_ERP:
910147904Ssam            TCHECK(*pptr);
911146778Ssam            if (*(pptr) == NLPID_CLNP) {
912146778Ssam                printf("\n\t-----original packet-----\n\t");
913146778Ssam                /* FIXME recursion protection */
914146778Ssam                clnp_print(pptr, length-clnp_header->length_indicator);
915146778Ssam                break;
916146778Ssam            }
917146778Ssam
918146778Ssam        case 	CLNP_PDU_DT:
919146778Ssam        case 	CLNP_PDU_MD:
920146778Ssam        case 	CLNP_PDU_ERQ:
921146778Ssam
922146778Ssam        default:
923146778Ssam            /* dump the PDU specific data */
924146778Ssam            if (length-(pptr-optr) > 0) {
925146778Ssam                printf("\n\t  undecoded non-header data, length %u",length-clnp_header->length_indicator);
926146778Ssam                print_unknown_data(pptr,"\n\t  ",length-(pptr-optr));
927146778Ssam            }
928146778Ssam        }
929146778Ssam
930146778Ssam        return (1);
931146778Ssam
932146778Ssam trunc:
933146778Ssam    fputs("[|clnp]", stdout);
934146778Ssam    return (1);
935146778Ssam
936146778Ssam}
937146778Ssam
938146778Ssam
939146778Ssam#define	ESIS_PDU_REDIRECT	6
940146778Ssam#define	ESIS_PDU_ESH	        2
941146778Ssam#define	ESIS_PDU_ISH	        4
942146778Ssam
943146778Ssamstatic struct tok esis_pdu_values[] = {
944146778Ssam    { ESIS_PDU_REDIRECT, "redirect"},
945146778Ssam    { ESIS_PDU_ESH,      "ESH"},
946146778Ssam    { ESIS_PDU_ISH,      "ISH"},
947146778Ssam    { 0, NULL }
948146778Ssam};
949146778Ssam
950146778Ssamstruct esis_header_t {
951146778Ssam	u_int8_t nlpid;
952146778Ssam	u_int8_t length_indicator;
953127675Sbms	u_int8_t version;
954127675Sbms	u_int8_t reserved;
955127675Sbms	u_int8_t type;
956146778Ssam	u_int8_t holdtime[2];
957127675Sbms	u_int8_t cksum[2];
95817680Spst};
95917680Spst
96017680Spststatic void
961146778Ssamesis_print(const u_int8_t *pptr, u_int length)
96217680Spst{
963146778Ssam	const u_int8_t *optr;
964146778Ssam	u_int li,esis_pdu_type,source_address_length, source_address_number;
965146778Ssam	const struct esis_header_t *esis_header;
96617680Spst
967146778Ssam        if (!eflag)
968146778Ssam            printf("ES-IS");
969146778Ssam
97098527Sfenner	if (length <= 2) {
97117680Spst		if (qflag)
972146778Ssam			printf("bad pkt!");
97317680Spst		else
974146778Ssam			printf("no header at all!");
97517680Spst		return;
97617680Spst	}
977146778Ssam
978146778Ssam	esis_header = (const struct esis_header_t *) pptr;
979147904Ssam        TCHECK(*esis_header);
980146778Ssam        li = esis_header->length_indicator;
981146778Ssam        optr = pptr;
982146778Ssam
983146778Ssam        /*
984146778Ssam         * Sanity checking of the header.
985146778Ssam         */
986146778Ssam
987146778Ssam        if (esis_header->nlpid != NLPID_ESIS) {
988146778Ssam            printf(" nlpid 0x%02x packet not supported", esis_header->nlpid);
989146778Ssam            return;
990146778Ssam        }
991146778Ssam
992146778Ssam        if (esis_header->version != ESIS_VERSION) {
993146778Ssam            printf(" version %d packet not supported", esis_header->version);
994146778Ssam            return;
995146778Ssam        }
996146778Ssam
99717680Spst	if (li > length) {
998146778Ssam            printf(" length indicator(%d) > PDU size (%d)!", li, length);
999146778Ssam            return;
100017680Spst	}
1001146778Ssam
1002146778Ssam	if (li < sizeof(struct esis_header_t) + 2) {
1003146778Ssam            printf(" length indicator < min PDU size %d:", li);
1004146778Ssam            while (--length != 0)
1005146778Ssam                printf("%02X", *pptr++);
1006146778Ssam            return;
100717680Spst	}
100817680Spst
1009146778Ssam        esis_pdu_type = esis_header->type & ESIS_PDU_TYPE_MASK;
101017680Spst
1011146778Ssam        if (vflag < 1) {
1012146778Ssam            printf("%s%s, length %u",
1013146778Ssam                   eflag ? "" : ", ",
1014146778Ssam                   tok2str(esis_pdu_values,"unknown type (%u)",esis_pdu_type),
1015146778Ssam                   length);
1016146778Ssam            return;
1017146778Ssam        } else
1018146778Ssam            printf("%slength %u\n\t%s (%u)",
1019146778Ssam                   eflag ? "" : ", ",
1020146778Ssam                   length,
1021146778Ssam                   tok2str(esis_pdu_values,"unknown type: %u", esis_pdu_type),
1022146778Ssam                   esis_pdu_type);
102317680Spst
1024146778Ssam        printf(", v: %u%s", esis_header->version, esis_header->version == ESIS_VERSION ? "" : "unsupported" );
1025146778Ssam        printf(", checksum: 0x%04x ", EXTRACT_16BITS(esis_header->cksum));
1026146778Ssam        /* do not attempt to verify the checksum if it is zero */
1027146778Ssam        if (EXTRACT_16BITS(esis_header->cksum) == 0)
1028146778Ssam                printf("(unverified)");
1029147904Ssam        else
1030147904Ssam                printf("(%s)", osi_cksum(pptr, li) ? "incorrect" : "correct");
103117680Spst
1032146778Ssam        printf(", holding time: %us, length indicator: %u",EXTRACT_16BITS(esis_header->holdtime),li);
103317680Spst
1034146778Ssam        if (vflag > 1)
1035146778Ssam            print_unknown_data(optr,"\n\t",sizeof(struct esis_header_t));
1036146778Ssam
1037146778Ssam	pptr += sizeof(struct esis_header_t);
1038146778Ssam	li -= sizeof(struct esis_header_t);
1039146778Ssam
1040146778Ssam	switch (esis_pdu_type) {
1041146778Ssam	case ESIS_PDU_REDIRECT: {
1042147904Ssam		const u_int8_t *dst, *snpa, *neta;
1043147904Ssam		u_int dstl, snpal, netal;
1044146778Ssam
1045147904Ssam		TCHECK(*pptr);
1046147904Ssam		if (li < 1) {
1047147904Ssam			printf(", bad redirect/li");
104817680Spst			return;
1049147904Ssam		}
1050147904Ssam		dstl = *pptr;
1051147904Ssam		pptr++;
1052147904Ssam		li--;
1053147904Ssam		TCHECK2(*pptr, dstl);
1054147904Ssam		if (li < dstl) {
1055147904Ssam			printf(", bad redirect/li");
105617680Spst			return;
1057147904Ssam		}
1058147904Ssam		dst = pptr;
1059147904Ssam		pptr += dstl;
1060147904Ssam                li -= dstl;
1061147904Ssam		printf("\n\t  %s", isonsap_string(dst,dstl));
1062146778Ssam
1063147904Ssam		TCHECK(*pptr);
1064147904Ssam		if (li < 1) {
1065147904Ssam			printf(", bad redirect/li");
1066147904Ssam			return;
1067147904Ssam		}
1068147904Ssam		snpal = *pptr;
1069147904Ssam		pptr++;
1070147904Ssam		li--;
1071147904Ssam		TCHECK2(*pptr, snpal);
1072147904Ssam		if (li < snpal) {
1073147904Ssam			printf(", bad redirect/li");
1074147904Ssam			return;
1075147904Ssam		}
1076147904Ssam		snpa = pptr;
1077147904Ssam		pptr += snpal;
1078147904Ssam                li -= snpal;
1079147904Ssam		TCHECK(*pptr);
1080147904Ssam		if (li < 1) {
1081147904Ssam			printf(", bad redirect/li");
1082147904Ssam			return;
1083147904Ssam		}
1084147904Ssam		netal = *pptr;
1085147904Ssam		pptr++;
1086147904Ssam		TCHECK2(*pptr, netal);
1087147904Ssam		if (li < netal) {
1088147904Ssam			printf(", bad redirect/li");
1089147904Ssam			return;
1090147904Ssam		}
1091147904Ssam		neta = pptr;
1092147904Ssam		pptr += netal;
1093147904Ssam                li -= netal;
1094147904Ssam
1095147904Ssam		if (netal == 0)
1096147904Ssam			printf("\n\t  %s", etheraddr_string(snpa));
109717680Spst		else
1098147904Ssam			printf("\n\t  %s", isonsap_string(neta,netal));
109917680Spst		break;
110017680Spst	}
1101127675Sbms
1102146778Ssam	case ESIS_PDU_ESH:
1103147904Ssam            TCHECK(*pptr);
1104147904Ssam            if (li < 1) {
1105147904Ssam                printf(", bad esh/li");
1106147904Ssam                return;
1107147904Ssam            }
1108146778Ssam            source_address_number = *pptr;
1109146778Ssam            pptr++;
1110146778Ssam            li--;
1111127675Sbms
1112146778Ssam            printf("\n\t  Number of Source Addresses: %u", source_address_number);
1113146778Ssam
1114146778Ssam            while (source_address_number > 0) {
1115147904Ssam                TCHECK(*pptr);
1116147904Ssam            	if (li < 1) {
1117147904Ssam                    printf(", bad esh/li");
1118147904Ssam            	    return;
1119147904Ssam            	}
1120146778Ssam                source_address_length = *pptr;
1121147904Ssam                pptr++;
1122147904Ssam            	li--;
1123147904Ssam
1124147904Ssam                TCHECK2(*pptr, source_address_length);
1125147904Ssam            	if (li < source_address_length) {
1126147904Ssam                    printf(", bad esh/li");
1127147904Ssam            	    return;
1128147904Ssam            	}
1129146778Ssam                printf("\n\t  NET (length: %u): %s",
1130146778Ssam                       source_address_length,
1131147904Ssam                       isonsap_string(pptr,source_address_length));
1132147904Ssam                pptr += source_address_length;
1133147904Ssam                li -= source_address_length;
1134146778Ssam                source_address_number--;
1135146778Ssam            }
1136146778Ssam
1137146778Ssam            break;
1138146778Ssam
1139146778Ssam	case ESIS_PDU_ISH: {
1140147904Ssam            TCHECK(*pptr);
1141147904Ssam            if (li < 1) {
1142147904Ssam                printf(", bad ish/li");
1143147904Ssam                return;
1144147904Ssam            }
1145146778Ssam            source_address_length = *pptr;
1146147904Ssam            pptr++;
1147147904Ssam            li--;
1148147904Ssam            TCHECK2(*pptr, source_address_length);
1149147904Ssam            if (li < source_address_length) {
1150147904Ssam                printf(", bad ish/li");
1151147904Ssam                return;
1152147904Ssam            }
1153147904Ssam            printf("\n\t  NET (length: %u): %s", source_address_length, isonsap_string(pptr, source_address_length));
1154147904Ssam            pptr += source_address_length;
1155147904Ssam            li -= source_address_length;
1156146778Ssam            break;
115717680Spst	}
115817680Spst
115917680Spst	default:
1160127675Sbms            if (vflag <= 1) {
1161146778Ssam		    if (pptr < snapend)
1162146778Ssam                            print_unknown_data(pptr,"\n\t  ",snapend-pptr);
1163127675Sbms            }
1164127675Sbms            return;
116517680Spst	}
1166127675Sbms
1167146778Ssam        /* now walk the options */
1168146778Ssam        while (li >= 2) {
1169146778Ssam            u_int op, opli;
1170146778Ssam            const u_int8_t *tptr;
1171146778Ssam
1172147904Ssam            TCHECK2(*pptr, 2);
1173146778Ssam            if (li < 2) {
1174146778Ssam                printf(", bad opts/li");
1175146778Ssam                return;
1176146778Ssam            }
1177146778Ssam            op = *pptr++;
1178146778Ssam            opli = *pptr++;
1179146778Ssam            li -= 2;
1180146778Ssam            if (opli > li) {
1181146778Ssam                printf(", opt (%d) too long", op);
1182146778Ssam                return;
1183146778Ssam            }
1184146778Ssam            li -= opli;
1185146778Ssam            tptr = pptr;
1186146778Ssam
1187146778Ssam            printf("\n\t  %s Option #%u, length %u, value: ",
1188146778Ssam                   tok2str(esis_option_values,"Unknown",op),
1189146778Ssam                   op,
1190146778Ssam                   opli);
119117680Spst
1192146778Ssam            switch (op) {
1193127675Sbms
1194146778Ssam            case ESIS_OPTION_ES_CONF_TIME:
1195147904Ssam                TCHECK2(*pptr, 2);
1196146778Ssam                printf("%us", EXTRACT_16BITS(tptr));
1197146778Ssam                break;
1198127675Sbms
1199146778Ssam            case ESIS_OPTION_PROTOCOLS:
1200146778Ssam                while (opli>0) {
1201147904Ssam                    TCHECK(*pptr);
1202146778Ssam                    printf("%s (0x%02x)",
1203146778Ssam                           tok2str(nlpid_values,
1204146778Ssam                                   "unknown",
1205146778Ssam                                   *tptr),
1206146778Ssam                           *tptr);
1207146778Ssam                    if (opli>1) /* further NPLIDs ? - put comma */
1208146778Ssam                        printf(", ");
1209146778Ssam                    tptr++;
1210146778Ssam                    opli--;
1211146778Ssam                }
1212146778Ssam                break;
1213127675Sbms
1214146778Ssam                /*
1215146778Ssam                 * FIXME those are the defined Options that lack a decoder
1216146778Ssam                 * you are welcome to contribute code ;-)
1217146778Ssam                 */
1218127675Sbms
1219146778Ssam            case ESIS_OPTION_QOS_MAINTENANCE:
1220146778Ssam            case ESIS_OPTION_SECURITY:
1221146778Ssam            case ESIS_OPTION_PRIORITY:
1222146778Ssam            case ESIS_OPTION_ADDRESS_MASK:
1223146778Ssam            case ESIS_OPTION_SNPA_MASK:
122417680Spst
1225146778Ssam            default:
1226146778Ssam                print_unknown_data(tptr,"\n\t  ",opli);
1227146778Ssam                break;
1228146778Ssam            }
1229146778Ssam            if (vflag > 1)
1230146778Ssam                print_unknown_data(pptr,"\n\t  ",opli);
1231146778Ssam            pptr += opli;
1232146778Ssam        }
1233147904Ssamtrunc:
1234147904Ssam	return;
1235146778Ssam}
1236146778Ssam
1237127675Sbms/* shared routine for printing system, node and lsp-ids */
1238127675Sbmsstatic char *
1239127675Sbmsisis_print_id(const u_int8_t *cp, int id_len)
124098527Sfenner{
1241127675Sbms    int i;
1242127675Sbms    static char id[sizeof("xxxx.xxxx.xxxx.yy-zz")];
1243127675Sbms    char *pos = id;
124417688Spst
1245127675Sbms    for (i = 1; i <= SYSTEM_ID_LEN; i++) {
1246127675Sbms        snprintf(pos, sizeof(id) - (pos - id), "%02x", *cp++);
1247127675Sbms	pos += strlen(pos);
1248127675Sbms	if (i == 2 || i == 4)
1249127675Sbms	    *pos++ = '.';
125098527Sfenner	}
1251127675Sbms    if (id_len >= NODE_ID_LEN) {
1252127675Sbms        snprintf(pos, sizeof(id) - (pos - id), ".%02x", *cp++);
1253127675Sbms	pos += strlen(pos);
1254127675Sbms    }
1255127675Sbms    if (id_len == LSP_ID_LEN)
1256127675Sbms        snprintf(pos, sizeof(id) - (pos - id), "-%02x", *cp);
1257127675Sbms    return (id);
125898527Sfenner}
125998527Sfenner
1260127675Sbms/* print the 4-byte metric block which is common found in the old-style TLVs */
126198527Sfennerstatic int
1262127675Sbmsisis_print_metric_block (const struct isis_metric_block *isis_metric_block)
126398527Sfenner{
1264127675Sbms    printf(", Default Metric: %d, %s",
1265127675Sbms           ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_default),
1266127675Sbms           ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_default) ? "External" : "Internal");
1267127675Sbms    if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_delay))
1268127675Sbms        printf("\n\t\t  Delay Metric: %d, %s",
1269127675Sbms               ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_delay),
1270127675Sbms               ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_delay) ? "External" : "Internal");
1271127675Sbms    if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_expense))
1272127675Sbms        printf("\n\t\t  Expense Metric: %d, %s",
1273127675Sbms               ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_expense),
1274127675Sbms               ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_expense) ? "External" : "Internal");
1275127675Sbms    if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_error))
1276127675Sbms        printf("\n\t\t  Error Metric: %d, %s",
1277127675Sbms               ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_error),
1278127675Sbms               ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_error) ? "External" : "Internal");
127998527Sfenner
1280127675Sbms    return(1); /* everything is ok */
128198527Sfenner}
128298527Sfenner
128398527Sfennerstatic int
1284127675Sbmsisis_print_tlv_ip_reach (const u_int8_t *cp, const char *ident, int length)
128598527Sfenner{
1286127675Sbms	int prefix_len;
1287127675Sbms	const struct isis_tlv_ip_reach *tlv_ip_reach;
128898527Sfenner
1289127675Sbms	tlv_ip_reach = (const struct isis_tlv_ip_reach *)cp;
1290127675Sbms
1291127675Sbms	while (length > 0) {
1292127675Sbms		if ((size_t)length < sizeof(*tlv_ip_reach)) {
1293127675Sbms			printf("short IPv4 Reachability (%d vs %lu)",
1294127675Sbms                               length,
1295127675Sbms                               (unsigned long)sizeof(*tlv_ip_reach));
129698527Sfenner			return (0);
129798527Sfenner		}
1298127675Sbms
1299127675Sbms		if (!TTEST(*tlv_ip_reach))
1300127675Sbms		    return (0);
1301127675Sbms
1302127675Sbms		prefix_len = mask2plen(EXTRACT_32BITS(tlv_ip_reach->mask));
1303127675Sbms
1304127675Sbms		if (prefix_len == -1)
1305127675Sbms			printf("%sIPv4 prefix: %s mask %s",
1306127675Sbms                               ident,
1307127675Sbms			       ipaddr_string((tlv_ip_reach->prefix)),
1308127675Sbms			       ipaddr_string((tlv_ip_reach->mask)));
1309127675Sbms		else
1310127675Sbms			printf("%sIPv4 prefix: %15s/%u",
1311127675Sbms                               ident,
1312127675Sbms			       ipaddr_string((tlv_ip_reach->prefix)),
1313127675Sbms			       prefix_len);
1314127675Sbms
1315127675Sbms		printf(", Distribution: %s, Metric: %u, %s",
1316127675Sbms                       ISIS_LSP_TLV_METRIC_UPDOWN(tlv_ip_reach->isis_metric_block.metric_default) ? "down" : "up",
1317127675Sbms                       ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_default),
1318127675Sbms                       ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_default) ? "External" : "Internal");
1319127675Sbms
1320127675Sbms		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_delay))
1321127675Sbms                    printf("%s  Delay Metric: %u, %s",
1322127675Sbms                           ident,
1323127675Sbms                           ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_delay),
1324127675Sbms                           ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_delay) ? "External" : "Internal");
1325127675Sbms
1326127675Sbms		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_expense))
1327127675Sbms                    printf("%s  Expense Metric: %u, %s",
1328127675Sbms                           ident,
1329127675Sbms                           ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_expense),
1330127675Sbms                           ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_expense) ? "External" : "Internal");
1331127675Sbms
1332127675Sbms		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_error))
1333127675Sbms                    printf("%s  Error Metric: %u, %s",
1334127675Sbms                           ident,
1335127675Sbms                           ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_error),
1336127675Sbms                           ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_error) ? "External" : "Internal");
1337127675Sbms
1338127675Sbms		length -= sizeof(struct isis_tlv_ip_reach);
1339127675Sbms		tlv_ip_reach++;
134098527Sfenner	}
134198527Sfenner	return (1);
134298527Sfenner}
134398527Sfenner
1344127675Sbms/*
1345127675Sbms * this is the common IP-REACH subTLV decoder it is called
1346127675Sbms * from various EXTD-IP REACH TLVs (135,235,236,237)
1347127675Sbms */
134898527Sfenner
1349127675Sbmsstatic int
1350127675Sbmsisis_print_ip_reach_subtlv (const u_int8_t *tptr,int subt,int subl,const char *ident) {
1351127675Sbms
1352127675Sbms        /* first lets see if we know the subTLVs name*/
1353127675Sbms	printf("%s%s subTLV #%u, length: %u",
1354127675Sbms	       ident,
1355127675Sbms               tok2str(isis_ext_ip_reach_subtlv_values,
1356127675Sbms                       "unknown",
1357127675Sbms                       subt),
1358127675Sbms               subt,
1359127675Sbms               subl);
1360127675Sbms
1361127675Sbms	if (!TTEST2(*tptr,subl))
1362127675Sbms	    goto trunctlv;
1363127675Sbms
1364127675Sbms    switch(subt) {
1365146778Ssam    case ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR: /* fall through */
1366146778Ssam    case ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32:
1367127675Sbms        while (subl >= 4) {
1368127675Sbms	    printf(", 0x%08x (=%u)",
1369127675Sbms		   EXTRACT_32BITS(tptr),
1370127675Sbms		   EXTRACT_32BITS(tptr));
1371127675Sbms	    tptr+=4;
1372127675Sbms	    subl-=4;
137317688Spst	}
1374127675Sbms	break;
1375146778Ssam    case ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64:
1376127675Sbms        while (subl >= 8) {
1377127675Sbms	    printf(", 0x%08x%08x",
1378127675Sbms		   EXTRACT_32BITS(tptr),
1379127675Sbms		   EXTRACT_32BITS(tptr+4));
1380127675Sbms	    tptr+=8;
1381127675Sbms	    subl-=8;
1382127675Sbms	}
1383127675Sbms	break;
1384127675Sbms    default:
1385127675Sbms	if(!print_unknown_data(tptr,"\n\t\t    ",
1386127675Sbms			       subl))
1387127675Sbms	  return(0);
1388127675Sbms	break;
1389127675Sbms    }
1390127675Sbms    return(1);
1391127675Sbms
1392127675Sbmstrunctlv:
1393127675Sbms    printf("%spacket exceeded snapshot",ident);
1394127675Sbms    return(0);
139598527Sfenner}
139617688Spst
1397127675Sbms/*
1398127675Sbms * this is the common IS-REACH subTLV decoder it is called
1399127675Sbms * from isis_print_ext_is_reach()
1400127675Sbms */
1401127675Sbms
140298527Sfennerstatic int
1403127675Sbmsisis_print_is_reach_subtlv (const u_int8_t *tptr,int subt,int subl,const char *ident) {
140498527Sfenner
1405146778Ssam        int priority_level,bandwidth_constraint;
1406127675Sbms        union { /* int to float conversion buffer for several subTLVs */
1407127675Sbms            float f;
1408127675Sbms            u_int32_t i;
1409127675Sbms        } bw;
141098527Sfenner
1411127675Sbms        /* first lets see if we know the subTLVs name*/
1412127675Sbms	printf("%s%s subTLV #%u, length: %u",
1413127675Sbms	       ident,
1414127675Sbms               tok2str(isis_ext_is_reach_subtlv_values,
1415127675Sbms                       "unknown",
1416127675Sbms                       subt),
1417127675Sbms               subt,
1418127675Sbms               subl);
141998527Sfenner
1420127675Sbms	if (!TTEST2(*tptr,subl))
1421127675Sbms	    goto trunctlv;
142298527Sfenner
1423127675Sbms        switch(subt) {
1424146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP:
1425146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID:
1426146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID:
1427127675Sbms	    if (subl >= 4) {
1428127675Sbms	      printf(", 0x%08x", EXTRACT_32BITS(tptr));
1429127675Sbms	      if (subl == 8) /* draft-ietf-isis-gmpls-extensions */
1430127675Sbms	        printf(", 0x%08x", EXTRACT_32BITS(tptr+4));
1431127675Sbms	    }
1432127675Sbms	    break;
1433146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR:
1434146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR:
1435127675Sbms            if (subl >= 4)
1436127675Sbms              printf(", %s", ipaddr_string(tptr));
1437127675Sbms            break;
1438146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW :
1439146778Ssam	case ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW:
1440127675Sbms            if (subl >= 4) {
1441127675Sbms              bw.i = EXTRACT_32BITS(tptr);
1442127675Sbms              printf(", %.3f Mbps", bw.f*8/1000000 );
1443127675Sbms            }
1444127675Sbms            break;
1445146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW :
1446127675Sbms            if (subl >= 32) {
1447127675Sbms              for (priority_level = 0; priority_level < 8; priority_level++) {
1448127675Sbms                bw.i = EXTRACT_32BITS(tptr);
1449127675Sbms                printf("%s  priority level %d: %.3f Mbps",
1450127675Sbms                       ident,
1451127675Sbms                       priority_level,
1452127675Sbms                       bw.f*8/1000000 );
1453127675Sbms		tptr+=4;
1454127675Sbms	      }
1455127675Sbms            }
1456127675Sbms            break;
1457146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_DIFFSERV_TE:
1458146778Ssam            printf("%sBandwidth Constraints Model ID: %s (%u)",
1459146778Ssam                   ident,
1460146778Ssam                   tok2str(diffserv_te_bc_values, "unknown", *tptr),
1461146778Ssam                   *tptr);
1462146778Ssam            tptr++;
1463146778Ssam            /* decode BCs until the subTLV ends */
1464146778Ssam            for (bandwidth_constraint = 0; bandwidth_constraint < (subl-1)/4; bandwidth_constraint++) {
1465146778Ssam                bw.i = EXTRACT_32BITS(tptr);
1466146778Ssam                printf("%s  Bandwidth constraint %d: %.3f Mbps",
1467146778Ssam                       ident,
1468146778Ssam                       bandwidth_constraint,
1469146778Ssam                       bw.f*8/1000000 );
1470146778Ssam		tptr+=4;
1471146778Ssam            }
1472146778Ssam            break;
1473146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC:
1474127675Sbms            if (subl >= 3)
1475127675Sbms              printf(", %u", EXTRACT_24BITS(tptr));
1476127675Sbms            break;
1477146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE:
1478127675Sbms            if (subl >= 2) {
1479127675Sbms              printf(", %s, Priority %u",
1480127675Sbms		   bittok2str(gmpls_link_prot_values, "none", *tptr),
1481127675Sbms                   *(tptr+1));
1482127675Sbms            }
1483127675Sbms            break;
1484146778Ssam        case ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR:
1485127675Sbms            if (subl >= 36) {
1486127675Sbms              printf("%s  Interface Switching Capability:%s",
1487127675Sbms                   ident,
1488127675Sbms                   tok2str(gmpls_switch_cap_values, "Unknown", *(tptr)));
1489127675Sbms              printf(", LSP Encoding: %s",
1490127675Sbms                   tok2str(gmpls_encoding_values, "Unknown", *(tptr+1)));
1491127675Sbms	      tptr+=4;
1492127675Sbms              printf("%s  Max LSP Bandwidth:",ident);
1493127675Sbms              for (priority_level = 0; priority_level < 8; priority_level++) {
1494127675Sbms                bw.i = EXTRACT_32BITS(tptr);
1495127675Sbms                printf("%s    priority level %d: %.3f Mbps",
1496127675Sbms                       ident,
1497127675Sbms                       priority_level,
1498127675Sbms                       bw.f*8/1000000 );
1499127675Sbms		tptr+=4;
1500127675Sbms              }
1501127675Sbms              subl-=36;
1502127675Sbms              /* there is some optional stuff left to decode but this is as of yet
1503127675Sbms                 not specified so just lets hexdump what is left */
1504127675Sbms              if(subl>0){
1505127675Sbms                if(!print_unknown_data(tptr,"\n\t\t    ",
1506147904Ssam				       subl))
1507127675Sbms                    return(0);
1508127675Sbms              }
1509127675Sbms            }
1510127675Sbms            break;
1511127675Sbms        default:
1512127675Sbms            if(!print_unknown_data(tptr,"\n\t\t    ",
1513127675Sbms				   subl))
1514127675Sbms                return(0);
1515127675Sbms            break;
1516127675Sbms        }
1517127675Sbms        return(1);
151898527Sfenner
1519127675Sbmstrunctlv:
1520127675Sbms    printf("%spacket exceeded snapshot",ident);
1521127675Sbms    return(0);
1522127675Sbms}
152398527Sfenner
152498527Sfenner
1525127675Sbms/*
1526127675Sbms * this is the common IS-REACH decoder it is called
1527127675Sbms * from various EXTD-IS REACH style TLVs (22,24,222)
1528127675Sbms */
152998527Sfenner
1530127675Sbmsstatic int
1531127675Sbmsisis_print_ext_is_reach (const u_int8_t *tptr,const char *ident, int tlv_type) {
153298527Sfenner
1533127675Sbms    char ident_buffer[20];
1534127675Sbms    int subtlv_type,subtlv_len,subtlv_sum_len;
1535127675Sbms    int proc_bytes = 0; /* how many bytes did we process ? */
1536127675Sbms
1537127675Sbms    if (!TTEST2(*tptr, NODE_ID_LEN))
1538127675Sbms        return(0);
153998527Sfenner
1540127675Sbms    printf("%sIS Neighbor: %s", ident, isis_print_id(tptr, NODE_ID_LEN));
1541127675Sbms    tptr+=(NODE_ID_LEN);
154298527Sfenner
1543146778Ssam    if (tlv_type != ISIS_TLV_IS_ALIAS_ID) { /* the Alias TLV Metric field is implicit 0 */
1544127675Sbms        if (!TTEST2(*tptr, 3))    /* and is therefore skipped */
1545127675Sbms	    return(0);
1546127675Sbms	printf(", Metric: %d",EXTRACT_24BITS(tptr));
1547127675Sbms	tptr+=3;
1548127675Sbms    }
1549127675Sbms
1550127675Sbms    if (!TTEST2(*tptr, 1))
1551127675Sbms        return(0);
1552127675Sbms    subtlv_sum_len=*(tptr++); /* read out subTLV length */
1553127675Sbms    proc_bytes=NODE_ID_LEN+3+1;
1554127675Sbms    printf(", %ssub-TLVs present",subtlv_sum_len ? "" : "no ");
1555127675Sbms    if (subtlv_sum_len) {
1556127675Sbms        printf(" (%u)",subtlv_sum_len);
1557127675Sbms        while (subtlv_sum_len>0) {
1558127675Sbms            if (!TTEST2(*tptr,2))
1559127675Sbms                return(0);
1560127675Sbms            subtlv_type=*(tptr++);
1561127675Sbms            subtlv_len=*(tptr++);
1562127675Sbms            /* prepend the ident string */
1563127675Sbms            snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
1564127675Sbms            if(!isis_print_is_reach_subtlv(tptr,subtlv_type,subtlv_len,ident_buffer))
1565127675Sbms                return(0);
1566127675Sbms            tptr+=subtlv_len;
1567127675Sbms            subtlv_sum_len-=(subtlv_len+2);
1568127675Sbms            proc_bytes+=(subtlv_len+2);
1569127675Sbms        }
1570127675Sbms    }
1571127675Sbms    return(proc_bytes);
157217688Spst}
157317688Spst
157417688Spst/*
1575127675Sbms * this is the common Multi Topology ID decoder
1576127675Sbms * it is called from various MT-TLVs (222,229,235,237)
1577127675Sbms */
1578127675Sbms
1579127675Sbmsstatic int
1580127675Sbmsisis_print_mtid (const u_int8_t *tptr,const char *ident) {
1581127675Sbms
1582127675Sbms    if (!TTEST2(*tptr, 2))
1583127675Sbms        return(0);
1584127675Sbms
1585127675Sbms    printf("%s%s",
1586127675Sbms           ident,
1587127675Sbms           tok2str(isis_mt_values,
1588127675Sbms                   "Reserved for IETF Consensus",
1589127675Sbms                   ISIS_MASK_MTID(EXTRACT_16BITS(tptr))));
1590127675Sbms
1591127675Sbms    printf(" Topology (0x%03x), Flags: [%s]",
1592127675Sbms           ISIS_MASK_MTID(EXTRACT_16BITS(tptr)),
1593127675Sbms           bittok2str(isis_mt_flag_values, "none",ISIS_MASK_MTFLAGS(EXTRACT_16BITS(tptr))));
1594127675Sbms
1595127675Sbms    return(2);
1596127675Sbms}
1597127675Sbms
1598127675Sbms/*
1599127675Sbms * this is the common extended IP reach decoder
1600127675Sbms * it is called from TLVs (135,235,236,237)
1601127675Sbms * we process the TLV and optional subTLVs and return
1602127675Sbms * the amount of processed bytes
1603127675Sbms */
1604127675Sbms
1605127675Sbmsstatic int
1606127675Sbmsisis_print_extd_ip_reach (const u_int8_t *tptr, const char *ident, u_int16_t afi) {
1607127675Sbms
1608127675Sbms    char ident_buffer[20];
1609127675Sbms    u_int8_t prefix[16]; /* shared copy buffer for IPv4 and IPv6 prefixes */
1610127675Sbms    u_int metric, status_byte, bit_length, byte_length, sublen, processed, subtlvtype, subtlvlen;
1611127675Sbms
1612127675Sbms    if (!TTEST2(*tptr, 4))
1613127675Sbms        return (0);
1614127675Sbms    metric = EXTRACT_32BITS(tptr);
1615127675Sbms    processed=4;
1616127675Sbms    tptr+=4;
1617127675Sbms
1618127675Sbms    if (afi == IPV4) {
1619127675Sbms        if (!TTEST2(*tptr, 1)) /* fetch status byte */
1620127675Sbms            return (0);
1621127675Sbms        status_byte=*(tptr++);
1622127675Sbms        bit_length = status_byte&0x3f;
1623127675Sbms        processed++;
1624127675Sbms#ifdef INET6
1625127675Sbms    } else if (afi == IPV6) {
1626127675Sbms        if (!TTEST2(*tptr, 1)) /* fetch status & prefix_len byte */
1627127675Sbms            return (0);
1628127675Sbms        status_byte=*(tptr++);
1629127675Sbms        bit_length=*(tptr++);
1630127675Sbms        processed+=2;
1631127675Sbms#endif
1632127675Sbms    } else
1633127675Sbms        return (0); /* somebody is fooling us */
1634127675Sbms
1635127675Sbms    byte_length = (bit_length + 7) / 8; /* prefix has variable length encoding */
1636127675Sbms
1637127675Sbms    if (!TTEST2(*tptr, byte_length))
1638127675Sbms        return (0);
1639127675Sbms    memset(prefix, 0, 16);              /* clear the copy buffer */
1640127675Sbms    memcpy(prefix,tptr,byte_length);    /* copy as much as is stored in the TLV */
1641127675Sbms    tptr+=byte_length;
1642127675Sbms    processed+=byte_length;
1643127675Sbms
1644127675Sbms    if (afi == IPV4)
1645127675Sbms        printf("%sIPv4 prefix: %15s/%u",
1646127675Sbms               ident,
1647127675Sbms               ipaddr_string(prefix),
1648127675Sbms               bit_length);
1649127675Sbms#ifdef INET6
1650127675Sbms    if (afi == IPV6)
1651127675Sbms        printf("%sIPv6 prefix: %s/%u",
1652127675Sbms               ident,
1653127675Sbms               ip6addr_string(prefix),
1654127675Sbms               bit_length);
1655127675Sbms#endif
1656127675Sbms
1657127675Sbms    printf(", Distribution: %s, Metric: %u",
1658127675Sbms           ISIS_MASK_TLV_EXTD_IP_UPDOWN(status_byte) ? "down" : "up",
1659127675Sbms           metric);
1660127675Sbms
1661127675Sbms    if (afi == IPV4 && ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte))
1662127675Sbms        printf(", sub-TLVs present");
1663127675Sbms#ifdef INET6
1664127675Sbms    if (afi == IPV6)
1665127675Sbms        printf(", %s%s",
1666127675Sbms               ISIS_MASK_TLV_EXTD_IP6_IE(status_byte) ? "External" : "Internal",
1667127675Sbms               ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte) ? ", sub-TLVs present" : "");
1668127675Sbms#endif
1669127675Sbms
1670127675Sbms    if ((ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte)  && afi == IPV4) ||
1671127675Sbms        (ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte) && afi == IPV6)) {
1672127675Sbms        /* assume that one prefix can hold more
1673127675Sbms           than one subTLV - therefore the first byte must reflect
1674127675Sbms           the aggregate bytecount of the subTLVs for this prefix
1675127675Sbms        */
1676127675Sbms        if (!TTEST2(*tptr, 1))
1677127675Sbms            return (0);
1678127675Sbms        sublen=*(tptr++);
1679127675Sbms        processed+=sublen+1;
1680127675Sbms        printf(" (%u)",sublen);   /* print out subTLV length */
1681127675Sbms
1682127675Sbms        while (sublen>0) {
1683127675Sbms            if (!TTEST2(*tptr,2))
1684127675Sbms                return (0);
1685127675Sbms            subtlvtype=*(tptr++);
1686127675Sbms            subtlvlen=*(tptr++);
1687127675Sbms            /* prepend the ident string */
1688127675Sbms            snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
1689127675Sbms            if(!isis_print_ip_reach_subtlv(tptr,subtlvtype,subtlvlen,ident_buffer))
1690127675Sbms                return(0);
1691127675Sbms            tptr+=subtlvlen;
1692127675Sbms            sublen-=(subtlvlen+2);
1693127675Sbms        }
1694127675Sbms    }
1695127675Sbms    return (processed);
1696127675Sbms}
1697127675Sbms
1698127675Sbms/*
169917688Spst * isis_print
170017688Spst * Decode IS-IS packets.  Return 0 on error.
170117688Spst */
170217688Spst
1703127675Sbmsstatic int isis_print (const u_int8_t *p, u_int length)
170417688Spst{
1705146778Ssam    const struct isis_common_header *isis_header;
170617688Spst
170798527Sfenner    const struct isis_iih_lan_header *header_iih_lan;
170898527Sfenner    const struct isis_iih_ptp_header *header_iih_ptp;
170998527Sfenner    const struct isis_lsp_header *header_lsp;
171098527Sfenner    const struct isis_csnp_header *header_csnp;
171198527Sfenner    const struct isis_psnp_header *header_psnp;
171217688Spst
171398527Sfenner    const struct isis_tlv_lsp *tlv_lsp;
171498527Sfenner    const struct isis_tlv_ptp_adj *tlv_ptp_adj;
171598527Sfenner    const struct isis_tlv_is_reach *tlv_is_reach;
1716127675Sbms    const struct isis_tlv_es_reach *tlv_es_reach;
171798527Sfenner
1718127675Sbms    u_int8_t pdu_type, max_area, id_length, tlv_type, tlv_len, tmp, alen, lan_alen, prefix_len;
1719127675Sbms    u_int8_t ext_is_len, ext_ip_len, mt_len;
1720127675Sbms    const u_int8_t *optr, *pptr, *tptr;
172198527Sfenner    u_short packet_len,pdu_len;
1722146778Ssam    u_int i,vendor_id;
172398527Sfenner
172498527Sfenner    packet_len=length;
1725127675Sbms    optr = p; /* initialize the _o_riginal pointer to the packet start -
1726127675Sbms                 need it for parsing the checksum TLV */
1727146778Ssam    isis_header = (const struct isis_common_header *)p;
1728146778Ssam    TCHECK(*isis_header);
1729127675Sbms    pptr = p+(ISIS_COMMON_HEADER_SIZE);
173098527Sfenner    header_iih_lan = (const struct isis_iih_lan_header *)pptr;
173198527Sfenner    header_iih_ptp = (const struct isis_iih_ptp_header *)pptr;
173298527Sfenner    header_lsp = (const struct isis_lsp_header *)pptr;
173398527Sfenner    header_csnp = (const struct isis_csnp_header *)pptr;
173498527Sfenner    header_psnp = (const struct isis_psnp_header *)pptr;
1735127675Sbms
1736146778Ssam    if (!eflag)
1737146778Ssam        printf("IS-IS");
1738146778Ssam
173917688Spst    /*
174017688Spst     * Sanity checking of the header.
174117688Spst     */
174217688Spst
1743146778Ssam    if (isis_header->version != ISIS_VERSION) {
1744146778Ssam	printf("version %d packet not supported", isis_header->version);
174598527Sfenner	return (0);
174617688Spst    }
174717688Spst
1748146778Ssam    if ((isis_header->id_length != SYSTEM_ID_LEN) && (isis_header->id_length != 0)) {
1749146778Ssam	printf("system ID length of %d is not supported",
1750146778Ssam	       isis_header->id_length);
175198527Sfenner	return (0);
175217688Spst    }
1753127675Sbms
1754146778Ssam    if (isis_header->pdu_version != ISIS_VERSION) {
1755146778Ssam	printf("version %d packet not supported", isis_header->pdu_version);
175698527Sfenner	return (0);
175717688Spst    }
175817688Spst
1759146778Ssam    max_area = isis_header->max_area;
176017688Spst    switch(max_area) {
176117688Spst    case 0:
1762127675Sbms	max_area = 3;	 /* silly shit */
176317688Spst	break;
176417688Spst    case 255:
1765146778Ssam	printf("bad packet -- 255 areas");
176698527Sfenner	return (0);
176717688Spst    default:
176817688Spst	break;
176917688Spst    }
177017688Spst
1771146778Ssam    id_length = isis_header->id_length;
1772127675Sbms    switch(id_length) {
1773127675Sbms    case 0:
1774127675Sbms        id_length = 6;	 /* silly shit again */
1775127675Sbms	break;
1776127675Sbms    case 1:              /* 1-8 are valid sys-ID lenghts */
1777127675Sbms    case 2:
1778127675Sbms    case 3:
1779127675Sbms    case 4:
1780127675Sbms    case 5:
1781127675Sbms    case 6:
1782127675Sbms    case 7:
1783127675Sbms    case 8:
1784127675Sbms        break;
1785127675Sbms    case 255:
1786127675Sbms        id_length = 0;   /* entirely useless */
1787127675Sbms	break;
1788127675Sbms    default:
1789127675Sbms        break;
1790127675Sbms    }
1791127675Sbms
1792127675Sbms    /* toss any non 6-byte sys-ID len PDUs */
1793127675Sbms    if (id_length != 6 ) {
1794146778Ssam	printf("bad packet -- illegal sys-ID length (%u)", id_length);
1795127675Sbms	return (0);
1796127675Sbms    }
1797127675Sbms
1798146778Ssam    pdu_type=isis_header->pdu_type;
1799127675Sbms
1800127675Sbms    /* in non-verbose mode print the basic PDU Type plus PDU specific brief information*/
1801127675Sbms    if (vflag < 1) {
1802146778Ssam        printf("%s%s",
1803146778Ssam               eflag ? "" : ", ",
1804127675Sbms               tok2str(isis_pdu_values,"unknown PDU-Type %u",pdu_type));
1805127675Sbms
1806127675Sbms	switch (pdu_type) {
1807127675Sbms
1808146778Ssam	case ISIS_PDU_L1_LAN_IIH:
1809146778Ssam	case ISIS_PDU_L2_LAN_IIH:
1810127675Sbms	    printf(", src-id %s",
1811127675Sbms                   isis_print_id(header_iih_lan->source_id,SYSTEM_ID_LEN));
1812127675Sbms	    printf(", lan-id %s, prio %u",
1813127675Sbms                   isis_print_id(header_iih_lan->lan_id,NODE_ID_LEN),
1814127675Sbms                   header_iih_lan->priority);
1815127675Sbms	    break;
1816146778Ssam	case ISIS_PDU_PTP_IIH:
1817127675Sbms	    printf(", src-id %s", isis_print_id(header_iih_ptp->source_id,SYSTEM_ID_LEN));
1818127675Sbms	    break;
1819146778Ssam	case ISIS_PDU_L1_LSP:
1820146778Ssam	case ISIS_PDU_L2_LSP:
1821127675Sbms	    printf(", lsp-id %s, seq 0x%08x, lifetime %5us",
1822127675Sbms		   isis_print_id(header_lsp->lsp_id, LSP_ID_LEN),
1823127675Sbms		   EXTRACT_32BITS(header_lsp->sequence_number),
1824127675Sbms		   EXTRACT_16BITS(header_lsp->remaining_lifetime));
1825127675Sbms	    break;
1826146778Ssam	case ISIS_PDU_L1_CSNP:
1827146778Ssam	case ISIS_PDU_L2_CSNP:
1828146778Ssam	    printf(", src-id %s", isis_print_id(header_csnp->source_id,NODE_ID_LEN));
1829127675Sbms	    break;
1830146778Ssam	case ISIS_PDU_L1_PSNP:
1831146778Ssam	case ISIS_PDU_L2_PSNP:
1832146778Ssam	    printf(", src-id %s", isis_print_id(header_psnp->source_id,NODE_ID_LEN));
1833127675Sbms	    break;
1834127675Sbms
1835127675Sbms	}
1836127675Sbms	printf(", length %u", length);
1837127675Sbms
1838127675Sbms        return(1);
1839127675Sbms    }
1840127675Sbms
1841127675Sbms    /* ok they seem to want to know everything - lets fully decode it */
1842146778Ssam    printf("%slength %u", eflag ? "" : ", ",length);
1843127675Sbms
1844127675Sbms    printf("\n\t%s, hlen: %u, v: %u, pdu-v: %u, sys-id-len: %u (%u), max-area: %u (%u)",
1845127675Sbms           tok2str(isis_pdu_values,
1846127675Sbms                   "unknown, type %u",
1847127675Sbms                   pdu_type),
1848146778Ssam           isis_header->fixed_len,
1849146778Ssam           isis_header->version,
1850146778Ssam           isis_header->pdu_version,
1851127675Sbms	   id_length,
1852146778Ssam	   isis_header->id_length,
185398527Sfenner           max_area,
1854146778Ssam           isis_header->max_area);
1855127675Sbms
1856127675Sbms    if (vflag > 1) {
1857127675Sbms        if(!print_unknown_data(optr,"\n\t",8)) /* provide the _o_riginal pointer */
1858127675Sbms            return(0);                         /* for optionally debugging the common header */
1859127675Sbms    }
1860127675Sbms
186198527Sfenner    switch (pdu_type) {
186298527Sfenner
1863146778Ssam    case ISIS_PDU_L1_LAN_IIH:
1864146778Ssam    case ISIS_PDU_L2_LAN_IIH:
1865146778Ssam	if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE)) {
186698527Sfenner	    printf(", bogus fixed header length %u should be %lu",
1867146778Ssam		   isis_header->fixed_len, (unsigned long)ISIS_IIH_LAN_HEADER_SIZE);
186898527Sfenner	    return (0);
186917688Spst	}
187098527Sfenner
187198527Sfenner	pdu_len=EXTRACT_16BITS(header_iih_lan->pdu_len);
187298527Sfenner	if (packet_len>pdu_len) {
1873127675Sbms            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1874127675Sbms            length=pdu_len;
187598527Sfenner	}
187698527Sfenner
187798527Sfenner	TCHECK(*header_iih_lan);
1878127675Sbms	printf("\n\t  source-id: %s,  holding time: %us, Flags: [%s]",
1879127675Sbms               isis_print_id(header_iih_lan->source_id,SYSTEM_ID_LEN),
1880127675Sbms               EXTRACT_16BITS(header_iih_lan->holding_time),
1881127675Sbms               tok2str(isis_iih_circuit_type_values,
1882127675Sbms                       "unknown circuit type 0x%02x",
1883127675Sbms                       header_iih_lan->circuit_type));
188498527Sfenner
1885127675Sbms	printf("\n\t  lan-id:    %s, Priority: %u, PDU length: %u",
1886127675Sbms               isis_print_id(header_iih_lan->lan_id, NODE_ID_LEN),
1887146778Ssam               (header_iih_lan->priority) & ISIS_LAN_PRIORITY_MASK,
1888127675Sbms               pdu_len);
188998527Sfenner
1890127675Sbms        if (vflag > 1) {
1891127675Sbms            if(!print_unknown_data(pptr,"\n\t  ",ISIS_IIH_LAN_HEADER_SIZE))
1892127675Sbms                return(0);
1893127675Sbms        }
189498527Sfenner
189598527Sfenner	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
189698527Sfenner	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
189717688Spst	break;
189898527Sfenner
1899146778Ssam    case ISIS_PDU_PTP_IIH:
1900146778Ssam	if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE)) {
190198527Sfenner	    printf(", bogus fixed header length %u should be %lu",
1902146778Ssam		   isis_header->fixed_len, (unsigned long)ISIS_IIH_PTP_HEADER_SIZE);
190398527Sfenner	    return (0);
190417688Spst	}
1905127675Sbms
190698527Sfenner	pdu_len=EXTRACT_16BITS(header_iih_ptp->pdu_len);
190798527Sfenner	if (packet_len>pdu_len) {
1908127675Sbms            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1909127675Sbms            length=pdu_len;
191098527Sfenner	}
1911127675Sbms
191298527Sfenner	TCHECK(*header_iih_ptp);
1913127675Sbms	printf("\n\t  source-id: %s, holding time: %us, Flags: [%s]",
1914127675Sbms               isis_print_id(header_iih_ptp->source_id,SYSTEM_ID_LEN),
1915127675Sbms               EXTRACT_16BITS(header_iih_ptp->holding_time),
1916127675Sbms               tok2str(isis_iih_circuit_type_values,
1917127675Sbms                       "unknown circuit type 0x%02x",
1918127675Sbms                       header_iih_ptp->circuit_type));
191998527Sfenner
1920127675Sbms	printf("\n\t  circuit-id: 0x%02x, PDU length: %u",
1921127675Sbms               header_iih_ptp->circuit_id,
1922127675Sbms               pdu_len);
192398527Sfenner
1924127675Sbms        if (vflag > 1) {
1925127675Sbms            if(!print_unknown_data(pptr,"\n\t  ",ISIS_IIH_PTP_HEADER_SIZE))
1926127675Sbms                return(0);
1927127675Sbms        }
192898527Sfenner
192998527Sfenner	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
193098527Sfenner	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
193117688Spst	break;
193298527Sfenner
1933146778Ssam    case ISIS_PDU_L1_LSP:
1934146778Ssam    case ISIS_PDU_L2_LSP:
1935146778Ssam	if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE)) {
193698527Sfenner	    printf(", bogus fixed header length %u should be %lu",
1937146778Ssam		   isis_header->fixed_len, (unsigned long)ISIS_LSP_HEADER_SIZE);
193898527Sfenner	    return (0);
193998527Sfenner	}
1940127675Sbms
194198527Sfenner	pdu_len=EXTRACT_16BITS(header_lsp->pdu_len);
194298527Sfenner	if (packet_len>pdu_len) {
1943127675Sbms            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1944127675Sbms            length=pdu_len;
194598527Sfenner	}
194698527Sfenner
194798527Sfenner	TCHECK(*header_lsp);
1948127675Sbms	printf("\n\t  lsp-id: %s, seq: 0x%08x, lifetime: %5us\n\t  chksum: 0x%04x",
1949127675Sbms               isis_print_id(header_lsp->lsp_id, LSP_ID_LEN),
1950127675Sbms               EXTRACT_32BITS(header_lsp->sequence_number),
1951127675Sbms               EXTRACT_16BITS(header_lsp->remaining_lifetime),
1952127675Sbms               EXTRACT_16BITS(header_lsp->checksum));
195398527Sfenner
1954127675Sbms        /* if this is a purge do not attempt to verify the checksum */
1955127675Sbms        if ( EXTRACT_16BITS(header_lsp->remaining_lifetime) == 0 &&
1956127675Sbms             EXTRACT_16BITS(header_lsp->checksum) == 0)
1957127675Sbms            printf(" (purged)");
1958127675Sbms        else
1959127675Sbms            /* verify the checksum -
1960127675Sbms             * checking starts at the lsp-id field at byte position [12]
1961127675Sbms             * hence the length needs to be reduced by 12 bytes */
1962127675Sbms            printf(" (%s)", (osi_cksum((u_int8_t *)header_lsp->lsp_id, length-12)) ? "incorrect" : "correct");
1963127675Sbms
1964127675Sbms	printf(", PDU length: %u, Flags: [ %s",
1965127675Sbms               pdu_len,
1966127675Sbms               ISIS_MASK_LSP_OL_BIT(header_lsp->typeblock) ? "Overload bit set, " : "");
1967127675Sbms
196898527Sfenner	if (ISIS_MASK_LSP_ATT_BITS(header_lsp->typeblock)) {
196998527Sfenner	    printf("%s", ISIS_MASK_LSP_ATT_DEFAULT_BIT(header_lsp->typeblock) ? "default " : "");
197098527Sfenner	    printf("%s", ISIS_MASK_LSP_ATT_DELAY_BIT(header_lsp->typeblock) ? "delay " : "");
197198527Sfenner	    printf("%s", ISIS_MASK_LSP_ATT_EXPENSE_BIT(header_lsp->typeblock) ? "expense " : "");
197298527Sfenner	    printf("%s", ISIS_MASK_LSP_ATT_ERROR_BIT(header_lsp->typeblock) ? "error " : "");
197398527Sfenner	    printf("ATT bit set, ");
197498527Sfenner	}
197598527Sfenner	printf("%s", ISIS_MASK_LSP_PARTITION_BIT(header_lsp->typeblock) ? "P bit set, " : "");
1976127675Sbms	printf("%s ]", tok2str(isis_lsp_istype_values,"Unknown(0x%x)",ISIS_MASK_LSP_ISTYPE_BITS(header_lsp->typeblock)));
197798527Sfenner
1978127675Sbms        if (vflag > 1) {
1979127675Sbms            if(!print_unknown_data(pptr,"\n\t  ",ISIS_LSP_HEADER_SIZE))
1980127675Sbms                return(0);
1981127675Sbms        }
1982127675Sbms
198398527Sfenner	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
198498527Sfenner	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
198517688Spst	break;
198698527Sfenner
1987146778Ssam    case ISIS_PDU_L1_CSNP:
1988146778Ssam    case ISIS_PDU_L2_CSNP:
1989146778Ssam	if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE)) {
199098527Sfenner	    printf(", bogus fixed header length %u should be %lu",
1991146778Ssam		   isis_header->fixed_len, (unsigned long)ISIS_CSNP_HEADER_SIZE);
199298527Sfenner	    return (0);
199398527Sfenner	}
1994127675Sbms
199598527Sfenner	pdu_len=EXTRACT_16BITS(header_csnp->pdu_len);
199698527Sfenner	if (packet_len>pdu_len) {
1997127675Sbms            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1998127675Sbms            length=pdu_len;
199998527Sfenner	}
200017688Spst
200198527Sfenner	TCHECK(*header_csnp);
2002127675Sbms	printf("\n\t  source-id:    %s, PDU length: %u",
2003127675Sbms               isis_print_id(header_csnp->source_id, NODE_ID_LEN),
2004127675Sbms               pdu_len);
2005127675Sbms	printf("\n\t  start lsp-id: %s",
2006127675Sbms               isis_print_id(header_csnp->start_lsp_id, LSP_ID_LEN));
2007127675Sbms	printf("\n\t  end lsp-id:   %s",
2008127675Sbms               isis_print_id(header_csnp->end_lsp_id, LSP_ID_LEN));
200917688Spst
2010127675Sbms        if (vflag > 1) {
2011127675Sbms            if(!print_unknown_data(pptr,"\n\t  ",ISIS_CSNP_HEADER_SIZE))
2012127675Sbms                return(0);
2013127675Sbms        }
2014127675Sbms
201598527Sfenner	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
201698527Sfenner	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
201798527Sfenner        break;
201817688Spst
2019146778Ssam    case ISIS_PDU_L1_PSNP:
2020146778Ssam    case ISIS_PDU_L2_PSNP:
2021146778Ssam	if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE)) {
202298527Sfenner	    printf("- bogus fixed header length %u should be %lu",
2023146778Ssam		   isis_header->fixed_len, (unsigned long)ISIS_PSNP_HEADER_SIZE);
202498527Sfenner	    return (0);
202598527Sfenner	}
202698527Sfenner
202798527Sfenner	pdu_len=EXTRACT_16BITS(header_psnp->pdu_len);
202898527Sfenner	if (packet_len>pdu_len) {
2029127675Sbms            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
2030127675Sbms            length=pdu_len;
203198527Sfenner	}
203298527Sfenner
203398527Sfenner	TCHECK(*header_psnp);
2034127675Sbms	printf("\n\t  source-id:    %s, PDU length: %u",
2035127675Sbms               isis_print_id(header_psnp->source_id, NODE_ID_LEN),
2036127675Sbms               pdu_len);
2037127675Sbms
2038127675Sbms        if (vflag > 1) {
2039127675Sbms            if(!print_unknown_data(pptr,"\n\t  ",ISIS_PSNP_HEADER_SIZE))
2040127675Sbms                return(0);
2041127675Sbms        }
2042127675Sbms
204398527Sfenner	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
204498527Sfenner	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
204517688Spst	break;
204617688Spst
204798527Sfenner    default:
2048127675Sbms	if(!print_unknown_data(pptr,"\n\t  ",length))
2049127675Sbms	    return(0);
2050127675Sbms	return (0);
205117688Spst    }
205217688Spst
205317688Spst    /*
205417688Spst     * Now print the TLV's.
205517688Spst     */
2056127675Sbms
205717688Spst    while (packet_len >= 2) {
205898527Sfenner        if (pptr == snapend) {
205998527Sfenner	    return (1);
206098527Sfenner        }
206198527Sfenner
206298527Sfenner	if (!TTEST2(*pptr, 2)) {
2063127675Sbms	    printf("\n\t\t packet exceeded snapshot (%ld) bytes",
2064127675Sbms                   (long)(pptr-snapend));
206598527Sfenner	    return (1);
206617688Spst	}
2067127675Sbms	tlv_type = *pptr++;
2068127675Sbms	tlv_len = *pptr++;
2069127675Sbms        tmp =tlv_len; /* copy temporary len & pointer to packet data */
2070127675Sbms        tptr = pptr;
207117688Spst	packet_len -= 2;
2072127675Sbms	if (tlv_len > packet_len) {
207317688Spst	    break;
207417688Spst	}
207517688Spst
2076127675Sbms        /* first lets see if we know the TLVs name*/
2077127675Sbms	printf("\n\t    %s TLV #%u, length: %u",
2078127675Sbms               tok2str(isis_tlv_values,
2079127675Sbms                       "unknown",
2080127675Sbms                       tlv_type),
2081127675Sbms               tlv_type,
2082127675Sbms               tlv_len);
2083127675Sbms
2084147175Ssam        if (tlv_len == 0) /* something is malformed */
2085147175Ssam            break;
2086147175Ssam
2087127675Sbms        /* now check if we have a decoder otherwise do a hexdump at the end*/
2088127675Sbms	switch (tlv_type) {
2089146778Ssam	case ISIS_TLV_AREA_ADDR:
209098527Sfenner	    if (!TTEST2(*tptr, 1))
209198527Sfenner		goto trunctlv;
209217688Spst	    alen = *tptr++;
209317688Spst	    while (tmp && alen < tmp) {
2094127675Sbms		printf("\n\t      Area address (length: %u): %s",
2095127675Sbms                       alen,
2096146778Ssam                       isonsap_string(tptr,alen));
209717688Spst		tptr += alen;
209817688Spst		tmp -= alen + 1;
209998527Sfenner		if (tmp==0) /* if this is the last area address do not attemt a boundary check */
2100127675Sbms                    break;
210198527Sfenner		if (!TTEST2(*tptr, 1))
210298527Sfenner		    goto trunctlv;
210317688Spst		alen = *tptr++;
210417688Spst	    }
210517688Spst	    break;
2106146778Ssam	case ISIS_TLV_ISNEIGH:
210775118Sfenner	    while (tmp >= ETHER_ADDR_LEN) {
2108127675Sbms                if (!TTEST2(*tptr, ETHER_ADDR_LEN))
2109127675Sbms                    goto trunctlv;
2110127675Sbms                printf("\n\t      SNPA: %s",isis_print_id(tptr,ETHER_ADDR_LEN));
2111127675Sbms                tmp -= ETHER_ADDR_LEN;
2112127675Sbms                tptr += ETHER_ADDR_LEN;
211317688Spst	    }
211417688Spst	    break;
211598527Sfenner
2116146778Ssam        case ISIS_TLV_ISNEIGH_VARLEN:
2117147175Ssam            if (!TTEST2(*tptr, 1) || tmp < 3) /* min. TLV length */
2118127675Sbms		goto trunctlv;
2119147904Ssam	    lan_alen = *tptr++; /* LAN address length */
2120147904Ssam	    if (lan_alen == 0) {
2121147904Ssam                printf("\n\t      LAN address length 0 bytes (invalid)");
2122147904Ssam                break;
2123147904Ssam            }
2124127675Sbms            tmp --;
2125127675Sbms            printf("\n\t      LAN address length %u bytes ",lan_alen);
2126127675Sbms	    while (tmp >= lan_alen) {
2127127675Sbms                if (!TTEST2(*tptr, lan_alen))
2128127675Sbms                    goto trunctlv;
2129127675Sbms                printf("\n\t\tIS Neighbor: %s",isis_print_id(tptr,lan_alen));
2130127675Sbms                tmp -= lan_alen;
2131127675Sbms                tptr +=lan_alen;
2132127675Sbms            }
2133127675Sbms            break;
2134127675Sbms
2135146778Ssam	case ISIS_TLV_PADDING:
213617688Spst	    break;
213798527Sfenner
2138146778Ssam        case ISIS_TLV_MT_IS_REACH:
2139127675Sbms            while (tmp >= 2+NODE_ID_LEN+3+1) {
2140127675Sbms                mt_len = isis_print_mtid(tptr, "\n\t      ");
2141127675Sbms                if (mt_len == 0) /* did something go wrong ? */
2142127675Sbms                    goto trunctlv;
2143127675Sbms                tptr+=mt_len;
2144127675Sbms                tmp-=mt_len;
214598527Sfenner
2146127675Sbms                ext_is_len = isis_print_ext_is_reach(tptr,"\n\t      ",tlv_type);
2147127675Sbms                if (ext_is_len == 0) /* did something go wrong ? */
214898527Sfenner                    goto trunctlv;
2149127675Sbms
2150127675Sbms                tmp-=ext_is_len;
2151127675Sbms                tptr+=ext_is_len;
215298527Sfenner            }
215398527Sfenner            break;
215498527Sfenner
2155146778Ssam        case ISIS_TLV_IS_ALIAS_ID:
2156127675Sbms	    while (tmp >= NODE_ID_LEN+1) { /* is it worth attempting a decode ? */
2157127675Sbms	        ext_is_len = isis_print_ext_is_reach(tptr,"\n\t      ",tlv_type);
2158127675Sbms		if (ext_is_len == 0) /* did something go wrong ? */
2159127675Sbms	            goto trunctlv;
2160127675Sbms		tmp-=ext_is_len;
2161127675Sbms		tptr+=ext_is_len;
2162127675Sbms	    }
2163127675Sbms	    break;
2164127675Sbms
2165146778Ssam        case ISIS_TLV_EXT_IS_REACH:
2166127675Sbms            while (tmp >= NODE_ID_LEN+3+1) { /* is it worth attempting a decode ? */
2167127675Sbms                ext_is_len = isis_print_ext_is_reach(tptr,"\n\t      ",tlv_type);
2168127675Sbms                if (ext_is_len == 0) /* did something go wrong ? */
2169127675Sbms                    goto trunctlv;
2170127675Sbms                tmp-=ext_is_len;
2171127675Sbms                tptr+=ext_is_len;
217298527Sfenner            }
217398527Sfenner            break;
2174146778Ssam        case ISIS_TLV_IS_REACH:
217598527Sfenner	    if (!TTEST2(*tptr,1))  /* check if there is one byte left to read out the virtual flag */
2176127675Sbms                goto trunctlv;
2177127675Sbms            printf("\n\t      %s",
2178127675Sbms                   tok2str(isis_is_reach_virtual_values,
2179127675Sbms                           "bogus virtual flag 0x%02x",
2180127675Sbms                           *tptr++));
218198527Sfenner	    tlv_is_reach = (const struct isis_tlv_is_reach *)tptr;
218298527Sfenner            while (tmp >= sizeof(struct isis_tlv_is_reach)) {
218398527Sfenner		if (!TTEST(*tlv_is_reach))
218498527Sfenner		    goto trunctlv;
2185127675Sbms		printf("\n\t      IS Neighbor: %s",
2186127675Sbms		       isis_print_id(tlv_is_reach->neighbor_nodeid, NODE_ID_LEN));
2187127675Sbms                isis_print_metric_block(&tlv_is_reach->isis_metric_block);
218898527Sfenner		tmp -= sizeof(struct isis_tlv_is_reach);
218998527Sfenner		tlv_is_reach++;
219098527Sfenner	    }
219198527Sfenner            break;
219298527Sfenner
2193146778Ssam        case ISIS_TLV_ESNEIGH:
2194127675Sbms	    tlv_es_reach = (const struct isis_tlv_es_reach *)tptr;
2195127675Sbms            while (tmp >= sizeof(struct isis_tlv_es_reach)) {
2196127675Sbms		if (!TTEST(*tlv_es_reach))
2197127675Sbms		    goto trunctlv;
2198127675Sbms		printf("\n\t      ES Neighbor: %s",
2199127675Sbms                       isis_print_id(tlv_es_reach->neighbor_sysid,SYSTEM_ID_LEN));
2200127675Sbms                isis_print_metric_block(&tlv_es_reach->isis_metric_block);
2201127675Sbms		tmp -= sizeof(struct isis_tlv_es_reach);
2202127675Sbms		tlv_es_reach++;
2203127675Sbms	    }
2204127675Sbms            break;
2205127675Sbms
2206127675Sbms            /* those two TLVs share the same format */
2207146778Ssam	case ISIS_TLV_INT_IP_REACH:
2208146778Ssam	case ISIS_TLV_EXT_IP_REACH:
2209127675Sbms	    if (!isis_print_tlv_ip_reach(pptr, "\n\t      ", tlv_len))
221098527Sfenner		return (1);
221117688Spst	    break;
221298527Sfenner
2213146778Ssam	case ISIS_TLV_EXTD_IP_REACH:
2214127675Sbms	    while (tmp>0) {
2215127675Sbms                ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", IPV4);
2216127675Sbms                if (ext_ip_len == 0) /* did something go wrong ? */
2217127675Sbms                    goto trunctlv;
2218127675Sbms                tptr+=ext_ip_len;
2219127675Sbms		tmp-=ext_ip_len;
2220127675Sbms	    }
222198527Sfenner	    break;
222298527Sfenner
2223146778Ssam        case ISIS_TLV_MT_IP_REACH:
2224127675Sbms	    while (tmp>0) {
2225127675Sbms                mt_len = isis_print_mtid(tptr, "\n\t      ");
2226127675Sbms                if (mt_len == 0) /* did something go wrong ? */
2227127675Sbms                    goto trunctlv;
2228127675Sbms                tptr+=mt_len;
2229127675Sbms                tmp-=mt_len;
223098527Sfenner
2231127675Sbms                ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", IPV4);
2232127675Sbms                if (ext_ip_len == 0) /* did something go wrong ? */
2233127675Sbms                    goto trunctlv;
2234127675Sbms                tptr+=ext_ip_len;
2235127675Sbms		tmp-=ext_ip_len;
223698527Sfenner	    }
223798527Sfenner	    break;
223898527Sfenner
223998527Sfenner#ifdef INET6
2240146778Ssam	case ISIS_TLV_IP6_REACH:
2241127675Sbms	    while (tmp>0) {
2242127675Sbms                ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", IPV6);
2243127675Sbms                if (ext_ip_len == 0) /* did something go wrong ? */
2244127675Sbms                    goto trunctlv;
2245127675Sbms                tptr+=ext_ip_len;
2246127675Sbms		tmp-=ext_ip_len;
2247127675Sbms	    }
2248127675Sbms	    break;
224998527Sfenner
2250146778Ssam	case ISIS_TLV_MT_IP6_REACH:
2251127675Sbms	    while (tmp>0) {
2252127675Sbms                mt_len = isis_print_mtid(tptr, "\n\t      ");
2253127675Sbms                if (mt_len == 0) /* did something go wrong ? */
2254127675Sbms                    goto trunctlv;
2255127675Sbms                tptr+=mt_len;
2256127675Sbms                tmp-=mt_len;
225798527Sfenner
2258127675Sbms                ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", IPV6);
2259127675Sbms                if (ext_ip_len == 0) /* did something go wrong ? */
2260127675Sbms                    goto trunctlv;
2261127675Sbms                tptr+=ext_ip_len;
2262127675Sbms		tmp-=ext_ip_len;
226398527Sfenner	    }
226498527Sfenner	    break;
226598527Sfenner
2266146778Ssam	case ISIS_TLV_IP6ADDR:
2267147904Ssam	    while (tmp>=16) {
226898527Sfenner		if (!TTEST2(*tptr, 16))
226998527Sfenner		    goto trunctlv;
227098527Sfenner
2271127675Sbms                printf("\n\t      IPv6 interface address: %s",
227298527Sfenner		       ip6addr_string(tptr));
227398527Sfenner
227498527Sfenner		tptr += 16;
2275127675Sbms		tmp -= 16;
227698527Sfenner	    }
227798527Sfenner	    break;
227898527Sfenner#endif
2279146778Ssam	case ISIS_TLV_AUTH:
2280127675Sbms	    if (!TTEST2(*tptr, 1))
228198527Sfenner		goto trunctlv;
2282127675Sbms
2283127675Sbms            printf("\n\t      %s: ",
2284127675Sbms                   tok2str(isis_subtlv_auth_values,
2285127675Sbms                           "unknown Authentication type 0x%02x",
2286127675Sbms                           *tptr));
2287127675Sbms
2288127675Sbms	    switch (*tptr) {
2289146778Ssam	    case ISIS_SUBTLV_AUTH_SIMPLE:
2290127675Sbms		for(i=1;i<tlv_len;i++) {
2291127675Sbms		    if (!TTEST2(*(tptr+i), 1))
229298527Sfenner			goto trunctlv;
2293127675Sbms		    printf("%c",*(tptr+i));
229498527Sfenner		}
2295127675Sbms		break;
2296146778Ssam	    case ISIS_SUBTLV_AUTH_MD5:
2297127675Sbms		for(i=1;i<tlv_len;i++) {
2298127675Sbms		    if (!TTEST2(*(tptr+i), 1))
229998527Sfenner			goto trunctlv;
2300127675Sbms		    printf("%02x",*(tptr+i));
230198527Sfenner		}
2302146778Ssam		if (tlv_len != ISIS_SUBTLV_AUTH_MD5_LEN+1)
2303127675Sbms                    printf(", (malformed subTLV) ");
2304127675Sbms		break;
2305146778Ssam	    case ISIS_SUBTLV_AUTH_PRIVATE:
2306127675Sbms	    default:
2307127675Sbms		if(!print_unknown_data(tptr+1,"\n\t\t  ",tlv_len-1))
2308127675Sbms		    return(0);
2309127675Sbms		break;
231098527Sfenner	    }
231198527Sfenner	    break;
231298527Sfenner
2313146778Ssam	case ISIS_TLV_PTP_ADJ:
2314127675Sbms	    tlv_ptp_adj = (const struct isis_tlv_ptp_adj *)tptr;
2315127675Sbms	    if(tmp>=1) {
2316127675Sbms		if (!TTEST2(*tptr, 1))
231798527Sfenner		    goto trunctlv;
2318127675Sbms		printf("\n\t      Adjacency State: %s (%u)",
2319127675Sbms		       tok2str(isis_ptp_adjancey_values, "unknown", *tptr),
2320127675Sbms                        *tptr);
2321127675Sbms		tmp--;
232298527Sfenner	    }
2323127675Sbms	    if(tmp>sizeof(tlv_ptp_adj->extd_local_circuit_id)) {
2324127675Sbms		if (!TTEST2(tlv_ptp_adj->extd_local_circuit_id,
2325127675Sbms                            sizeof(tlv_ptp_adj->extd_local_circuit_id)))
232698527Sfenner		    goto trunctlv;
2327127675Sbms		printf("\n\t      Extended Local circuit-ID: 0x%08x",
2328127675Sbms		       EXTRACT_32BITS(tlv_ptp_adj->extd_local_circuit_id));
2329127675Sbms		tmp-=sizeof(tlv_ptp_adj->extd_local_circuit_id);
233098527Sfenner	    }
2331127675Sbms	    if(tmp>=SYSTEM_ID_LEN) {
2332127675Sbms		if (!TTEST2(tlv_ptp_adj->neighbor_sysid, SYSTEM_ID_LEN))
233398527Sfenner		    goto trunctlv;
2334127675Sbms		printf("\n\t      Neighbor System-ID: %s",
2335127675Sbms		       isis_print_id(tlv_ptp_adj->neighbor_sysid,SYSTEM_ID_LEN));
2336127675Sbms		tmp-=SYSTEM_ID_LEN;
233798527Sfenner	    }
2338127675Sbms	    if(tmp>=sizeof(tlv_ptp_adj->neighbor_extd_local_circuit_id)) {
2339127675Sbms		if (!TTEST2(tlv_ptp_adj->neighbor_extd_local_circuit_id,
2340127675Sbms                            sizeof(tlv_ptp_adj->neighbor_extd_local_circuit_id)))
234198527Sfenner		    goto trunctlv;
2342127675Sbms		printf("\n\t      Neighbor Extended Local circuit-ID: 0x%08x",
2343127675Sbms		       EXTRACT_32BITS(tlv_ptp_adj->neighbor_extd_local_circuit_id));
234498527Sfenner	    }
234532149Spst	    break;
234698527Sfenner
2347146778Ssam	case ISIS_TLV_PROTOCOLS:
2348127675Sbms	    printf("\n\t      NLPID(s): ");
2349127675Sbms	    while (tmp>0) {
2350127675Sbms		if (!TTEST2(*(tptr), 1))
235198527Sfenner		    goto trunctlv;
2352127675Sbms		printf("%s (0x%02x)",
2353146778Ssam                       tok2str(nlpid_values,
2354127675Sbms                               "unknown",
2355127675Sbms                               *tptr),
2356127675Sbms                       *tptr);
2357127675Sbms		if (tmp>1) /* further NPLIDs ? - put comma */
235898527Sfenner		    printf(", ");
2359127675Sbms                tptr++;
2360127675Sbms                tmp--;
236198527Sfenner	    }
236232149Spst	    break;
236398527Sfenner
2364146778Ssam	case ISIS_TLV_TE_ROUTER_ID:
236598527Sfenner	    if (!TTEST2(*pptr, 4))
236698527Sfenner		goto trunctlv;
2367127675Sbms	    printf("\n\t      Traffic Engineering Router ID: %s", ipaddr_string(pptr));
236898527Sfenner	    break;
236998527Sfenner
2370146778Ssam	case ISIS_TLV_IPADDR:
2371147904Ssam	    while (tmp>=4) {
237298527Sfenner		if (!TTEST2(*tptr, 4))
237398527Sfenner		    goto trunctlv;
2374127675Sbms		printf("\n\t      IPv4 interface address: %s", ipaddr_string(tptr));
237598527Sfenner		tptr += 4;
2376127675Sbms		tmp -= 4;
237798527Sfenner	    }
237832149Spst	    break;
237998527Sfenner
2380146778Ssam	case ISIS_TLV_HOSTNAME:
2381127675Sbms	    printf("\n\t      Hostname: ");
2382127675Sbms	    while (tmp>0) {
2383127675Sbms		if (!TTEST2(*tptr, 1))
238498527Sfenner		    goto trunctlv;
2385127675Sbms		printf("%c",*tptr++);
2386127675Sbms                tmp--;
238798527Sfenner	    }
238898527Sfenner	    break;
238998527Sfenner
2390146778Ssam	case ISIS_TLV_SHARED_RISK_GROUP:
2391147904Ssam	    if (tmp < NODE_ID_LEN)
2392147904Ssam	        break;
2393127675Sbms	    if (!TTEST2(*tptr, NODE_ID_LEN))
2394127675Sbms                goto trunctlv;
2395127675Sbms	    printf("\n\t      IS Neighbor: %s", isis_print_id(tptr, NODE_ID_LEN));
2396127675Sbms	    tptr+=(NODE_ID_LEN);
2397127675Sbms	    tmp-=(NODE_ID_LEN);
2398127675Sbms
2399147904Ssam	    if (tmp < 1)
2400147904Ssam	        break;
2401127675Sbms	    if (!TTEST2(*tptr, 1))
2402127675Sbms                goto trunctlv;
2403127675Sbms	    printf(", Flags: [%s]", ISIS_MASK_TLV_SHARED_RISK_GROUP(*tptr++) ? "numbered" : "unnumbered");
2404127675Sbms	    tmp--;
2405127675Sbms
2406147904Ssam	    if (tmp < 4)
2407147904Ssam	        break;
2408127675Sbms	    if (!TTEST2(*tptr,4))
2409127675Sbms                goto trunctlv;
2410127675Sbms	    printf("\n\t      IPv4 interface address: %s", ipaddr_string(tptr));
2411127675Sbms	    tptr+=4;
2412127675Sbms	    tmp-=4;
2413127675Sbms
2414147904Ssam	    if (tmp < 4)
2415147904Ssam	        break;
2416127675Sbms	    if (!TTEST2(*tptr,4))
2417127675Sbms                goto trunctlv;
2418127675Sbms	    printf("\n\t      IPv4 neighbor address: %s", ipaddr_string(tptr));
2419127675Sbms	    tptr+=4;
2420127675Sbms	    tmp-=4;
2421127675Sbms
2422147904Ssam	    while (tmp>=4) {
2423127675Sbms                if (!TTEST2(*tptr, 4))
2424127675Sbms                    goto trunctlv;
2425127675Sbms                printf("\n\t      Link-ID: 0x%08x", EXTRACT_32BITS(tptr));
2426127675Sbms                tptr+=4;
2427127675Sbms                tmp-=4;
2428127675Sbms	    }
2429127675Sbms	    break;
2430127675Sbms
2431146778Ssam	case ISIS_TLV_LSP:
2432127675Sbms	    tlv_lsp = (const struct isis_tlv_lsp *)tptr;
2433147904Ssam	    while(tmp>=sizeof(struct isis_tlv_lsp)) {
2434127675Sbms		if (!TTEST((tlv_lsp->lsp_id)[LSP_ID_LEN-1]))
243598527Sfenner		    goto trunctlv;
2436127675Sbms		printf("\n\t      lsp-id: %s",
2437127675Sbms                       isis_print_id(tlv_lsp->lsp_id, LSP_ID_LEN));
243898527Sfenner		if (!TTEST2(tlv_lsp->sequence_number, 4))
243998527Sfenner		    goto trunctlv;
2440127675Sbms		printf(", seq: 0x%08x",EXTRACT_32BITS(tlv_lsp->sequence_number));
244198527Sfenner		if (!TTEST2(tlv_lsp->remaining_lifetime, 2))
244298527Sfenner		    goto trunctlv;
2443127675Sbms		printf(", lifetime: %5ds",EXTRACT_16BITS(tlv_lsp->remaining_lifetime));
244498527Sfenner		if (!TTEST2(tlv_lsp->checksum, 2))
244598527Sfenner		    goto trunctlv;
2446127675Sbms		printf(", chksum: 0x%04x",EXTRACT_16BITS(tlv_lsp->checksum));
2447127675Sbms		tmp-=sizeof(struct isis_tlv_lsp);
244898527Sfenner		tlv_lsp++;
244998527Sfenner	    }
245098527Sfenner	    break;
245198527Sfenner
2452146778Ssam	case ISIS_TLV_CHECKSUM:
2453147904Ssam	    if (tmp < 2)
2454147904Ssam	        break;
2455127675Sbms	    if (!TTEST2(*tptr, 2))
245698527Sfenner		goto trunctlv;
2457127675Sbms	    printf("\n\t      checksum: 0x%04x ", EXTRACT_16BITS(tptr));
2458127675Sbms            /* do not attempt to verify the checksum if it is zero
2459127675Sbms             * most likely a HMAC-MD5 TLV is also present and
2460127675Sbms             * to avoid conflicts the checksum TLV is zeroed.
2461127675Sbms             * see rfc3358 for details
2462127675Sbms             */
2463127675Sbms            if (EXTRACT_16BITS(tptr) == 0)
2464127675Sbms                printf("(unverified)");
2465127675Sbms            else printf("(%s)", osi_cksum(optr, length) ? "incorrect" : "correct");
246698527Sfenner	    break;
246798527Sfenner
2468146778Ssam	case ISIS_TLV_MT_SUPPORTED:
2469127675Sbms	    while (tmp>1) {
2470127675Sbms		/* length can only be a multiple of 2, otherwise there is
247198527Sfenner		   something broken -> so decode down until length is 1 */
2472127675Sbms		if (tmp!=1) {
2473127675Sbms                    mt_len = isis_print_mtid(tptr, "\n\t      ");
2474127675Sbms                    if (mt_len == 0) /* did something go wrong ? */
2475127675Sbms                        goto trunctlv;
2476127675Sbms                    tptr+=mt_len;
2477127675Sbms                    tmp-=mt_len;
247898527Sfenner		} else {
2479127675Sbms		    printf("\n\t      malformed MT-ID");
248098527Sfenner		    break;
248198527Sfenner		}
248298527Sfenner	    }
248398527Sfenner	    break;
248498527Sfenner
2485146778Ssam	case ISIS_TLV_RESTART_SIGNALING:
2486147904Ssam	    if (tmp < 3)
2487147904Ssam	        break;
2488127675Sbms            if (!TTEST2(*tptr, 3))
2489127675Sbms                goto trunctlv;
2490127675Sbms            printf("\n\t      Flags [%s], Remaining holding time %us",
2491127675Sbms                   bittok2str(isis_restart_flag_values, "none", *tptr),
2492127675Sbms                   EXTRACT_16BITS(tptr+1));
2493127675Sbms	    tptr+=3;
2494147904Ssam            tmp-=3;
2495147904Ssam            if (tmp == SYSTEM_ID_LEN) {
2496147904Ssam                    if (!TTEST2(*tptr, SYSTEM_ID_LEN))
2497147904Ssam                            goto trunctlv;
2498147904Ssam                    printf(", for %s",isis_print_id(tptr,SYSTEM_ID_LEN));
2499147904Ssam            } else if (tmp == NODE_ID_LEN) {
2500147904Ssam                    if (!TTEST2(*tptr, NODE_ID_LEN))
2501147904Ssam                            goto trunctlv;
2502147904Ssam                    printf(", for %s",isis_print_id(tptr,NODE_ID_LEN));
2503147904Ssam            }
250498527Sfenner	    break;
250598527Sfenner
2506146778Ssam        case ISIS_TLV_IDRP_INFO:
2507147904Ssam	    if (tmp < 1)
2508147904Ssam	        break;
2509127675Sbms            if (!TTEST2(*tptr, 1))
2510127675Sbms                goto trunctlv;
2511127675Sbms            printf("\n\t      Inter-Domain Information Type: %s",
2512127675Sbms                   tok2str(isis_subtlv_idrp_values,
2513127675Sbms                           "Unknown (0x%02x)",
2514127675Sbms                           *tptr));
2515127675Sbms            switch (*tptr++) {
2516146778Ssam            case ISIS_SUBTLV_IDRP_ASN:
2517127675Sbms                if (!TTEST2(*tptr, 2)) /* fetch AS number */
2518127675Sbms                    goto trunctlv;
2519127675Sbms                printf("AS Number: %u",EXTRACT_16BITS(tptr));
2520127675Sbms                break;
2521146778Ssam            case ISIS_SUBTLV_IDRP_LOCAL:
2522146778Ssam            case ISIS_SUBTLV_IDRP_RES:
2523127675Sbms            default:
2524127675Sbms                if(!print_unknown_data(tptr,"\n\t      ",tlv_len-1))
2525127675Sbms                    return(0);
2526127675Sbms                break;
2527127675Sbms            }
2528127675Sbms            break;
2529127675Sbms
2530146778Ssam        case ISIS_TLV_LSP_BUFFERSIZE:
2531147904Ssam	    if (tmp < 2)
2532147904Ssam	        break;
2533127675Sbms            if (!TTEST2(*tptr, 2))
2534127675Sbms                goto trunctlv;
2535127675Sbms            printf("\n\t      LSP Buffersize: %u",EXTRACT_16BITS(tptr));
2536127675Sbms            break;
2537127675Sbms
2538146778Ssam        case ISIS_TLV_PART_DIS:
2539127675Sbms            while (tmp >= SYSTEM_ID_LEN) {
2540127675Sbms                if (!TTEST2(*tptr, SYSTEM_ID_LEN))
2541127675Sbms                    goto trunctlv;
2542127675Sbms                printf("\n\t      %s",isis_print_id(tptr,SYSTEM_ID_LEN));
2543127675Sbms                tptr+=SYSTEM_ID_LEN;
2544127675Sbms                tmp-=SYSTEM_ID_LEN;
2545127675Sbms            }
2546127675Sbms            break;
2547127675Sbms
2548146778Ssam        case ISIS_TLV_PREFIX_NEIGH:
2549147904Ssam	    if (tmp < sizeof(struct isis_metric_block))
2550147904Ssam	        break;
2551127675Sbms            if (!TTEST2(*tptr, sizeof(struct isis_metric_block)))
2552127675Sbms                goto trunctlv;
2553127675Sbms            printf("\n\t      Metric Block");
2554127675Sbms            isis_print_metric_block((const struct isis_metric_block *)tptr);
2555127675Sbms            tptr+=sizeof(struct isis_metric_block);
2556127675Sbms            tmp-=sizeof(struct isis_metric_block);
2557127675Sbms
2558127675Sbms            while(tmp>0) {
2559127675Sbms                if (!TTEST2(*tptr, 1))
2560127675Sbms                    goto trunctlv;
2561127675Sbms                prefix_len=*tptr++; /* read out prefix length in semioctets*/
2562147904Ssam                if (prefix_len < 2) {
2563147904Ssam                    printf("\n\t\tAddress: prefix length %u < 2", prefix_len);
2564147904Ssam                    break;
2565147904Ssam                }
2566127675Sbms                tmp--;
2567147904Ssam                if (tmp < prefix_len/2)
2568147904Ssam                    break;
2569127675Sbms                if (!TTEST2(*tptr, prefix_len/2))
2570127675Sbms                    goto trunctlv;
2571127675Sbms                printf("\n\t\tAddress: %s/%u",
2572146778Ssam                       isonsap_string(tptr,prefix_len/2),
2573127675Sbms                       prefix_len*4);
2574127675Sbms                tptr+=prefix_len/2;
2575127675Sbms                tmp-=prefix_len/2;
2576127675Sbms            }
2577127675Sbms            break;
2578127675Sbms
2579146778Ssam        case ISIS_TLV_IIH_SEQNR:
2580147904Ssam	    if (tmp < 4)
2581147904Ssam	        break;
2582127675Sbms            if (!TTEST2(*tptr, 4)) /* check if four bytes are on the wire */
2583127675Sbms                goto trunctlv;
2584127675Sbms            printf("\n\t      Sequence number: %u", EXTRACT_32BITS(tptr) );
2585127675Sbms            break;
2586127675Sbms
2587146778Ssam        case ISIS_TLV_VENDOR_PRIVATE:
2588147904Ssam	    if (tmp < 3)
2589147904Ssam	        break;
2590127675Sbms            if (!TTEST2(*tptr, 3)) /* check if enough byte for a full oui */
2591127675Sbms                goto trunctlv;
2592146778Ssam            vendor_id = EXTRACT_24BITS(tptr);
2593146778Ssam            printf("\n\t      Vendor: %s (%u)",
2594146778Ssam                   tok2str(oui_values,"Unknown",vendor_id),
2595146778Ssam                   vendor_id);
2596127675Sbms            tptr+=3;
2597127675Sbms            tmp-=3;
2598127675Sbms            if (tmp > 0) /* hexdump the rest */
2599127675Sbms                if(!print_unknown_data(tptr,"\n\t\t",tmp))
2600127675Sbms                    return(0);
2601127675Sbms            break;
2602127675Sbms            /*
2603127675Sbms             * FIXME those are the defined TLVs that lack a decoder
2604127675Sbms             * you are welcome to contribute code ;-)
2605127675Sbms             */
2606127675Sbms
2607146778Ssam        case ISIS_TLV_DECNET_PHASE4:
2608146778Ssam        case ISIS_TLV_LUCENT_PRIVATE:
2609146778Ssam        case ISIS_TLV_IPAUTH:
2610146778Ssam        case ISIS_TLV_NORTEL_PRIVATE1:
2611146778Ssam        case ISIS_TLV_NORTEL_PRIVATE2:
2612127675Sbms
261317688Spst	default:
2614127675Sbms            if (vflag <= 1) {
2615127675Sbms                if(!print_unknown_data(pptr,"\n\t\t",tlv_len))
2616127675Sbms                    return(0);
2617127675Sbms            }
261817688Spst	    break;
261917688Spst	}
2620127675Sbms        /* do we want to see an additionally hexdump ? */
2621127675Sbms        if (vflag> 1) {
2622127675Sbms	    if(!print_unknown_data(pptr,"\n\t      ",tlv_len))
2623127675Sbms	        return(0);
2624127675Sbms        }
262517688Spst
2626127675Sbms	pptr += tlv_len;
2627127675Sbms	packet_len -= tlv_len;
262817688Spst    }
262917688Spst
263017688Spst    if (packet_len != 0) {
2631127675Sbms	printf("\n\t      %u straggler bytes", packet_len);
263217688Spst    }
263398527Sfenner    return (1);
263498527Sfenner
2635127675Sbms trunc:
263698527Sfenner    fputs("[|isis]", stdout);
263798527Sfenner    return (1);
263898527Sfenner
2639127675Sbms trunctlv:
2640127675Sbms    printf("\n\t\t packet exceeded snapshot");
264117688Spst    return(1);
264217688Spst}
264317688Spst
264417751Spst/*
264517751Spst * Verify the checksum.  See 8473-1, Appendix C, section C.4.
264617751Spst */
264717751Spst
264817688Spststatic int
2649127675Sbmsosi_cksum(const u_int8_t *tptr, u_int len)
265017680Spst{
265117680Spst	int32_t c0 = 0, c1 = 0;
265217680Spst
265339300Sfenner	while ((int)--len >= 0) {
2654127675Sbms		c0 += *tptr++;
265517751Spst		c0 %= 255;
265617680Spst		c1 += c0;
265717680Spst		c1 %= 255;
265817680Spst	}
265917751Spst	return (c0 | c1);
266017680Spst}
2661146778Ssam
2662146778Ssam
2663146778Ssam/*
2664146778Ssam * Local Variables:
2665146778Ssam * c-style: whitesmith
2666146778Ssam * c-basic-offset: 8
2667146778Ssam * End:
2668146778Ssam */
2669