print-isoclns.c revision 127675
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
2498527Sfenner * complete IS-IS support.
2598527Sfenner *
2656896Sfenner * $FreeBSD: head/contrib/tcpdump/print-isoclns.c 127675 2004-03-31 14:57:24Z bms $
2717680Spst */
2817680Spst
2917680Spst#ifndef lint
30127675Sbmsstatic const char rcsid[] _U_ =
31127675Sbms    "@(#) $Header: /tcpdump/master/tcpdump/print-isoclns.c,v 1.106.2.5 2004/03/24 01:45:26 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"
4717688Spst#include "extract.h"
48127675Sbms#include "gmpls.h"
4917680Spst
5017688Spst#define	NLPID_CLNS	129	/* 0x81 */
5117688Spst#define	NLPID_ESIS	130	/* 0x82 */
5217688Spst#define	NLPID_ISIS	131	/* 0x83 */
5398527Sfenner#define NLPID_IP6       0x8e
54127675Sbms#define NLPID_IP        0xcc
5517688Spst#define	NLPID_NULLNS	0
5617680Spst
57127675Sbms#define IPV4            1       /* AFI value */
58127675Sbms#define IPV6            2       /* AFI value */
59127675Sbms
6032149Spst/*
6132149Spst * IS-IS is defined in ISO 10589.  Look there for protocol definitions.
6232149Spst */
6332149Spst
6475118Sfenner#define SYSTEM_ID_LEN	ETHER_ADDR_LEN
65127675Sbms#define NODE_ID_LEN     SYSTEM_ID_LEN+1
66127675Sbms#define LSP_ID_LEN      SYSTEM_ID_LEN+2
67127675Sbms
6832149Spst#define ISIS_VERSION	1
6932149Spst#define PDU_TYPE_MASK	0x1F
7032149Spst#define PRIORITY_MASK	0x7F
7132149Spst
7232149Spst#define L1_LAN_IIH	15
7332149Spst#define L2_LAN_IIH	16
7432149Spst#define PTP_IIH		17
7598527Sfenner#define L1_LSP       	18
7698527Sfenner#define L2_LSP       	20
7798527Sfenner#define L1_CSNP  	24
7898527Sfenner#define L2_CSNP  	25
7998527Sfenner#define L1_PSNP		26
8098527Sfenner#define L2_PSNP		27
8132149Spst
82127675Sbmsstatic struct tok isis_pdu_values[] = {
83127675Sbms    { L1_LAN_IIH,       "L1 Lan IIH"},
84127675Sbms    { L2_LAN_IIH,       "L2 Lan IIH"},
85127675Sbms    { PTP_IIH,          "p2p IIH"},
86127675Sbms    { L1_LSP,           "L1 LSP"},
87127675Sbms    { L2_LSP,           "L2 LSP"},
88127675Sbms    { L1_CSNP,          "L1 CSNP"},
89127675Sbms    { L2_CSNP,          "L2 CSNP"},
90127675Sbms    { L1_PSNP,          "L1 PSNP"},
91127675Sbms    { L2_PSNP,          "L2 PSNP"},
92127675Sbms    { 0, NULL}
93127675Sbms};
9498527Sfenner
9532149Spst/*
9632149Spst * A TLV is a tuple of a type, length and a value and is normally used for
9732149Spst * encoding information in all sorts of places.  This is an enumeration of
9832149Spst * the well known types.
99127675Sbms *
100127675Sbms * list taken from rfc3359 plus some memory from veterans ;-)
10132149Spst */
10232149Spst
103127675Sbms#define TLV_AREA_ADDR           1   /* iso10589 */
104127675Sbms#define TLV_IS_REACH            2   /* iso10589 */
105127675Sbms#define TLV_ESNEIGH             3   /* iso10589 */
106127675Sbms#define TLV_PART_DIS            4   /* iso10589 */
107127675Sbms#define TLV_PREFIX_NEIGH        5   /* iso10589 */
108127675Sbms#define TLV_ISNEIGH             6   /* iso10589 */
109127675Sbms#define TLV_ISNEIGH_VARLEN      7   /* iso10589 */
110127675Sbms#define TLV_PADDING             8   /* iso10589 */
111127675Sbms#define TLV_LSP                 9   /* iso10589 */
112127675Sbms#define TLV_AUTH                10  /* iso10589, rfc3567 */
113127675Sbms#define TLV_CHECKSUM            12  /* rfc3358 */
114127675Sbms#define TLV_LSP_BUFFERSIZE      14  /* iso10589 rev2 */
115127675Sbms#define TLV_EXT_IS_REACH        22  /* draft-ietf-isis-traffic-05 */
116127675Sbms#define TLV_IS_ALIAS_ID         24  /* draft-ietf-isis-ext-lsp-frags-02 */
117127675Sbms#define TLV_DECNET_PHASE4       42
118127675Sbms#define TLV_LUCENT_PRIVATE      66
119127675Sbms#define TLV_INT_IP_REACH        128 /* rfc1195, rfc2966 */
120127675Sbms#define TLV_PROTOCOLS           129 /* rfc1195 */
121127675Sbms#define TLV_EXT_IP_REACH        130 /* rfc1195, rfc2966 */
122127675Sbms#define TLV_IDRP_INFO           131 /* rfc1195 */
123127675Sbms#define TLV_IPADDR              132 /* rfc1195 */
124127675Sbms#define TLV_IPAUTH              133 /* rfc1195 */
125127675Sbms#define TLV_TE_ROUTER_ID        134 /* draft-ietf-isis-traffic-05 */
126127675Sbms#define TLV_EXTD_IP_REACH       135 /* draft-ietf-isis-traffic-05 */
127127675Sbms#define TLV_HOSTNAME            137 /* rfc2763 */
128127675Sbms#define TLV_SHARED_RISK_GROUP   138 /* draft-ietf-isis-gmpls-extensions */
129127675Sbms#define TLV_NORTEL_PRIVATE1     176
130127675Sbms#define TLV_NORTEL_PRIVATE2     177
131127675Sbms#define TLV_HOLDTIME            198 /* ES-IS */
132127675Sbms#define TLV_RESTART_SIGNALING   211 /* draft-ietf-isis-restart-01 */
133127675Sbms#define TLV_MT_IS_REACH         222 /* draft-ietf-isis-wg-multi-topology-05 */
134127675Sbms#define TLV_MT_SUPPORTED        229 /* draft-ietf-isis-wg-multi-topology-05 */
135127675Sbms#define TLV_IP6ADDR             232 /* draft-ietf-isis-ipv6-02 */
136127675Sbms#define TLV_MT_IP_REACH         235 /* draft-ietf-isis-wg-multi-topology-05 */
137127675Sbms#define TLV_IP6_REACH           236 /* draft-ietf-isis-ipv6-02 */
138127675Sbms#define TLV_MT_IP6_REACH        237 /* draft-ietf-isis-wg-multi-topology-05 */
139127675Sbms#define TLV_PTP_ADJ             240 /* rfc3373 */
140127675Sbms#define TLV_IIH_SEQNR           241 /* draft-shen-isis-iih-sequence-00 */
141127675Sbms#define TLV_VENDOR_PRIVATE      250 /* draft-ietf-isis-proprietary-tlv-00 */
14232149Spst
143127675Sbmsstatic struct tok isis_tlv_values[] = {
144127675Sbms    { TLV_AREA_ADDR,	     "Area address(es)"},
145127675Sbms    { TLV_IS_REACH,          "IS Reachability"},
146127675Sbms    { TLV_ESNEIGH,           "ES Neighbor(s)"},
147127675Sbms    { TLV_PART_DIS,          "Partition DIS"},
148127675Sbms    { TLV_PREFIX_NEIGH,      "Prefix Neighbors"},
149127675Sbms    { TLV_ISNEIGH,           "IS Neighbor(s)"},
150127675Sbms    { TLV_ISNEIGH_VARLEN,    "IS Neighbor(s) (variable length)"},
151127675Sbms    { TLV_PADDING,           "Padding"},
152127675Sbms    { TLV_LSP,               "LSP entries"},
153127675Sbms    { TLV_AUTH,              "Authentication"},
154127675Sbms    { TLV_CHECKSUM,          "Checksum"},
155127675Sbms    { TLV_LSP_BUFFERSIZE,    "LSP Buffersize"},
156127675Sbms    { TLV_EXT_IS_REACH,      "Extended IS Reachability"},
157127675Sbms    { TLV_IS_ALIAS_ID,       "IS Alias ID"},
158127675Sbms    { TLV_DECNET_PHASE4,     "DECnet Phase IV"},
159127675Sbms    { TLV_LUCENT_PRIVATE,    "Lucent Proprietary"},
160127675Sbms    { TLV_INT_IP_REACH,      "IPv4 Internal Reachability"},
161127675Sbms    { TLV_PROTOCOLS,         "Protocols supported"},
162127675Sbms    { TLV_EXT_IP_REACH,      "IPv4 External Reachability"},
163127675Sbms    { TLV_IDRP_INFO,         "Inter-Domain Information Type"},
164127675Sbms    { TLV_IPADDR,            "IPv4 Interface address(es)"},
165127675Sbms    { TLV_IPAUTH,            "IPv4 authentication (deprecated)"},
166127675Sbms    { TLV_TE_ROUTER_ID,      "Traffic Engineering Router ID"},
167127675Sbms    { TLV_EXTD_IP_REACH,      "Extended IPv4 Reachability"},
168127675Sbms    { TLV_HOSTNAME,          "Hostname"},
169127675Sbms    { TLV_SHARED_RISK_GROUP, "Shared Risk Link Group"},
170127675Sbms    { TLV_NORTEL_PRIVATE1,   "Nortel Proprietary"},
171127675Sbms    { TLV_NORTEL_PRIVATE2,   "Nortel Proprietary"},
172127675Sbms    { TLV_HOLDTIME,          "Holdtime"},
173127675Sbms    { TLV_RESTART_SIGNALING, "Restart Signaling"},
174127675Sbms    { TLV_MT_IS_REACH,       "Multi Topology IS Reachability"},
175127675Sbms    { TLV_MT_SUPPORTED,      "Multi Topology"},
176127675Sbms    { TLV_IP6ADDR,           "IPv6 Interface address(es)"},
177127675Sbms    { TLV_MT_IP_REACH,       "Multi-Topology IPv4 Reachability"},
178127675Sbms    { TLV_IP6_REACH,         "IPv6 reachability"},
179127675Sbms    { TLV_MT_IP6_REACH,      "Multi-Topology IP6 Reachability"},
180127675Sbms    { TLV_PTP_ADJ,           "Point-to-point Adjacency State"},
181127675Sbms    { TLV_IIH_SEQNR,         "Hello PDU Sequence Number"},
182127675Sbms    { TLV_VENDOR_PRIVATE,    "Vendor Private"},
183127675Sbms    { 0, NULL }
184127675Sbms};
18598527Sfenner
186127675Sbms#define SUBTLV_EXT_IS_REACH_ADMIN_GROUP           3 /* draft-ietf-isis-traffic-05 */
187127675Sbms#define SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID  4 /* draft-ietf-isis-gmpls-extensions */
188127675Sbms#define SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID        5 /* draft-ietf-isis-traffic-05 */
189127675Sbms#define SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR        6 /* draft-ietf-isis-traffic-05 */
190127675Sbms#define SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR    8 /* draft-ietf-isis-traffic-05 */
191127675Sbms#define SUBTLV_EXT_IS_REACH_MAX_LINK_BW           9 /* draft-ietf-isis-traffic-05 */
192127675Sbms#define SUBTLV_EXT_IS_REACH_RESERVABLE_BW        10 /* draft-ietf-isis-traffic-05 */
193127675Sbms#define SUBTLV_EXT_IS_REACH_UNRESERVED_BW        11 /* draft-ietf-isis-traffic-05 */
194127675Sbms#define SUBTLV_EXT_IS_REACH_TE_METRIC            18 /* draft-ietf-isis-traffic-05 */
195127675Sbms#define SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE 20 /* draft-ietf-isis-gmpls-extensions */
196127675Sbms#define SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR    21 /* draft-ietf-isis-gmpls-extensions */
19798527Sfenner
198127675Sbmsstatic struct tok isis_ext_is_reach_subtlv_values[] = {
199127675Sbms    { SUBTLV_EXT_IS_REACH_ADMIN_GROUP,            "Administrative groups" },
200127675Sbms    { SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID,   "Link Local/Remote Identifier" },
201127675Sbms    { SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID,         "Link Remote Identifier" },
202127675Sbms    { SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR,         "IPv4 interface address" },
203127675Sbms    { SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR,     "IPv4 neighbor address" },
204127675Sbms    { SUBTLV_EXT_IS_REACH_MAX_LINK_BW,            "Maximum link bandwidth" },
205127675Sbms    { SUBTLV_EXT_IS_REACH_RESERVABLE_BW,          "Reservable link bandwidth" },
206127675Sbms    { SUBTLV_EXT_IS_REACH_UNRESERVED_BW,          "Unreserved bandwidth" },
207127675Sbms    { SUBTLV_EXT_IS_REACH_TE_METRIC,              "Traffic Engineering Metric" },
208127675Sbms    { SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE,   "Link Protection Type" },
209127675Sbms    { SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR,      "Interface Switching Capability" },
210127675Sbms    { 250,                                        "Reserved for cisco specific extensions" },
211127675Sbms    { 251,                                        "Reserved for cisco specific extensions" },
212127675Sbms    { 252,                                        "Reserved for cisco specific extensions" },
213127675Sbms    { 253,                                        "Reserved for cisco specific extensions" },
214127675Sbms    { 254,                                        "Reserved for cisco specific extensions" },
215127675Sbms    { 255,                                        "Reserved for future expansion" },
216127675Sbms    { 0, NULL }
217127675Sbms};
21898527Sfenner
219127675Sbms#define SUBTLV_EXTD_IP_REACH_ADMIN_TAG32          1
220127675Sbms#define SUBTLV_EXTD_IP_REACH_ADMIN_TAG64          2
221127675Sbms
222127675Sbmsstatic struct tok isis_ext_ip_reach_subtlv_values[] = {
223127675Sbms    { SUBTLV_EXTD_IP_REACH_ADMIN_TAG32,           "32-Bit Administrative tag" },
224127675Sbms    { SUBTLV_EXTD_IP_REACH_ADMIN_TAG64,           "64-Bit Administrative tag" },
225127675Sbms    { 0, NULL }
226127675Sbms};
227127675Sbms
228127675Sbms#define SUBTLV_AUTH_SIMPLE        1
229127675Sbms#define SUBTLV_AUTH_MD5          54
230127675Sbms#define SUBTLV_AUTH_MD5_LEN      16
231127675Sbms#define SUBTLV_AUTH_PRIVATE     255
232127675Sbms
233127675Sbmsstatic struct tok isis_subtlv_auth_values[] = {
234127675Sbms    { SUBTLV_AUTH_SIMPLE,	"simple text password"},
235127675Sbms    { SUBTLV_AUTH_MD5,	        "HMAC-MD5 password"},
236127675Sbms    { SUBTLV_AUTH_PRIVATE,	"Routing Domain private password"},
237127675Sbms    { 0, NULL }
238127675Sbms};
239127675Sbms
240127675Sbms#define SUBTLV_IDRP_RES           0
241127675Sbms#define SUBTLV_IDRP_LOCAL         1
242127675Sbms#define SUBTLV_IDRP_ASN           2
243127675Sbms
244127675Sbmsstatic struct tok isis_subtlv_idrp_values[] = {
245127675Sbms    { SUBTLV_IDRP_RES,         "Reserved"},
246127675Sbms    { SUBTLV_IDRP_LOCAL,       "Routing-Domain Specific"},
247127675Sbms    { SUBTLV_IDRP_ASN,         "AS Number Tag"},
248127675Sbms    { 0, NULL}
249127675Sbms};
250127675Sbms
251127675Sbms#define ISIS_8BIT_MASK(x)                  ((x)&0xff)
252127675Sbms
25398527Sfenner#define ISIS_MASK_LSP_OL_BIT(x)            ((x)&0x4)
25498527Sfenner#define ISIS_MASK_LSP_ISTYPE_BITS(x)       ((x)&0x3)
25598527Sfenner#define ISIS_MASK_LSP_PARTITION_BIT(x)     ((x)&0x80)
25698527Sfenner#define ISIS_MASK_LSP_ATT_BITS(x)          ((x)&0x78)
25798527Sfenner#define ISIS_MASK_LSP_ATT_ERROR_BIT(x)     ((x)&0x40)
25898527Sfenner#define ISIS_MASK_LSP_ATT_EXPENSE_BIT(x)   ((x)&0x20)
25998527Sfenner#define ISIS_MASK_LSP_ATT_DELAY_BIT(x)     ((x)&0x10)
26098527Sfenner#define ISIS_MASK_LSP_ATT_DEFAULT_BIT(x)   ((x)&0x8)
26198527Sfenner
262127675Sbms#define ISIS_MASK_MTID(x)                  ((x)&0x0fff)
263127675Sbms#define ISIS_MASK_MTFLAGS(x)               ((x)&0xf000)
26498527Sfenner
265127675Sbmsstatic struct tok isis_mt_flag_values[] = {
266127675Sbms    { 0x4000,                  "sub-TLVs present"},
267127675Sbms    { 0x8000,                  "ATT bit set"},
268127675Sbms    { 0, NULL}
269127675Sbms};
27098527Sfenner
271127675Sbms#define ISIS_MASK_TLV_EXTD_IP_UPDOWN(x)     ((x)&0x80)
272127675Sbms#define ISIS_MASK_TLV_EXTD_IP_SUBTLV(x)     ((x)&0x40)
27398527Sfenner
274127675Sbms#define ISIS_MASK_TLV_EXTD_IP6_IE(x)        ((x)&0x40)
275127675Sbms#define ISIS_MASK_TLV_EXTD_IP6_SUBTLV(x)    ((x)&0x20)
276127675Sbms
27798527Sfenner#define ISIS_LSP_TLV_METRIC_SUPPORTED(x)   ((x)&0x80)
27898527Sfenner#define ISIS_LSP_TLV_METRIC_IE(x)          ((x)&0x40)
27998527Sfenner#define ISIS_LSP_TLV_METRIC_UPDOWN(x)      ((x)&0x80)
28098527Sfenner#define ISIS_LSP_TLV_METRIC_VALUE(x)	   ((x)&0x3f)
28198527Sfenner
282127675Sbms#define ISIS_MASK_TLV_SHARED_RISK_GROUP(x) ((x)&0x1)
283127675Sbms
284127675Sbmsstatic struct tok isis_mt_values[] = {
285127675Sbms    { 0,    "IPv4 unicast"},
286127675Sbms    { 1,    "In-Band Management"},
287127675Sbms    { 2,    "IPv6 unicast"},
288127675Sbms    { 3,    "Multicast"},
289127675Sbms    { 4095, "Development, Experimental or Proprietary"},
290127675Sbms    { 0, NULL }
291127675Sbms};
292127675Sbms
293127675Sbmsstatic struct tok isis_iih_circuit_type_values[] = {
294127675Sbms    { 1,    "Level 1 only"},
295127675Sbms    { 2,    "Level 2 only"},
296127675Sbms    { 3,    "Level 1, Level 2"},
297127675Sbms    { 0, NULL}
298127675Sbms};
299127675Sbms
30098527Sfenner#define ISIS_LSP_TYPE_UNUSED0   0
30198527Sfenner#define ISIS_LSP_TYPE_LEVEL_1   1
30298527Sfenner#define ISIS_LSP_TYPE_UNUSED2   2
30398527Sfenner#define ISIS_LSP_TYPE_LEVEL_2   3
30498527Sfenner
30598527Sfennerstatic struct tok isis_lsp_istype_values[] = {
306127675Sbms    { ISIS_LSP_TYPE_UNUSED0,	"Unused 0x0 (invalid)"},
307127675Sbms    { ISIS_LSP_TYPE_LEVEL_1,	"L1 IS"},
308127675Sbms    { ISIS_LSP_TYPE_UNUSED2,	"Unused 0x2 (invalid)"},
309127675Sbms    { ISIS_LSP_TYPE_LEVEL_2,	"L1L2 IS"},
310127675Sbms    { 0, NULL }
31198527Sfenner};
31298527Sfenner
313127675Sbmsstatic struct tok osi_nlpid_values[] = {
314127675Sbms    { NLPID_CLNS,   "CLNS"},
315127675Sbms    { NLPID_IP,     "IPv4"},
316127675Sbms    { NLPID_IP6,    "IPv6"},
317127675Sbms    { 0, NULL }
31898527Sfenner};
31998527Sfenner
32032149Spst/*
32132149Spst * Katz's point to point adjacency TLV uses codes to tell us the state of
32232149Spst * the remote adjacency.  Enumerate them.
32332149Spst */
32432149Spst
32532149Spst#define ISIS_PTP_ADJ_UP   0
32632149Spst#define ISIS_PTP_ADJ_INIT 1
32732149Spst#define ISIS_PTP_ADJ_DOWN 2
32832149Spst
32917680Spst
33098527Sfennerstatic struct tok isis_ptp_adjancey_values[] = {
331127675Sbms    { ISIS_PTP_ADJ_UP,    "Up" },
332127675Sbms    { ISIS_PTP_ADJ_INIT,  "Initializing" },
333127675Sbms    { ISIS_PTP_ADJ_DOWN,  "Down" },
334127675Sbms    { 0, NULL}
33532149Spst};
33632149Spst
33798527Sfennerstruct isis_tlv_ptp_adj {
338127675Sbms    u_int8_t adjacency_state;
339127675Sbms    u_int8_t extd_local_circuit_id[4];
340127675Sbms    u_int8_t neighbor_sysid[SYSTEM_ID_LEN];
341127675Sbms    u_int8_t neighbor_extd_local_circuit_id[4];
34232149Spst};
34332149Spst
344127675Sbmsstatic int osi_cksum(const u_int8_t *, u_int);
345127675Sbmsstatic void esis_print(const u_int8_t *, u_int);
346127675Sbmsstatic int isis_print(const u_int8_t *, u_int);
347127675Sbms
348127675Sbmsstruct isis_metric_block {
349127675Sbms    u_int8_t metric_default;
350127675Sbms    u_int8_t metric_delay;
351127675Sbms    u_int8_t metric_expense;
352127675Sbms    u_int8_t metric_error;
35398527Sfenner};
35498527Sfenner
35598527Sfennerstruct isis_tlv_is_reach {
356127675Sbms    struct isis_metric_block isis_metric_block;
357127675Sbms    u_int8_t neighbor_nodeid[NODE_ID_LEN];
35898527Sfenner};
35998527Sfenner
360127675Sbmsstruct isis_tlv_es_reach {
361127675Sbms    struct isis_metric_block isis_metric_block;
362127675Sbms    u_int8_t neighbor_sysid[SYSTEM_ID_LEN];
363127675Sbms};
36498527Sfenner
365127675Sbmsstruct isis_tlv_ip_reach {
366127675Sbms    struct isis_metric_block isis_metric_block;
367127675Sbms    u_int8_t prefix[4];
368127675Sbms    u_int8_t mask[4];
369127675Sbms};
370127675Sbms
371127675Sbmsstatic struct tok isis_is_reach_virtual_values[] = {
372127675Sbms    { 0,    "IsNotVirtual"},
373127675Sbms    { 1,    "IsVirtual"},
374127675Sbms    { 0, NULL }
375127675Sbms};
376127675Sbms
377127675Sbmsstatic struct tok isis_restart_flag_values[] = {
378127675Sbms    { 0x1,  "Restart Request"},
379127675Sbms    { 0x2,  "Restart Acknowledgement"},
380127675Sbms    { 0, NULL }
381127675Sbms};
382127675Sbms
38332149Spststruct isis_common_header {
384127675Sbms    u_int8_t nlpid;
385127675Sbms    u_int8_t fixed_len;
386127675Sbms    u_int8_t version;			/* Protocol version */
387127675Sbms    u_int8_t id_length;
388127675Sbms    u_int8_t pdu_type;		        /* 3 MSbits are reserved */
389127675Sbms    u_int8_t pdu_version;		/* Packet format version */
390127675Sbms    u_int8_t reserved;
391127675Sbms    u_int8_t max_area;
39232149Spst};
39332149Spst
39498527Sfennerstruct isis_iih_lan_header {
395127675Sbms    u_int8_t circuit_type;
396127675Sbms    u_int8_t source_id[SYSTEM_ID_LEN];
397127675Sbms    u_int8_t holding_time[2];
398127675Sbms    u_int8_t pdu_len[2];
399127675Sbms    u_int8_t priority;
400127675Sbms    u_int8_t lan_id[NODE_ID_LEN];
40132149Spst};
40298527Sfenner
40398527Sfennerstruct isis_iih_ptp_header {
404127675Sbms    u_int8_t circuit_type;
405127675Sbms    u_int8_t source_id[SYSTEM_ID_LEN];
406127675Sbms    u_int8_t holding_time[2];
407127675Sbms    u_int8_t pdu_len[2];
408127675Sbms    u_int8_t circuit_id;
40932149Spst};
41032149Spst
41198527Sfennerstruct isis_lsp_header {
412127675Sbms    u_int8_t pdu_len[2];
413127675Sbms    u_int8_t remaining_lifetime[2];
414127675Sbms    u_int8_t lsp_id[LSP_ID_LEN];
415127675Sbms    u_int8_t sequence_number[4];
416127675Sbms    u_int8_t checksum[2];
417127675Sbms    u_int8_t typeblock;
41832149Spst};
41932149Spst
42098527Sfennerstruct isis_csnp_header {
421127675Sbms    u_int8_t pdu_len[2];
422127675Sbms    u_int8_t source_id[NODE_ID_LEN];
423127675Sbms    u_int8_t start_lsp_id[LSP_ID_LEN];
424127675Sbms    u_int8_t end_lsp_id[LSP_ID_LEN];
42598527Sfenner};
42632149Spst
42798527Sfennerstruct isis_psnp_header {
428127675Sbms    u_int8_t pdu_len[2];
429127675Sbms    u_int8_t source_id[NODE_ID_LEN];
43098527Sfenner};
43132149Spst
43298527Sfennerstruct isis_tlv_lsp {
433127675Sbms    u_int8_t remaining_lifetime[2];
434127675Sbms    u_int8_t lsp_id[LSP_ID_LEN];
435127675Sbms    u_int8_t sequence_number[4];
436127675Sbms    u_int8_t checksum[2];
43798527Sfenner};
438127675Sbms
439127675Sbmsstatic char *
440127675Sbmsprint_nsap(register const u_int8_t *pptr, register int nsap_length)
441127675Sbms{
442127675Sbms	int nsap_idx;
443127675Sbms	static char nsap_ascii_output[sizeof("xx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xx")];
444127675Sbms        char *junk_buf = nsap_ascii_output;
445127675Sbms
446127675Sbms        if (nsap_length < 1 || nsap_length > 20) {
447127675Sbms                snprintf(nsap_ascii_output, sizeof(nsap_ascii_output),
448127675Sbms                    "illegal length");
449127675Sbms                return (nsap_ascii_output);
450127675Sbms        }
451127675Sbms
452127675Sbms	for (nsap_idx = 0; nsap_idx < nsap_length; nsap_idx++) {
453127675Sbms		if (!TTEST2(*pptr, 1))
454127675Sbms			return (0);
455127675Sbms		snprintf(junk_buf,
456127675Sbms		    sizeof(nsap_ascii_output) - (junk_buf - nsap_ascii_output),
457127675Sbms		    "%02x", *pptr++);
458127675Sbms		junk_buf += strlen(junk_buf);
459127675Sbms		if (((nsap_idx & 1) == 0) &&
460127675Sbms                     (nsap_idx + 1 < nsap_length)) {
461127675Sbms                     	*junk_buf++ = '.';
462127675Sbms		}
463127675Sbms	}
464127675Sbms        *(junk_buf) = '\0';
465127675Sbms	return (nsap_ascii_output);
466127675Sbms}
467127675Sbms
46898527Sfenner#define ISIS_COMMON_HEADER_SIZE (sizeof(struct isis_common_header))
46998527Sfenner#define ISIS_IIH_LAN_HEADER_SIZE (sizeof(struct isis_iih_lan_header))
47098527Sfenner#define ISIS_IIH_PTP_HEADER_SIZE (sizeof(struct isis_iih_ptp_header))
47198527Sfenner#define ISIS_LSP_HEADER_SIZE (sizeof(struct isis_lsp_header))
47298527Sfenner#define ISIS_CSNP_HEADER_SIZE (sizeof(struct isis_csnp_header))
47398527Sfenner#define ISIS_PSNP_HEADER_SIZE (sizeof(struct isis_psnp_header))
47432149Spst
475127675Sbmsvoid isoclns_print(const u_int8_t *p, u_int length, u_int caplen)
47617680Spst{
47798527Sfenner	const struct isis_common_header *header;
478127675Sbms
47998527Sfenner	header = (const struct isis_common_header *)p;
48032149Spst
481127675Sbms        printf("%sOSI", caplen < 1 ? "|" : "");
48217680Spst
483127675Sbms        if (caplen < 1) /* enough bytes on the wire ? */
484127675Sbms                return;
485127675Sbms
48617680Spst	switch (*p) {
48717680Spst
48817688Spst	case NLPID_CLNS:
489127675Sbms		(void)printf(", CLNS, length %u", length);
49017680Spst		break;
49117680Spst
49217688Spst	case NLPID_ESIS:
49317680Spst		esis_print(p, length);
49417680Spst		return;
49517680Spst
49617688Spst	case NLPID_ISIS:
49717751Spst		if (!isis_print(p, length))
498127675Sbms                        print_unknown_data(p,"\n\t",caplen);
49917680Spst		break;
50017680Spst
50117688Spst	case NLPID_NULLNS:
502127675Sbms		(void)printf(", ISO NULLNS, length: %u", length);
50317680Spst		break;
50417680Spst
50517680Spst	default:
506127675Sbms		(void)printf(", Unknown NLPID 0x%02x, length: %u", p[0], length);
50717680Spst		if (caplen > 1)
508127675Sbms                        print_unknown_data(p,"\n\t",caplen);
50917680Spst		break;
51017680Spst	}
51117680Spst}
51217680Spst
51317680Spst#define	ESIS_REDIRECT	6
51417680Spst#define	ESIS_ESH	2
51517680Spst#define	ESIS_ISH	4
51617680Spst
517127675Sbmsstatic struct tok esis_values[] = {
518127675Sbms    { ESIS_REDIRECT, "redirect"},
519127675Sbms    { ESIS_ESH,      "ESH"},
520127675Sbms    { ESIS_ISH,      "ISH"},
521127675Sbms    { 0, NULL }
522127675Sbms};
523127675Sbms
52417680Spststruct esis_hdr {
525127675Sbms	u_int8_t version;
526127675Sbms	u_int8_t reserved;
527127675Sbms	u_int8_t type;
528127675Sbms	u_int8_t tmo[2];
529127675Sbms	u_int8_t cksum[2];
53017680Spst};
53117680Spst
53217680Spststatic void
533127675Sbmsesis_print(const u_int8_t *p, u_int length)
53417680Spst{
535127675Sbms	const u_int8_t *ep;
53698527Sfenner	u_int li;
53798527Sfenner	const struct esis_hdr *eh;
53817680Spst
53998527Sfenner	if (length <= 2) {
54017680Spst		if (qflag)
54117680Spst			printf(" bad pkt!");
54217680Spst		else
54317680Spst			printf(" no header at all!");
54417680Spst		return;
54517680Spst	}
54698527Sfenner	li = p[1];
54798527Sfenner	eh = (const struct esis_hdr *) &p[2];
54817680Spst	ep = p + li;
54917680Spst	if (li > length) {
55017680Spst		if (qflag)
55117680Spst			printf(" bad pkt!");
55217680Spst		else
55317680Spst			printf(" LI(%d) > PDU size (%d)!", li, length);
55417680Spst		return;
55517680Spst	}
55617680Spst	if (li < sizeof(struct esis_hdr) + 2) {
55717680Spst		if (qflag)
55817680Spst			printf(" bad pkt!");
55917680Spst		else {
56017680Spst			printf(" too short for esis header %d:", li);
56139300Sfenner			while (--length != 0)
56217680Spst				printf("%02X", *p++);
56317680Spst		}
56417680Spst		return;
56517680Spst	}
56617680Spst
567127675Sbms        printf(", ES-IS, %s, length %u",
568127675Sbms               tok2str(esis_values,"unknown type: %u",eh->type & 0x1f),
569127675Sbms               length);
57017680Spst
571127675Sbms        if(vflag < 1)
572127675Sbms               return;
57317680Spst
574127675Sbms	if (vflag && osi_cksum(p, li)) {
575127675Sbms		printf(" bad cksum (got 0x%02x%02x)",
57617751Spst		       eh->cksum[1], eh->cksum[0]);
57717751Spst		default_print(p, length);
57817680Spst		return;
57917680Spst	}
58017680Spst	if (eh->version != 1) {
58117680Spst		printf(" unsupported version %d", eh->version);
58217680Spst		return;
58317680Spst	}
58417680Spst	p += sizeof(*eh) + 2;
58517680Spst	li -= sizeof(*eh) + 2;	/* protoid * li */
58617680Spst
58717680Spst	switch (eh->type & 0x1f) {
58817680Spst	case ESIS_REDIRECT: {
589127675Sbms		const u_int8_t *dst, *snpa, *is;
59017680Spst
59117680Spst		dst = p; p += *p + 1;
59217680Spst		if (p > snapend)
59317680Spst			return;
594127675Sbms		printf("\n\t\t %s", isonsap_string(dst));
59517680Spst		snpa = p; p += *p + 1;
59617680Spst		is = p;   p += *p + 1;
59717680Spst		if (p > snapend)
59817680Spst			return;
59917680Spst		if (p > ep) {
60017680Spst			printf(" [bad li]");
60117680Spst			return;
60217680Spst		}
60317680Spst		if (is[0] == 0)
60417680Spst			printf(" > %s", etheraddr_string(&snpa[1]));
60517680Spst		else
60617680Spst			printf(" > %s", isonsap_string(is));
60717680Spst		li = ep - p;
60817680Spst		break;
60917680Spst	}
610127675Sbms
61117680Spst	case ESIS_ESH:
61217680Spst		break;
613127675Sbms
61417680Spst	case ESIS_ISH: {
615127675Sbms		const u_int8_t *is;
61617680Spst
61717680Spst		is = p; p += *p + 1;
61817680Spst		if (p > ep) {
61917680Spst			printf(" [bad li]");
62017680Spst			return;
62117680Spst		}
62217680Spst		if (p > snapend)
62317680Spst			return;
62417751Spst		if (!qflag)
625127675Sbms			printf("\n\tNET: %s", print_nsap(is+1,*is));
62617680Spst		li = ep - p;
62717680Spst		break;
62817680Spst	}
62917680Spst
63017680Spst	default:
631127675Sbms            if (vflag <= 1) {
632127675Sbms		    if (p < snapend)
633127675Sbms                            print_unknown_data(p,"\n\t  ",snapend-p);
634127675Sbms            }
635127675Sbms            return;
63617680Spst	}
637127675Sbms
638127675Sbms        /* hexdump - FIXME ? */
639127675Sbms        if (vflag > 1) {
640127675Sbms                    if (p < snapend)
641127675Sbms                            print_unknown_data(p,"\n\t  ",snapend-p);
642127675Sbms        }
64317680Spst	if (vflag)
64417680Spst		while (p < ep && li) {
64598527Sfenner			u_int op, opli;
646127675Sbms			const u_int8_t *q;
64717680Spst
64817680Spst			if (snapend - p < 2)
64917680Spst				return;
65017680Spst			if (li < 2) {
651127675Sbms				printf(", bad opts/li");
65217680Spst				return;
65317680Spst			}
65417680Spst			op = *p++;
65517680Spst			opli = *p++;
65617680Spst			li -= 2;
65717680Spst			if (opli > li) {
658127675Sbms				printf(", opt (%d) too long", op);
65917680Spst				return;
66017680Spst			}
66117680Spst			li -= opli;
66217680Spst			q = p;
66317680Spst			p += opli;
664127675Sbms
66517680Spst			if (snapend < p)
66617680Spst				return;
667127675Sbms
668127675Sbms			if (op == TLV_HOLDTIME && opli == 2) {
669127675Sbms				printf("\n\tholdtime: %us", EXTRACT_16BITS(q));
67017680Spst				continue;
67117680Spst			}
672127675Sbms
673127675Sbms			if (op == TLV_PROTOCOLS && opli >= 1) {
674127675Sbms				printf("\n\t%s (length: %u): %s",
675127675Sbms                                       tok2str(isis_tlv_values, "unknown", op),
676127675Sbms                                       opli,
677127675Sbms                                       tok2str(osi_nlpid_values,"Unknown 0x%02x",*q));
678127675Sbms				continue;
679127675Sbms			}
680127675Sbms
681127675Sbms                        print_unknown_data(q,"\n\t  ",opli);
68217680Spst		}
68317680Spst}
68417680Spst
685127675Sbms/* shared routine for printing system, node and lsp-ids */
686127675Sbmsstatic char *
687127675Sbmsisis_print_id(const u_int8_t *cp, int id_len)
68898527Sfenner{
689127675Sbms    int i;
690127675Sbms    static char id[sizeof("xxxx.xxxx.xxxx.yy-zz")];
691127675Sbms    char *pos = id;
69217688Spst
693127675Sbms    for (i = 1; i <= SYSTEM_ID_LEN; i++) {
694127675Sbms        snprintf(pos, sizeof(id) - (pos - id), "%02x", *cp++);
695127675Sbms	pos += strlen(pos);
696127675Sbms	if (i == 2 || i == 4)
697127675Sbms	    *pos++ = '.';
69898527Sfenner	}
699127675Sbms    if (id_len >= NODE_ID_LEN) {
700127675Sbms        snprintf(pos, sizeof(id) - (pos - id), ".%02x", *cp++);
701127675Sbms	pos += strlen(pos);
702127675Sbms    }
703127675Sbms    if (id_len == LSP_ID_LEN)
704127675Sbms        snprintf(pos, sizeof(id) - (pos - id), "-%02x", *cp);
705127675Sbms    return (id);
70698527Sfenner}
70798527Sfenner
708127675Sbms/* print the 4-byte metric block which is common found in the old-style TLVs */
70998527Sfennerstatic int
710127675Sbmsisis_print_metric_block (const struct isis_metric_block *isis_metric_block)
71198527Sfenner{
712127675Sbms    printf(", Default Metric: %d, %s",
713127675Sbms           ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_default),
714127675Sbms           ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_default) ? "External" : "Internal");
715127675Sbms    if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_delay))
716127675Sbms        printf("\n\t\t  Delay Metric: %d, %s",
717127675Sbms               ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_delay),
718127675Sbms               ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_delay) ? "External" : "Internal");
719127675Sbms    if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_expense))
720127675Sbms        printf("\n\t\t  Expense Metric: %d, %s",
721127675Sbms               ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_expense),
722127675Sbms               ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_expense) ? "External" : "Internal");
723127675Sbms    if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_error))
724127675Sbms        printf("\n\t\t  Error Metric: %d, %s",
725127675Sbms               ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_error),
726127675Sbms               ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_error) ? "External" : "Internal");
72798527Sfenner
728127675Sbms    return(1); /* everything is ok */
72998527Sfenner}
73098527Sfenner
73198527Sfennerstatic int
732127675Sbmsisis_print_tlv_ip_reach (const u_int8_t *cp, const char *ident, int length)
73398527Sfenner{
734127675Sbms	int prefix_len;
735127675Sbms	const struct isis_tlv_ip_reach *tlv_ip_reach;
73698527Sfenner
737127675Sbms	tlv_ip_reach = (const struct isis_tlv_ip_reach *)cp;
738127675Sbms
739127675Sbms	while (length > 0) {
740127675Sbms		if ((size_t)length < sizeof(*tlv_ip_reach)) {
741127675Sbms			printf("short IPv4 Reachability (%d vs %lu)",
742127675Sbms                               length,
743127675Sbms                               (unsigned long)sizeof(*tlv_ip_reach));
74498527Sfenner			return (0);
74598527Sfenner		}
746127675Sbms
747127675Sbms		if (!TTEST(*tlv_ip_reach))
748127675Sbms		    return (0);
749127675Sbms
750127675Sbms		prefix_len = mask2plen(EXTRACT_32BITS(tlv_ip_reach->mask));
751127675Sbms
752127675Sbms		if (prefix_len == -1)
753127675Sbms			printf("%sIPv4 prefix: %s mask %s",
754127675Sbms                               ident,
755127675Sbms			       ipaddr_string((tlv_ip_reach->prefix)),
756127675Sbms			       ipaddr_string((tlv_ip_reach->mask)));
757127675Sbms		else
758127675Sbms			printf("%sIPv4 prefix: %15s/%u",
759127675Sbms                               ident,
760127675Sbms			       ipaddr_string((tlv_ip_reach->prefix)),
761127675Sbms			       prefix_len);
762127675Sbms
763127675Sbms		printf(", Distribution: %s, Metric: %u, %s",
764127675Sbms                       ISIS_LSP_TLV_METRIC_UPDOWN(tlv_ip_reach->isis_metric_block.metric_default) ? "down" : "up",
765127675Sbms                       ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_default),
766127675Sbms                       ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_default) ? "External" : "Internal");
767127675Sbms
768127675Sbms		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_delay))
769127675Sbms                    printf("%s  Delay Metric: %u, %s",
770127675Sbms                           ident,
771127675Sbms                           ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_delay),
772127675Sbms                           ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_delay) ? "External" : "Internal");
773127675Sbms
774127675Sbms		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_expense))
775127675Sbms                    printf("%s  Expense Metric: %u, %s",
776127675Sbms                           ident,
777127675Sbms                           ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_expense),
778127675Sbms                           ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_expense) ? "External" : "Internal");
779127675Sbms
780127675Sbms		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_error))
781127675Sbms                    printf("%s  Error Metric: %u, %s",
782127675Sbms                           ident,
783127675Sbms                           ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_error),
784127675Sbms                           ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_error) ? "External" : "Internal");
785127675Sbms
786127675Sbms		length -= sizeof(struct isis_tlv_ip_reach);
787127675Sbms		tlv_ip_reach++;
78898527Sfenner	}
78998527Sfenner	return (1);
79098527Sfenner}
79198527Sfenner
792127675Sbms/*
793127675Sbms * this is the common IP-REACH subTLV decoder it is called
794127675Sbms * from various EXTD-IP REACH TLVs (135,235,236,237)
795127675Sbms */
79698527Sfenner
797127675Sbmsstatic int
798127675Sbmsisis_print_ip_reach_subtlv (const u_int8_t *tptr,int subt,int subl,const char *ident) {
799127675Sbms
800127675Sbms        /* first lets see if we know the subTLVs name*/
801127675Sbms	printf("%s%s subTLV #%u, length: %u",
802127675Sbms	       ident,
803127675Sbms               tok2str(isis_ext_ip_reach_subtlv_values,
804127675Sbms                       "unknown",
805127675Sbms                       subt),
806127675Sbms               subt,
807127675Sbms               subl);
808127675Sbms
809127675Sbms	if (!TTEST2(*tptr,subl))
810127675Sbms	    goto trunctlv;
811127675Sbms
812127675Sbms    switch(subt) {
813127675Sbms    case SUBTLV_EXTD_IP_REACH_ADMIN_TAG32:
814127675Sbms        while (subl >= 4) {
815127675Sbms	    printf(", 0x%08x (=%u)",
816127675Sbms		   EXTRACT_32BITS(tptr),
817127675Sbms		   EXTRACT_32BITS(tptr));
818127675Sbms	    tptr+=4;
819127675Sbms	    subl-=4;
82017688Spst	}
821127675Sbms	break;
822127675Sbms    case SUBTLV_EXTD_IP_REACH_ADMIN_TAG64:
823127675Sbms        while (subl >= 8) {
824127675Sbms	    printf(", 0x%08x%08x",
825127675Sbms		   EXTRACT_32BITS(tptr),
826127675Sbms		   EXTRACT_32BITS(tptr+4));
827127675Sbms	    tptr+=8;
828127675Sbms	    subl-=8;
829127675Sbms	}
830127675Sbms	break;
831127675Sbms    default:
832127675Sbms	if(!print_unknown_data(tptr,"\n\t\t    ",
833127675Sbms			       subl))
834127675Sbms	  return(0);
835127675Sbms	break;
836127675Sbms    }
837127675Sbms    return(1);
838127675Sbms
839127675Sbmstrunctlv:
840127675Sbms    printf("%spacket exceeded snapshot",ident);
841127675Sbms    return(0);
84298527Sfenner}
84317688Spst
844127675Sbms/*
845127675Sbms * this is the common IS-REACH subTLV decoder it is called
846127675Sbms * from isis_print_ext_is_reach()
847127675Sbms */
848127675Sbms
84998527Sfennerstatic int
850127675Sbmsisis_print_is_reach_subtlv (const u_int8_t *tptr,int subt,int subl,const char *ident) {
85198527Sfenner
852127675Sbms        int priority_level;
853127675Sbms        union { /* int to float conversion buffer for several subTLVs */
854127675Sbms            float f;
855127675Sbms            u_int32_t i;
856127675Sbms        } bw;
85798527Sfenner
858127675Sbms        /* first lets see if we know the subTLVs name*/
859127675Sbms	printf("%s%s subTLV #%u, length: %u",
860127675Sbms	       ident,
861127675Sbms               tok2str(isis_ext_is_reach_subtlv_values,
862127675Sbms                       "unknown",
863127675Sbms                       subt),
864127675Sbms               subt,
865127675Sbms               subl);
86698527Sfenner
867127675Sbms	if (!TTEST2(*tptr,subl))
868127675Sbms	    goto trunctlv;
86998527Sfenner
870127675Sbms        switch(subt) {
871127675Sbms        case SUBTLV_EXT_IS_REACH_ADMIN_GROUP:
872127675Sbms        case SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID:
873127675Sbms        case SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID:
874127675Sbms	    if (subl >= 4) {
875127675Sbms	      printf(", 0x%08x", EXTRACT_32BITS(tptr));
876127675Sbms	      if (subl == 8) /* draft-ietf-isis-gmpls-extensions */
877127675Sbms	        printf(", 0x%08x", EXTRACT_32BITS(tptr+4));
878127675Sbms	    }
879127675Sbms	    break;
880127675Sbms        case SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR:
881127675Sbms        case SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR:
882127675Sbms            if (subl >= 4)
883127675Sbms              printf(", %s", ipaddr_string(tptr));
884127675Sbms            break;
885127675Sbms        case SUBTLV_EXT_IS_REACH_MAX_LINK_BW :
886127675Sbms	case SUBTLV_EXT_IS_REACH_RESERVABLE_BW:
887127675Sbms            if (subl >= 4) {
888127675Sbms              bw.i = EXTRACT_32BITS(tptr);
889127675Sbms              printf(", %.3f Mbps", bw.f*8/1000000 );
890127675Sbms            }
891127675Sbms            break;
892127675Sbms        case SUBTLV_EXT_IS_REACH_UNRESERVED_BW :
893127675Sbms            if (subl >= 32) {
894127675Sbms              for (priority_level = 0; priority_level < 8; priority_level++) {
895127675Sbms                bw.i = EXTRACT_32BITS(tptr);
896127675Sbms                printf("%s  priority level %d: %.3f Mbps",
897127675Sbms                       ident,
898127675Sbms                       priority_level,
899127675Sbms                       bw.f*8/1000000 );
900127675Sbms		tptr+=4;
901127675Sbms	      }
902127675Sbms            }
903127675Sbms            break;
904127675Sbms        case SUBTLV_EXT_IS_REACH_TE_METRIC:
905127675Sbms            if (subl >= 3)
906127675Sbms              printf(", %u", EXTRACT_24BITS(tptr));
907127675Sbms            break;
908127675Sbms        case SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE:
909127675Sbms            if (subl >= 2) {
910127675Sbms              printf(", %s, Priority %u",
911127675Sbms		   bittok2str(gmpls_link_prot_values, "none", *tptr),
912127675Sbms                   *(tptr+1));
913127675Sbms            }
914127675Sbms            break;
915127675Sbms        case SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR:
916127675Sbms            if (subl >= 36) {
917127675Sbms              printf("%s  Interface Switching Capability:%s",
918127675Sbms                   ident,
919127675Sbms                   tok2str(gmpls_switch_cap_values, "Unknown", *(tptr)));
920127675Sbms              printf(", LSP Encoding: %s",
921127675Sbms                   tok2str(gmpls_encoding_values, "Unknown", *(tptr+1)));
922127675Sbms	      tptr+=4;
923127675Sbms              printf("%s  Max LSP Bandwidth:",ident);
924127675Sbms              for (priority_level = 0; priority_level < 8; priority_level++) {
925127675Sbms                bw.i = EXTRACT_32BITS(tptr);
926127675Sbms                printf("%s    priority level %d: %.3f Mbps",
927127675Sbms                       ident,
928127675Sbms                       priority_level,
929127675Sbms                       bw.f*8/1000000 );
930127675Sbms		tptr+=4;
931127675Sbms              }
932127675Sbms              subl-=36;
933127675Sbms              /* there is some optional stuff left to decode but this is as of yet
934127675Sbms                 not specified so just lets hexdump what is left */
935127675Sbms              if(subl>0){
936127675Sbms                if(!print_unknown_data(tptr,"\n\t\t    ",
937127675Sbms				       subl-36))
938127675Sbms                    return(0);
939127675Sbms              }
940127675Sbms            }
941127675Sbms            break;
942127675Sbms        default:
943127675Sbms            if(!print_unknown_data(tptr,"\n\t\t    ",
944127675Sbms				   subl))
945127675Sbms                return(0);
946127675Sbms            break;
947127675Sbms        }
948127675Sbms        return(1);
94998527Sfenner
950127675Sbmstrunctlv:
951127675Sbms    printf("%spacket exceeded snapshot",ident);
952127675Sbms    return(0);
953127675Sbms}
95498527Sfenner
95598527Sfenner
956127675Sbms/*
957127675Sbms * this is the common IS-REACH decoder it is called
958127675Sbms * from various EXTD-IS REACH style TLVs (22,24,222)
959127675Sbms */
96098527Sfenner
961127675Sbmsstatic int
962127675Sbmsisis_print_ext_is_reach (const u_int8_t *tptr,const char *ident, int tlv_type) {
96398527Sfenner
964127675Sbms    char ident_buffer[20];
965127675Sbms    int subtlv_type,subtlv_len,subtlv_sum_len;
966127675Sbms    int proc_bytes = 0; /* how many bytes did we process ? */
967127675Sbms
968127675Sbms    if (!TTEST2(*tptr, NODE_ID_LEN))
969127675Sbms        return(0);
97098527Sfenner
971127675Sbms    printf("%sIS Neighbor: %s", ident, isis_print_id(tptr, NODE_ID_LEN));
972127675Sbms    tptr+=(NODE_ID_LEN);
97398527Sfenner
974127675Sbms    if (tlv_type != TLV_IS_ALIAS_ID) { /* the Alias TLV Metric field is implicit 0 */
975127675Sbms        if (!TTEST2(*tptr, 3))    /* and is therefore skipped */
976127675Sbms	    return(0);
977127675Sbms	printf(", Metric: %d",EXTRACT_24BITS(tptr));
978127675Sbms	tptr+=3;
979127675Sbms    }
980127675Sbms
981127675Sbms    if (!TTEST2(*tptr, 1))
982127675Sbms        return(0);
983127675Sbms    subtlv_sum_len=*(tptr++); /* read out subTLV length */
984127675Sbms    proc_bytes=NODE_ID_LEN+3+1;
985127675Sbms    printf(", %ssub-TLVs present",subtlv_sum_len ? "" : "no ");
986127675Sbms    if (subtlv_sum_len) {
987127675Sbms        printf(" (%u)",subtlv_sum_len);
988127675Sbms        while (subtlv_sum_len>0) {
989127675Sbms            if (!TTEST2(*tptr,2))
990127675Sbms                return(0);
991127675Sbms            subtlv_type=*(tptr++);
992127675Sbms            subtlv_len=*(tptr++);
993127675Sbms            /* prepend the ident string */
994127675Sbms            snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
995127675Sbms            if(!isis_print_is_reach_subtlv(tptr,subtlv_type,subtlv_len,ident_buffer))
996127675Sbms                return(0);
997127675Sbms            tptr+=subtlv_len;
998127675Sbms            subtlv_sum_len-=(subtlv_len+2);
999127675Sbms            proc_bytes+=(subtlv_len+2);
1000127675Sbms        }
1001127675Sbms    }
1002127675Sbms    return(proc_bytes);
100317688Spst}
100417688Spst
100517688Spst/*
1006127675Sbms * this is the common Multi Topology ID decoder
1007127675Sbms * it is called from various MT-TLVs (222,229,235,237)
1008127675Sbms */
1009127675Sbms
1010127675Sbmsstatic int
1011127675Sbmsisis_print_mtid (const u_int8_t *tptr,const char *ident) {
1012127675Sbms
1013127675Sbms    if (!TTEST2(*tptr, 2))
1014127675Sbms        return(0);
1015127675Sbms
1016127675Sbms    printf("%s%s",
1017127675Sbms           ident,
1018127675Sbms           tok2str(isis_mt_values,
1019127675Sbms                   "Reserved for IETF Consensus",
1020127675Sbms                   ISIS_MASK_MTID(EXTRACT_16BITS(tptr))));
1021127675Sbms
1022127675Sbms    printf(" Topology (0x%03x), Flags: [%s]",
1023127675Sbms           ISIS_MASK_MTID(EXTRACT_16BITS(tptr)),
1024127675Sbms           bittok2str(isis_mt_flag_values, "none",ISIS_MASK_MTFLAGS(EXTRACT_16BITS(tptr))));
1025127675Sbms
1026127675Sbms    return(2);
1027127675Sbms}
1028127675Sbms
1029127675Sbms/*
1030127675Sbms * this is the common extended IP reach decoder
1031127675Sbms * it is called from TLVs (135,235,236,237)
1032127675Sbms * we process the TLV and optional subTLVs and return
1033127675Sbms * the amount of processed bytes
1034127675Sbms */
1035127675Sbms
1036127675Sbmsstatic int
1037127675Sbmsisis_print_extd_ip_reach (const u_int8_t *tptr, const char *ident, u_int16_t afi) {
1038127675Sbms
1039127675Sbms    char ident_buffer[20];
1040127675Sbms    u_int8_t prefix[16]; /* shared copy buffer for IPv4 and IPv6 prefixes */
1041127675Sbms    u_int metric, status_byte, bit_length, byte_length, sublen, processed, subtlvtype, subtlvlen;
1042127675Sbms
1043127675Sbms    if (!TTEST2(*tptr, 4))
1044127675Sbms        return (0);
1045127675Sbms    metric = EXTRACT_32BITS(tptr);
1046127675Sbms    processed=4;
1047127675Sbms    tptr+=4;
1048127675Sbms
1049127675Sbms    if (afi == IPV4) {
1050127675Sbms        if (!TTEST2(*tptr, 1)) /* fetch status byte */
1051127675Sbms            return (0);
1052127675Sbms        status_byte=*(tptr++);
1053127675Sbms        bit_length = status_byte&0x3f;
1054127675Sbms        processed++;
1055127675Sbms#ifdef INET6
1056127675Sbms    } else if (afi == IPV6) {
1057127675Sbms        if (!TTEST2(*tptr, 1)) /* fetch status & prefix_len byte */
1058127675Sbms            return (0);
1059127675Sbms        status_byte=*(tptr++);
1060127675Sbms        bit_length=*(tptr++);
1061127675Sbms        processed+=2;
1062127675Sbms#endif
1063127675Sbms    } else
1064127675Sbms        return (0); /* somebody is fooling us */
1065127675Sbms
1066127675Sbms    byte_length = (bit_length + 7) / 8; /* prefix has variable length encoding */
1067127675Sbms
1068127675Sbms    if (!TTEST2(*tptr, byte_length))
1069127675Sbms        return (0);
1070127675Sbms    memset(prefix, 0, 16);              /* clear the copy buffer */
1071127675Sbms    memcpy(prefix,tptr,byte_length);    /* copy as much as is stored in the TLV */
1072127675Sbms    tptr+=byte_length;
1073127675Sbms    processed+=byte_length;
1074127675Sbms
1075127675Sbms    if (afi == IPV4)
1076127675Sbms        printf("%sIPv4 prefix: %15s/%u",
1077127675Sbms               ident,
1078127675Sbms               ipaddr_string(prefix),
1079127675Sbms               bit_length);
1080127675Sbms#ifdef INET6
1081127675Sbms    if (afi == IPV6)
1082127675Sbms        printf("%sIPv6 prefix: %s/%u",
1083127675Sbms               ident,
1084127675Sbms               ip6addr_string(prefix),
1085127675Sbms               bit_length);
1086127675Sbms#endif
1087127675Sbms
1088127675Sbms    printf(", Distribution: %s, Metric: %u",
1089127675Sbms           ISIS_MASK_TLV_EXTD_IP_UPDOWN(status_byte) ? "down" : "up",
1090127675Sbms           metric);
1091127675Sbms
1092127675Sbms    if (afi == IPV4 && ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte))
1093127675Sbms        printf(", sub-TLVs present");
1094127675Sbms#ifdef INET6
1095127675Sbms    if (afi == IPV6)
1096127675Sbms        printf(", %s%s",
1097127675Sbms               ISIS_MASK_TLV_EXTD_IP6_IE(status_byte) ? "External" : "Internal",
1098127675Sbms               ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte) ? ", sub-TLVs present" : "");
1099127675Sbms#endif
1100127675Sbms
1101127675Sbms    if ((ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte)  && afi == IPV4) ||
1102127675Sbms        (ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte) && afi == IPV6)) {
1103127675Sbms        /* assume that one prefix can hold more
1104127675Sbms           than one subTLV - therefore the first byte must reflect
1105127675Sbms           the aggregate bytecount of the subTLVs for this prefix
1106127675Sbms        */
1107127675Sbms        if (!TTEST2(*tptr, 1))
1108127675Sbms            return (0);
1109127675Sbms        sublen=*(tptr++);
1110127675Sbms        processed+=sublen+1;
1111127675Sbms        printf(" (%u)",sublen);   /* print out subTLV length */
1112127675Sbms
1113127675Sbms        while (sublen>0) {
1114127675Sbms            if (!TTEST2(*tptr,2))
1115127675Sbms                return (0);
1116127675Sbms            subtlvtype=*(tptr++);
1117127675Sbms            subtlvlen=*(tptr++);
1118127675Sbms            /* prepend the ident string */
1119127675Sbms            snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
1120127675Sbms            if(!isis_print_ip_reach_subtlv(tptr,subtlvtype,subtlvlen,ident_buffer))
1121127675Sbms                return(0);
1122127675Sbms            tptr+=subtlvlen;
1123127675Sbms            sublen-=(subtlvlen+2);
1124127675Sbms        }
1125127675Sbms    }
1126127675Sbms    return (processed);
1127127675Sbms}
1128127675Sbms
1129127675Sbms/*
113017688Spst * isis_print
113117688Spst * Decode IS-IS packets.  Return 0 on error.
113217688Spst */
113317688Spst
1134127675Sbmsstatic int isis_print (const u_int8_t *p, u_int length)
113517688Spst{
113698527Sfenner    const struct isis_common_header *header;
113717688Spst
113898527Sfenner    const struct isis_iih_lan_header *header_iih_lan;
113998527Sfenner    const struct isis_iih_ptp_header *header_iih_ptp;
114098527Sfenner    const struct isis_lsp_header *header_lsp;
114198527Sfenner    const struct isis_csnp_header *header_csnp;
114298527Sfenner    const struct isis_psnp_header *header_psnp;
114317688Spst
114498527Sfenner    const struct isis_tlv_lsp *tlv_lsp;
114598527Sfenner    const struct isis_tlv_ptp_adj *tlv_ptp_adj;
114698527Sfenner    const struct isis_tlv_is_reach *tlv_is_reach;
1147127675Sbms    const struct isis_tlv_es_reach *tlv_es_reach;
114898527Sfenner
1149127675Sbms    u_int8_t pdu_type, max_area, id_length, tlv_type, tlv_len, tmp, alen, lan_alen, prefix_len;
1150127675Sbms    u_int8_t ext_is_len, ext_ip_len, mt_len;
1151127675Sbms    const u_int8_t *optr, *pptr, *tptr;
115298527Sfenner    u_short packet_len,pdu_len;
1153127675Sbms    u_int i;
115498527Sfenner
115598527Sfenner    packet_len=length;
1156127675Sbms    optr = p; /* initialize the _o_riginal pointer to the packet start -
1157127675Sbms                 need it for parsing the checksum TLV */
1158127675Sbms    header = (const struct isis_common_header *)p;
115998527Sfenner    TCHECK(*header);
1160127675Sbms    pptr = p+(ISIS_COMMON_HEADER_SIZE);
116198527Sfenner    header_iih_lan = (const struct isis_iih_lan_header *)pptr;
116298527Sfenner    header_iih_ptp = (const struct isis_iih_ptp_header *)pptr;
116398527Sfenner    header_lsp = (const struct isis_lsp_header *)pptr;
116498527Sfenner    header_csnp = (const struct isis_csnp_header *)pptr;
116598527Sfenner    header_psnp = (const struct isis_psnp_header *)pptr;
1166127675Sbms
116717688Spst    /*
116817688Spst     * Sanity checking of the header.
116917688Spst     */
117017688Spst
117117688Spst    if (header->version != ISIS_VERSION) {
117298527Sfenner	printf(", version %d packet not supported", header->version);
117398527Sfenner	return (0);
117417688Spst    }
117517688Spst
117617688Spst    if ((header->id_length != SYSTEM_ID_LEN) && (header->id_length != 0)) {
117798527Sfenner	printf(", system ID length of %d is not supported",
117817688Spst	       header->id_length);
117998527Sfenner	return (0);
118017688Spst    }
1181127675Sbms
1182127675Sbms    if (header->pdu_version != ISIS_VERSION) {
1183127675Sbms	printf(", version %d packet not supported", header->pdu_version);
118498527Sfenner	return (0);
118517688Spst    }
118617688Spst
118798527Sfenner    max_area = header->max_area;
118817688Spst    switch(max_area) {
118917688Spst    case 0:
1190127675Sbms	max_area = 3;	 /* silly shit */
119117688Spst	break;
119217688Spst    case 255:
119398527Sfenner	printf(", bad packet -- 255 areas");
119498527Sfenner	return (0);
119517688Spst    default:
119617688Spst	break;
119717688Spst    }
119817688Spst
1199127675Sbms    id_length = header->id_length;
1200127675Sbms    switch(id_length) {
1201127675Sbms    case 0:
1202127675Sbms        id_length = 6;	 /* silly shit again */
1203127675Sbms	break;
1204127675Sbms    case 1:              /* 1-8 are valid sys-ID lenghts */
1205127675Sbms    case 2:
1206127675Sbms    case 3:
1207127675Sbms    case 4:
1208127675Sbms    case 5:
1209127675Sbms    case 6:
1210127675Sbms    case 7:
1211127675Sbms    case 8:
1212127675Sbms        break;
1213127675Sbms    case 255:
1214127675Sbms        id_length = 0;   /* entirely useless */
1215127675Sbms	break;
1216127675Sbms    default:
1217127675Sbms        break;
1218127675Sbms    }
1219127675Sbms
1220127675Sbms    /* toss any non 6-byte sys-ID len PDUs */
1221127675Sbms    if (id_length != 6 ) {
1222127675Sbms	printf(", bad packet -- illegal sys-ID length (%u)", id_length);
1223127675Sbms	return (0);
1224127675Sbms    }
1225127675Sbms
1226127675Sbms    pdu_type=header->pdu_type;
1227127675Sbms
1228127675Sbms    /* in non-verbose mode print the basic PDU Type plus PDU specific brief information*/
1229127675Sbms    if (vflag < 1) {
1230127675Sbms        printf(", IS-IS, %s",
1231127675Sbms               tok2str(isis_pdu_values,"unknown PDU-Type %u",pdu_type));
1232127675Sbms
1233127675Sbms	switch (pdu_type) {
1234127675Sbms
1235127675Sbms	case L1_LAN_IIH:
1236127675Sbms	case L2_LAN_IIH:
1237127675Sbms	    printf(", src-id %s",
1238127675Sbms                   isis_print_id(header_iih_lan->source_id,SYSTEM_ID_LEN));
1239127675Sbms	    printf(", lan-id %s, prio %u",
1240127675Sbms                   isis_print_id(header_iih_lan->lan_id,NODE_ID_LEN),
1241127675Sbms                   header_iih_lan->priority);
1242127675Sbms	    break;
1243127675Sbms	case PTP_IIH:
1244127675Sbms	    printf(", src-id %s", isis_print_id(header_iih_ptp->source_id,SYSTEM_ID_LEN));
1245127675Sbms	    break;
1246127675Sbms	case L1_LSP:
1247127675Sbms	case L2_LSP:
1248127675Sbms	    printf(", lsp-id %s, seq 0x%08x, lifetime %5us",
1249127675Sbms		   isis_print_id(header_lsp->lsp_id, LSP_ID_LEN),
1250127675Sbms		   EXTRACT_32BITS(header_lsp->sequence_number),
1251127675Sbms		   EXTRACT_16BITS(header_lsp->remaining_lifetime));
1252127675Sbms	    break;
1253127675Sbms	case L1_CSNP:
1254127675Sbms	case L2_CSNP:
1255127675Sbms	    printf(", src-id %s", isis_print_id(header_csnp->source_id,SYSTEM_ID_LEN));
1256127675Sbms	    break;
1257127675Sbms	case L1_PSNP:
1258127675Sbms	case L2_PSNP:
1259127675Sbms	    printf(", src-id %s", isis_print_id(header_psnp->source_id,SYSTEM_ID_LEN));
1260127675Sbms	    break;
1261127675Sbms
1262127675Sbms	}
1263127675Sbms	printf(", length %u", length);
1264127675Sbms
1265127675Sbms        return(1);
1266127675Sbms    }
1267127675Sbms
1268127675Sbms    /* ok they seem to want to know everything - lets fully decode it */
1269127675Sbms    printf(", IS-IS, length: %u",length);
1270127675Sbms
1271127675Sbms    printf("\n\t%s, hlen: %u, v: %u, pdu-v: %u, sys-id-len: %u (%u), max-area: %u (%u)",
1272127675Sbms           tok2str(isis_pdu_values,
1273127675Sbms                   "unknown, type %u",
1274127675Sbms                   pdu_type),
127598527Sfenner           header->fixed_len,
1276127675Sbms           header->version,
1277127675Sbms           header->pdu_version,
1278127675Sbms	   id_length,
1279127675Sbms	   header->id_length,
128098527Sfenner           max_area,
128198527Sfenner           header->max_area);
1282127675Sbms
1283127675Sbms    if (vflag > 1) {
1284127675Sbms        if(!print_unknown_data(optr,"\n\t",8)) /* provide the _o_riginal pointer */
1285127675Sbms            return(0);                         /* for optionally debugging the common header */
1286127675Sbms    }
1287127675Sbms
128898527Sfenner    switch (pdu_type) {
128998527Sfenner
1290127675Sbms    case L1_LAN_IIH:
129198527Sfenner    case L2_LAN_IIH:
129298527Sfenner	if (header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE)) {
129398527Sfenner	    printf(", bogus fixed header length %u should be %lu",
129498527Sfenner		   header->fixed_len, (unsigned long)ISIS_IIH_LAN_HEADER_SIZE);
129598527Sfenner	    return (0);
129617688Spst	}
129798527Sfenner
129898527Sfenner	pdu_len=EXTRACT_16BITS(header_iih_lan->pdu_len);
129998527Sfenner	if (packet_len>pdu_len) {
1300127675Sbms            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1301127675Sbms            length=pdu_len;
130298527Sfenner	}
130398527Sfenner
130498527Sfenner	TCHECK(*header_iih_lan);
1305127675Sbms	printf("\n\t  source-id: %s,  holding time: %us, Flags: [%s]",
1306127675Sbms               isis_print_id(header_iih_lan->source_id,SYSTEM_ID_LEN),
1307127675Sbms               EXTRACT_16BITS(header_iih_lan->holding_time),
1308127675Sbms               tok2str(isis_iih_circuit_type_values,
1309127675Sbms                       "unknown circuit type 0x%02x",
1310127675Sbms                       header_iih_lan->circuit_type));
131198527Sfenner
1312127675Sbms	printf("\n\t  lan-id:    %s, Priority: %u, PDU length: %u",
1313127675Sbms               isis_print_id(header_iih_lan->lan_id, NODE_ID_LEN),
1314127675Sbms               (header_iih_lan->priority) & PRIORITY_MASK,
1315127675Sbms               pdu_len);
131698527Sfenner
1317127675Sbms        if (vflag > 1) {
1318127675Sbms            if(!print_unknown_data(pptr,"\n\t  ",ISIS_IIH_LAN_HEADER_SIZE))
1319127675Sbms                return(0);
1320127675Sbms        }
132198527Sfenner
132298527Sfenner	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
132398527Sfenner	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
132417688Spst	break;
132598527Sfenner
132698527Sfenner    case PTP_IIH:
132798527Sfenner	if (header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE)) {
132898527Sfenner	    printf(", bogus fixed header length %u should be %lu",
132998527Sfenner		   header->fixed_len, (unsigned long)ISIS_IIH_PTP_HEADER_SIZE);
133098527Sfenner	    return (0);
133117688Spst	}
1332127675Sbms
133398527Sfenner	pdu_len=EXTRACT_16BITS(header_iih_ptp->pdu_len);
133498527Sfenner	if (packet_len>pdu_len) {
1335127675Sbms            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1336127675Sbms            length=pdu_len;
133798527Sfenner	}
1338127675Sbms
133998527Sfenner	TCHECK(*header_iih_ptp);
1340127675Sbms	printf("\n\t  source-id: %s, holding time: %us, Flags: [%s]",
1341127675Sbms               isis_print_id(header_iih_ptp->source_id,SYSTEM_ID_LEN),
1342127675Sbms               EXTRACT_16BITS(header_iih_ptp->holding_time),
1343127675Sbms               tok2str(isis_iih_circuit_type_values,
1344127675Sbms                       "unknown circuit type 0x%02x",
1345127675Sbms                       header_iih_ptp->circuit_type));
134698527Sfenner
1347127675Sbms	printf("\n\t  circuit-id: 0x%02x, PDU length: %u",
1348127675Sbms               header_iih_ptp->circuit_id,
1349127675Sbms               pdu_len);
135098527Sfenner
1351127675Sbms        if (vflag > 1) {
1352127675Sbms            if(!print_unknown_data(pptr,"\n\t  ",ISIS_IIH_PTP_HEADER_SIZE))
1353127675Sbms                return(0);
1354127675Sbms        }
135598527Sfenner
135698527Sfenner	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
135798527Sfenner	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
135817688Spst	break;
135998527Sfenner
136098527Sfenner    case L1_LSP:
136198527Sfenner    case L2_LSP:
136298527Sfenner	if (header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE)) {
136398527Sfenner	    printf(", bogus fixed header length %u should be %lu",
136498527Sfenner		   header->fixed_len, (unsigned long)ISIS_LSP_HEADER_SIZE);
136598527Sfenner	    return (0);
136698527Sfenner	}
1367127675Sbms
136898527Sfenner	pdu_len=EXTRACT_16BITS(header_lsp->pdu_len);
136998527Sfenner	if (packet_len>pdu_len) {
1370127675Sbms            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1371127675Sbms            length=pdu_len;
137298527Sfenner	}
137398527Sfenner
137498527Sfenner	TCHECK(*header_lsp);
1375127675Sbms	printf("\n\t  lsp-id: %s, seq: 0x%08x, lifetime: %5us\n\t  chksum: 0x%04x",
1376127675Sbms               isis_print_id(header_lsp->lsp_id, LSP_ID_LEN),
1377127675Sbms               EXTRACT_32BITS(header_lsp->sequence_number),
1378127675Sbms               EXTRACT_16BITS(header_lsp->remaining_lifetime),
1379127675Sbms               EXTRACT_16BITS(header_lsp->checksum));
138098527Sfenner
1381127675Sbms        /* if this is a purge do not attempt to verify the checksum */
1382127675Sbms        if ( EXTRACT_16BITS(header_lsp->remaining_lifetime) == 0 &&
1383127675Sbms             EXTRACT_16BITS(header_lsp->checksum) == 0)
1384127675Sbms            printf(" (purged)");
1385127675Sbms        else
1386127675Sbms            /* verify the checksum -
1387127675Sbms             * checking starts at the lsp-id field at byte position [12]
1388127675Sbms             * hence the length needs to be reduced by 12 bytes */
1389127675Sbms            printf(" (%s)", (osi_cksum((u_int8_t *)header_lsp->lsp_id, length-12)) ? "incorrect" : "correct");
1390127675Sbms
1391127675Sbms	printf(", PDU length: %u, Flags: [ %s",
1392127675Sbms               pdu_len,
1393127675Sbms               ISIS_MASK_LSP_OL_BIT(header_lsp->typeblock) ? "Overload bit set, " : "");
1394127675Sbms
139598527Sfenner	if (ISIS_MASK_LSP_ATT_BITS(header_lsp->typeblock)) {
139698527Sfenner	    printf("%s", ISIS_MASK_LSP_ATT_DEFAULT_BIT(header_lsp->typeblock) ? "default " : "");
139798527Sfenner	    printf("%s", ISIS_MASK_LSP_ATT_DELAY_BIT(header_lsp->typeblock) ? "delay " : "");
139898527Sfenner	    printf("%s", ISIS_MASK_LSP_ATT_EXPENSE_BIT(header_lsp->typeblock) ? "expense " : "");
139998527Sfenner	    printf("%s", ISIS_MASK_LSP_ATT_ERROR_BIT(header_lsp->typeblock) ? "error " : "");
140098527Sfenner	    printf("ATT bit set, ");
140198527Sfenner	}
140298527Sfenner	printf("%s", ISIS_MASK_LSP_PARTITION_BIT(header_lsp->typeblock) ? "P bit set, " : "");
1403127675Sbms	printf("%s ]", tok2str(isis_lsp_istype_values,"Unknown(0x%x)",ISIS_MASK_LSP_ISTYPE_BITS(header_lsp->typeblock)));
140498527Sfenner
1405127675Sbms        if (vflag > 1) {
1406127675Sbms            if(!print_unknown_data(pptr,"\n\t  ",ISIS_LSP_HEADER_SIZE))
1407127675Sbms                return(0);
1408127675Sbms        }
1409127675Sbms
141098527Sfenner	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
141198527Sfenner	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
141217688Spst	break;
141398527Sfenner
141498527Sfenner    case L1_CSNP:
141598527Sfenner    case L2_CSNP:
141698527Sfenner	if (header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE)) {
141798527Sfenner	    printf(", bogus fixed header length %u should be %lu",
141898527Sfenner		   header->fixed_len, (unsigned long)ISIS_CSNP_HEADER_SIZE);
141998527Sfenner	    return (0);
142098527Sfenner	}
1421127675Sbms
142298527Sfenner	pdu_len=EXTRACT_16BITS(header_csnp->pdu_len);
142398527Sfenner	if (packet_len>pdu_len) {
1424127675Sbms            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1425127675Sbms            length=pdu_len;
142698527Sfenner	}
142717688Spst
142898527Sfenner	TCHECK(*header_csnp);
1429127675Sbms	printf("\n\t  source-id:    %s, PDU length: %u",
1430127675Sbms               isis_print_id(header_csnp->source_id, NODE_ID_LEN),
1431127675Sbms               pdu_len);
1432127675Sbms	printf("\n\t  start lsp-id: %s",
1433127675Sbms               isis_print_id(header_csnp->start_lsp_id, LSP_ID_LEN));
1434127675Sbms	printf("\n\t  end lsp-id:   %s",
1435127675Sbms               isis_print_id(header_csnp->end_lsp_id, LSP_ID_LEN));
143617688Spst
1437127675Sbms        if (vflag > 1) {
1438127675Sbms            if(!print_unknown_data(pptr,"\n\t  ",ISIS_CSNP_HEADER_SIZE))
1439127675Sbms                return(0);
1440127675Sbms        }
1441127675Sbms
144298527Sfenner	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
144398527Sfenner	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
144498527Sfenner        break;
144517688Spst
144698527Sfenner    case L1_PSNP:
144798527Sfenner    case L2_PSNP:
144898527Sfenner	if (header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE)) {
144998527Sfenner	    printf("- bogus fixed header length %u should be %lu",
145098527Sfenner		   header->fixed_len, (unsigned long)ISIS_PSNP_HEADER_SIZE);
145198527Sfenner	    return (0);
145298527Sfenner	}
145398527Sfenner
145498527Sfenner	pdu_len=EXTRACT_16BITS(header_psnp->pdu_len);
145598527Sfenner	if (packet_len>pdu_len) {
1456127675Sbms            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1457127675Sbms            length=pdu_len;
145898527Sfenner	}
145998527Sfenner
146098527Sfenner	TCHECK(*header_psnp);
1461127675Sbms	printf("\n\t  source-id:    %s, PDU length: %u",
1462127675Sbms               isis_print_id(header_psnp->source_id, NODE_ID_LEN),
1463127675Sbms               pdu_len);
1464127675Sbms
1465127675Sbms        if (vflag > 1) {
1466127675Sbms            if(!print_unknown_data(pptr,"\n\t  ",ISIS_PSNP_HEADER_SIZE))
1467127675Sbms                return(0);
1468127675Sbms        }
1469127675Sbms
147098527Sfenner	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
147198527Sfenner	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
147217688Spst	break;
147317688Spst
147498527Sfenner    default:
1475127675Sbms	if(!print_unknown_data(pptr,"\n\t  ",length))
1476127675Sbms	    return(0);
1477127675Sbms	return (0);
147817688Spst    }
147917688Spst
148017688Spst    /*
148117688Spst     * Now print the TLV's.
148217688Spst     */
1483127675Sbms
148417688Spst    while (packet_len >= 2) {
148598527Sfenner        if (pptr == snapend) {
148698527Sfenner	    return (1);
148798527Sfenner        }
148898527Sfenner
148998527Sfenner	if (!TTEST2(*pptr, 2)) {
1490127675Sbms	    printf("\n\t\t packet exceeded snapshot (%ld) bytes",
1491127675Sbms                   (long)(pptr-snapend));
149298527Sfenner	    return (1);
149317688Spst	}
1494127675Sbms	tlv_type = *pptr++;
1495127675Sbms	tlv_len = *pptr++;
1496127675Sbms        tmp =tlv_len; /* copy temporary len & pointer to packet data */
1497127675Sbms        tptr = pptr;
149817688Spst	packet_len -= 2;
1499127675Sbms	if (tlv_len > packet_len) {
150017688Spst	    break;
150117688Spst	}
150217688Spst
1503127675Sbms        /* first lets see if we know the TLVs name*/
1504127675Sbms	printf("\n\t    %s TLV #%u, length: %u",
1505127675Sbms               tok2str(isis_tlv_values,
1506127675Sbms                       "unknown",
1507127675Sbms                       tlv_type),
1508127675Sbms               tlv_type,
1509127675Sbms               tlv_len);
1510127675Sbms
1511127675Sbms        /* now check if we have a decoder otherwise do a hexdump at the end*/
1512127675Sbms	switch (tlv_type) {
151317688Spst	case TLV_AREA_ADDR:
151498527Sfenner	    if (!TTEST2(*tptr, 1))
151598527Sfenner		goto trunctlv;
151617688Spst	    alen = *tptr++;
151717688Spst	    while (tmp && alen < tmp) {
1518127675Sbms		printf("\n\t      Area address (length: %u): %s",
1519127675Sbms                       alen,
1520127675Sbms                       print_nsap(tptr, alen));
152117688Spst		tptr += alen;
152217688Spst		tmp -= alen + 1;
152398527Sfenner		if (tmp==0) /* if this is the last area address do not attemt a boundary check */
1524127675Sbms                    break;
152598527Sfenner		if (!TTEST2(*tptr, 1))
152698527Sfenner		    goto trunctlv;
152717688Spst		alen = *tptr++;
152817688Spst	    }
152917688Spst	    break;
153017688Spst	case TLV_ISNEIGH:
153175118Sfenner	    while (tmp >= ETHER_ADDR_LEN) {
1532127675Sbms                if (!TTEST2(*tptr, ETHER_ADDR_LEN))
1533127675Sbms                    goto trunctlv;
1534127675Sbms                printf("\n\t      SNPA: %s",isis_print_id(tptr,ETHER_ADDR_LEN));
1535127675Sbms                tmp -= ETHER_ADDR_LEN;
1536127675Sbms                tptr += ETHER_ADDR_LEN;
153717688Spst	    }
153817688Spst	    break;
153998527Sfenner
1540127675Sbms        case TLV_ISNEIGH_VARLEN:
1541127675Sbms            if (!TTEST2(*tptr, 1))
1542127675Sbms		goto trunctlv;
1543127675Sbms	    lan_alen = *tptr++; /* LAN adress length */
1544127675Sbms            tmp --;
1545127675Sbms            printf("\n\t      LAN address length %u bytes ",lan_alen);
1546127675Sbms	    while (tmp >= lan_alen) {
1547127675Sbms                if (!TTEST2(*tptr, lan_alen))
1548127675Sbms                    goto trunctlv;
1549127675Sbms                printf("\n\t\tIS Neighbor: %s",isis_print_id(tptr,lan_alen));
1550127675Sbms                tmp -= lan_alen;
1551127675Sbms                tptr +=lan_alen;
1552127675Sbms            }
1553127675Sbms            break;
1554127675Sbms
155517688Spst	case TLV_PADDING:
155617688Spst	    break;
155798527Sfenner
155898527Sfenner        case TLV_MT_IS_REACH:
1559127675Sbms            while (tmp >= 2+NODE_ID_LEN+3+1) {
1560127675Sbms                mt_len = isis_print_mtid(tptr, "\n\t      ");
1561127675Sbms                if (mt_len == 0) /* did something go wrong ? */
1562127675Sbms                    goto trunctlv;
1563127675Sbms                tptr+=mt_len;
1564127675Sbms                tmp-=mt_len;
156598527Sfenner
1566127675Sbms                ext_is_len = isis_print_ext_is_reach(tptr,"\n\t      ",tlv_type);
1567127675Sbms                if (ext_is_len == 0) /* did something go wrong ? */
156898527Sfenner                    goto trunctlv;
1569127675Sbms
1570127675Sbms                tmp-=ext_is_len;
1571127675Sbms                tptr+=ext_is_len;
157298527Sfenner            }
157398527Sfenner            break;
157498527Sfenner
1575127675Sbms        case TLV_IS_ALIAS_ID:
1576127675Sbms	    while (tmp >= NODE_ID_LEN+1) { /* is it worth attempting a decode ? */
1577127675Sbms	        ext_is_len = isis_print_ext_is_reach(tptr,"\n\t      ",tlv_type);
1578127675Sbms		if (ext_is_len == 0) /* did something go wrong ? */
1579127675Sbms	            goto trunctlv;
1580127675Sbms		tmp-=ext_is_len;
1581127675Sbms		tptr+=ext_is_len;
1582127675Sbms	    }
1583127675Sbms	    break;
1584127675Sbms
158598527Sfenner        case TLV_EXT_IS_REACH:
1586127675Sbms            while (tmp >= NODE_ID_LEN+3+1) { /* is it worth attempting a decode ? */
1587127675Sbms                ext_is_len = isis_print_ext_is_reach(tptr,"\n\t      ",tlv_type);
1588127675Sbms                if (ext_is_len == 0) /* did something go wrong ? */
1589127675Sbms                    goto trunctlv;
1590127675Sbms                tmp-=ext_is_len;
1591127675Sbms                tptr+=ext_is_len;
159298527Sfenner            }
159398527Sfenner            break;
159498527Sfenner        case TLV_IS_REACH:
159598527Sfenner	    if (!TTEST2(*tptr,1))  /* check if there is one byte left to read out the virtual flag */
1596127675Sbms                goto trunctlv;
1597127675Sbms            printf("\n\t      %s",
1598127675Sbms                   tok2str(isis_is_reach_virtual_values,
1599127675Sbms                           "bogus virtual flag 0x%02x",
1600127675Sbms                           *tptr++));
160198527Sfenner	    tlv_is_reach = (const struct isis_tlv_is_reach *)tptr;
160298527Sfenner            while (tmp >= sizeof(struct isis_tlv_is_reach)) {
160398527Sfenner		if (!TTEST(*tlv_is_reach))
160498527Sfenner		    goto trunctlv;
1605127675Sbms		printf("\n\t      IS Neighbor: %s",
1606127675Sbms		       isis_print_id(tlv_is_reach->neighbor_nodeid, NODE_ID_LEN));
1607127675Sbms                isis_print_metric_block(&tlv_is_reach->isis_metric_block);
160898527Sfenner		tmp -= sizeof(struct isis_tlv_is_reach);
160998527Sfenner		tlv_is_reach++;
161098527Sfenner	    }
161198527Sfenner            break;
161298527Sfenner
1613127675Sbms        case TLV_ESNEIGH:
1614127675Sbms	    tlv_es_reach = (const struct isis_tlv_es_reach *)tptr;
1615127675Sbms            while (tmp >= sizeof(struct isis_tlv_es_reach)) {
1616127675Sbms		if (!TTEST(*tlv_es_reach))
1617127675Sbms		    goto trunctlv;
1618127675Sbms		printf("\n\t      ES Neighbor: %s",
1619127675Sbms                       isis_print_id(tlv_es_reach->neighbor_sysid,SYSTEM_ID_LEN));
1620127675Sbms                isis_print_metric_block(&tlv_es_reach->isis_metric_block);
1621127675Sbms		tmp -= sizeof(struct isis_tlv_es_reach);
1622127675Sbms		tlv_es_reach++;
1623127675Sbms	    }
1624127675Sbms            break;
1625127675Sbms
1626127675Sbms            /* those two TLVs share the same format */
1627127675Sbms	case TLV_INT_IP_REACH:
1628127675Sbms	case TLV_EXT_IP_REACH:
1629127675Sbms	    if (!isis_print_tlv_ip_reach(pptr, "\n\t      ", tlv_len))
163098527Sfenner		return (1);
163117688Spst	    break;
163298527Sfenner
1633127675Sbms	case TLV_EXTD_IP_REACH:
1634127675Sbms	    while (tmp>0) {
1635127675Sbms                ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", IPV4);
1636127675Sbms                if (ext_ip_len == 0) /* did something go wrong ? */
1637127675Sbms                    goto trunctlv;
1638127675Sbms                tptr+=ext_ip_len;
1639127675Sbms		tmp-=ext_ip_len;
1640127675Sbms	    }
164198527Sfenner	    break;
164298527Sfenner
1643127675Sbms        case TLV_MT_IP_REACH:
1644127675Sbms	    while (tmp>0) {
1645127675Sbms                mt_len = isis_print_mtid(tptr, "\n\t      ");
1646127675Sbms                if (mt_len == 0) /* did something go wrong ? */
1647127675Sbms                    goto trunctlv;
1648127675Sbms                tptr+=mt_len;
1649127675Sbms                tmp-=mt_len;
165098527Sfenner
1651127675Sbms                ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", IPV4);
1652127675Sbms                if (ext_ip_len == 0) /* did something go wrong ? */
1653127675Sbms                    goto trunctlv;
1654127675Sbms                tptr+=ext_ip_len;
1655127675Sbms		tmp-=ext_ip_len;
165698527Sfenner	    }
165798527Sfenner	    break;
165898527Sfenner
165998527Sfenner#ifdef INET6
166098527Sfenner	case TLV_IP6_REACH:
1661127675Sbms	    while (tmp>0) {
1662127675Sbms                ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", IPV6);
1663127675Sbms                if (ext_ip_len == 0) /* did something go wrong ? */
1664127675Sbms                    goto trunctlv;
1665127675Sbms                tptr+=ext_ip_len;
1666127675Sbms		tmp-=ext_ip_len;
1667127675Sbms	    }
1668127675Sbms	    break;
166998527Sfenner
1670127675Sbms	case TLV_MT_IP6_REACH:
1671127675Sbms	    while (tmp>0) {
1672127675Sbms                mt_len = isis_print_mtid(tptr, "\n\t      ");
1673127675Sbms                if (mt_len == 0) /* did something go wrong ? */
1674127675Sbms                    goto trunctlv;
1675127675Sbms                tptr+=mt_len;
1676127675Sbms                tmp-=mt_len;
167798527Sfenner
1678127675Sbms                ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", IPV6);
1679127675Sbms                if (ext_ip_len == 0) /* did something go wrong ? */
1680127675Sbms                    goto trunctlv;
1681127675Sbms                tptr+=ext_ip_len;
1682127675Sbms		tmp-=ext_ip_len;
168398527Sfenner	    }
168498527Sfenner	    break;
168598527Sfenner
168698527Sfenner	case TLV_IP6ADDR:
1687127675Sbms	    while (tmp>0) {
168898527Sfenner		if (!TTEST2(*tptr, 16))
168998527Sfenner		    goto trunctlv;
169098527Sfenner
1691127675Sbms                printf("\n\t      IPv6 interface address: %s",
169298527Sfenner		       ip6addr_string(tptr));
169398527Sfenner
169498527Sfenner		tptr += 16;
1695127675Sbms		tmp -= 16;
169698527Sfenner	    }
169798527Sfenner	    break;
169898527Sfenner#endif
169998527Sfenner	case TLV_AUTH:
1700127675Sbms	    if (!TTEST2(*tptr, 1))
170198527Sfenner		goto trunctlv;
1702127675Sbms
1703127675Sbms            printf("\n\t      %s: ",
1704127675Sbms                   tok2str(isis_subtlv_auth_values,
1705127675Sbms                           "unknown Authentication type 0x%02x",
1706127675Sbms                           *tptr));
1707127675Sbms
1708127675Sbms	    switch (*tptr) {
1709127675Sbms	    case SUBTLV_AUTH_SIMPLE:
1710127675Sbms		for(i=1;i<tlv_len;i++) {
1711127675Sbms		    if (!TTEST2(*(tptr+i), 1))
171298527Sfenner			goto trunctlv;
1713127675Sbms		    printf("%c",*(tptr+i));
171498527Sfenner		}
1715127675Sbms		break;
1716127675Sbms	    case SUBTLV_AUTH_MD5:
1717127675Sbms		for(i=1;i<tlv_len;i++) {
1718127675Sbms		    if (!TTEST2(*(tptr+i), 1))
171998527Sfenner			goto trunctlv;
1720127675Sbms		    printf("%02x",*(tptr+i));
172198527Sfenner		}
1722127675Sbms		if (tlv_len != SUBTLV_AUTH_MD5_LEN+1)
1723127675Sbms                    printf(", (malformed subTLV) ");
1724127675Sbms		break;
1725127675Sbms	    case SUBTLV_AUTH_PRIVATE:
1726127675Sbms	    default:
1727127675Sbms		if(!print_unknown_data(tptr+1,"\n\t\t  ",tlv_len-1))
1728127675Sbms		    return(0);
1729127675Sbms		break;
173098527Sfenner	    }
173198527Sfenner	    break;
173298527Sfenner
173332149Spst	case TLV_PTP_ADJ:
1734127675Sbms	    tlv_ptp_adj = (const struct isis_tlv_ptp_adj *)tptr;
1735127675Sbms	    if(tmp>=1) {
1736127675Sbms		if (!TTEST2(*tptr, 1))
173798527Sfenner		    goto trunctlv;
1738127675Sbms		printf("\n\t      Adjacency State: %s (%u)",
1739127675Sbms		       tok2str(isis_ptp_adjancey_values, "unknown", *tptr),
1740127675Sbms                        *tptr);
1741127675Sbms		tmp--;
174298527Sfenner	    }
1743127675Sbms	    if(tmp>sizeof(tlv_ptp_adj->extd_local_circuit_id)) {
1744127675Sbms		if (!TTEST2(tlv_ptp_adj->extd_local_circuit_id,
1745127675Sbms                            sizeof(tlv_ptp_adj->extd_local_circuit_id)))
174698527Sfenner		    goto trunctlv;
1747127675Sbms		printf("\n\t      Extended Local circuit-ID: 0x%08x",
1748127675Sbms		       EXTRACT_32BITS(tlv_ptp_adj->extd_local_circuit_id));
1749127675Sbms		tmp-=sizeof(tlv_ptp_adj->extd_local_circuit_id);
175098527Sfenner	    }
1751127675Sbms	    if(tmp>=SYSTEM_ID_LEN) {
1752127675Sbms		if (!TTEST2(tlv_ptp_adj->neighbor_sysid, SYSTEM_ID_LEN))
175398527Sfenner		    goto trunctlv;
1754127675Sbms		printf("\n\t      Neighbor System-ID: %s",
1755127675Sbms		       isis_print_id(tlv_ptp_adj->neighbor_sysid,SYSTEM_ID_LEN));
1756127675Sbms		tmp-=SYSTEM_ID_LEN;
175798527Sfenner	    }
1758127675Sbms	    if(tmp>=sizeof(tlv_ptp_adj->neighbor_extd_local_circuit_id)) {
1759127675Sbms		if (!TTEST2(tlv_ptp_adj->neighbor_extd_local_circuit_id,
1760127675Sbms                            sizeof(tlv_ptp_adj->neighbor_extd_local_circuit_id)))
176198527Sfenner		    goto trunctlv;
1762127675Sbms		printf("\n\t      Neighbor Extended Local circuit-ID: 0x%08x",
1763127675Sbms		       EXTRACT_32BITS(tlv_ptp_adj->neighbor_extd_local_circuit_id));
176498527Sfenner	    }
176532149Spst	    break;
176698527Sfenner
176732149Spst	case TLV_PROTOCOLS:
1768127675Sbms	    printf("\n\t      NLPID(s): ");
1769127675Sbms	    while (tmp>0) {
1770127675Sbms		if (!TTEST2(*(tptr), 1))
177198527Sfenner		    goto trunctlv;
1772127675Sbms		printf("%s (0x%02x)",
1773127675Sbms                       tok2str(osi_nlpid_values,
1774127675Sbms                               "unknown",
1775127675Sbms                               *tptr),
1776127675Sbms                       *tptr);
1777127675Sbms		if (tmp>1) /* further NPLIDs ? - put comma */
177898527Sfenner		    printf(", ");
1779127675Sbms                tptr++;
1780127675Sbms                tmp--;
178198527Sfenner	    }
178232149Spst	    break;
178398527Sfenner
178498527Sfenner	case TLV_TE_ROUTER_ID:
178598527Sfenner	    if (!TTEST2(*pptr, 4))
178698527Sfenner		goto trunctlv;
1787127675Sbms	    printf("\n\t      Traffic Engineering Router ID: %s", ipaddr_string(pptr));
178898527Sfenner	    break;
178998527Sfenner
179032149Spst	case TLV_IPADDR:
1791127675Sbms	    while (tmp>0) {
179298527Sfenner		if (!TTEST2(*tptr, 4))
179398527Sfenner		    goto trunctlv;
1794127675Sbms		printf("\n\t      IPv4 interface address: %s", ipaddr_string(tptr));
179598527Sfenner		tptr += 4;
1796127675Sbms		tmp -= 4;
179798527Sfenner	    }
179832149Spst	    break;
179998527Sfenner
180098527Sfenner	case TLV_HOSTNAME:
1801127675Sbms	    printf("\n\t      Hostname: ");
1802127675Sbms	    while (tmp>0) {
1803127675Sbms		if (!TTEST2(*tptr, 1))
180498527Sfenner		    goto trunctlv;
1805127675Sbms		printf("%c",*tptr++);
1806127675Sbms                tmp--;
180798527Sfenner	    }
180898527Sfenner	    break;
180998527Sfenner
1810127675Sbms	case TLV_SHARED_RISK_GROUP:
1811127675Sbms	    if (!TTEST2(*tptr, NODE_ID_LEN))
1812127675Sbms                goto trunctlv;
1813127675Sbms	    printf("\n\t      IS Neighbor: %s", isis_print_id(tptr, NODE_ID_LEN));
1814127675Sbms	    tptr+=(NODE_ID_LEN);
1815127675Sbms	    tmp-=(NODE_ID_LEN);
1816127675Sbms
1817127675Sbms	    if (!TTEST2(*tptr, 1))
1818127675Sbms                goto trunctlv;
1819127675Sbms	    printf(", Flags: [%s]", ISIS_MASK_TLV_SHARED_RISK_GROUP(*tptr++) ? "numbered" : "unnumbered");
1820127675Sbms	    tmp--;
1821127675Sbms
1822127675Sbms	    if (!TTEST2(*tptr,4))
1823127675Sbms                goto trunctlv;
1824127675Sbms	    printf("\n\t      IPv4 interface address: %s", ipaddr_string(tptr));
1825127675Sbms	    tptr+=4;
1826127675Sbms	    tmp-=4;
1827127675Sbms
1828127675Sbms	    if (!TTEST2(*tptr,4))
1829127675Sbms                goto trunctlv;
1830127675Sbms	    printf("\n\t      IPv4 neighbor address: %s", ipaddr_string(tptr));
1831127675Sbms	    tptr+=4;
1832127675Sbms	    tmp-=4;
1833127675Sbms
1834127675Sbms	    while (tmp>0) {
1835127675Sbms                if (!TTEST2(*tptr, 4))
1836127675Sbms                    goto trunctlv;
1837127675Sbms                printf("\n\t      Link-ID: 0x%08x", EXTRACT_32BITS(tptr));
1838127675Sbms                tptr+=4;
1839127675Sbms                tmp-=4;
1840127675Sbms	    }
1841127675Sbms	    break;
1842127675Sbms
1843127675Sbms	case TLV_LSP:
1844127675Sbms	    tlv_lsp = (const struct isis_tlv_lsp *)tptr;
1845127675Sbms	    while(tmp>0) {
1846127675Sbms		if (!TTEST((tlv_lsp->lsp_id)[LSP_ID_LEN-1]))
184798527Sfenner		    goto trunctlv;
1848127675Sbms		printf("\n\t      lsp-id: %s",
1849127675Sbms                       isis_print_id(tlv_lsp->lsp_id, LSP_ID_LEN));
185098527Sfenner		if (!TTEST2(tlv_lsp->sequence_number, 4))
185198527Sfenner		    goto trunctlv;
1852127675Sbms		printf(", seq: 0x%08x",EXTRACT_32BITS(tlv_lsp->sequence_number));
185398527Sfenner		if (!TTEST2(tlv_lsp->remaining_lifetime, 2))
185498527Sfenner		    goto trunctlv;
1855127675Sbms		printf(", lifetime: %5ds",EXTRACT_16BITS(tlv_lsp->remaining_lifetime));
185698527Sfenner		if (!TTEST2(tlv_lsp->checksum, 2))
185798527Sfenner		    goto trunctlv;
1858127675Sbms		printf(", chksum: 0x%04x",EXTRACT_16BITS(tlv_lsp->checksum));
1859127675Sbms		tmp-=sizeof(struct isis_tlv_lsp);
186098527Sfenner		tlv_lsp++;
186198527Sfenner	    }
186298527Sfenner	    break;
186398527Sfenner
186498527Sfenner	case TLV_CHECKSUM:
1865127675Sbms	    if (!TTEST2(*tptr, 2))
186698527Sfenner		goto trunctlv;
1867127675Sbms	    printf("\n\t      checksum: 0x%04x ", EXTRACT_16BITS(tptr));
1868127675Sbms            /* do not attempt to verify the checksum if it is zero
1869127675Sbms             * most likely a HMAC-MD5 TLV is also present and
1870127675Sbms             * to avoid conflicts the checksum TLV is zeroed.
1871127675Sbms             * see rfc3358 for details
1872127675Sbms             */
1873127675Sbms            if (EXTRACT_16BITS(tptr) == 0)
1874127675Sbms                printf("(unverified)");
1875127675Sbms            else printf("(%s)", osi_cksum(optr, length) ? "incorrect" : "correct");
187698527Sfenner	    break;
187798527Sfenner
187898527Sfenner	case TLV_MT_SUPPORTED:
1879127675Sbms	    while (tmp>1) {
1880127675Sbms		/* length can only be a multiple of 2, otherwise there is
188198527Sfenner		   something broken -> so decode down until length is 1 */
1882127675Sbms		if (tmp!=1) {
1883127675Sbms                    mt_len = isis_print_mtid(tptr, "\n\t      ");
1884127675Sbms                    if (mt_len == 0) /* did something go wrong ? */
1885127675Sbms                        goto trunctlv;
1886127675Sbms                    tptr+=mt_len;
1887127675Sbms                    tmp-=mt_len;
188898527Sfenner		} else {
1889127675Sbms		    printf("\n\t      malformed MT-ID");
189098527Sfenner		    break;
189198527Sfenner		}
189298527Sfenner	    }
189398527Sfenner	    break;
189498527Sfenner
189598527Sfenner	case TLV_RESTART_SIGNALING:
1896127675Sbms            if (!TTEST2(*tptr, 3))
1897127675Sbms                goto trunctlv;
1898127675Sbms            printf("\n\t      Flags [%s], Remaining holding time %us",
1899127675Sbms                   bittok2str(isis_restart_flag_values, "none", *tptr),
1900127675Sbms                   EXTRACT_16BITS(tptr+1));
1901127675Sbms	    tptr+=3;
190298527Sfenner	    break;
190398527Sfenner
1904127675Sbms        case TLV_IDRP_INFO:
1905127675Sbms            if (!TTEST2(*tptr, 1))
1906127675Sbms                goto trunctlv;
1907127675Sbms            printf("\n\t      Inter-Domain Information Type: %s",
1908127675Sbms                   tok2str(isis_subtlv_idrp_values,
1909127675Sbms                           "Unknown (0x%02x)",
1910127675Sbms                           *tptr));
1911127675Sbms            switch (*tptr++) {
1912127675Sbms            case SUBTLV_IDRP_ASN:
1913127675Sbms                if (!TTEST2(*tptr, 2)) /* fetch AS number */
1914127675Sbms                    goto trunctlv;
1915127675Sbms                printf("AS Number: %u",EXTRACT_16BITS(tptr));
1916127675Sbms                break;
1917127675Sbms            case SUBTLV_IDRP_LOCAL:
1918127675Sbms            case SUBTLV_IDRP_RES:
1919127675Sbms            default:
1920127675Sbms                if(!print_unknown_data(tptr,"\n\t      ",tlv_len-1))
1921127675Sbms                    return(0);
1922127675Sbms                break;
1923127675Sbms            }
1924127675Sbms            break;
1925127675Sbms
1926127675Sbms        case TLV_LSP_BUFFERSIZE:
1927127675Sbms            if (!TTEST2(*tptr, 2))
1928127675Sbms                goto trunctlv;
1929127675Sbms            printf("\n\t      LSP Buffersize: %u",EXTRACT_16BITS(tptr));
1930127675Sbms            break;
1931127675Sbms
1932127675Sbms        case TLV_PART_DIS:
1933127675Sbms            while (tmp >= SYSTEM_ID_LEN) {
1934127675Sbms                if (!TTEST2(*tptr, SYSTEM_ID_LEN))
1935127675Sbms                    goto trunctlv;
1936127675Sbms                printf("\n\t      %s",isis_print_id(tptr,SYSTEM_ID_LEN));
1937127675Sbms                tptr+=SYSTEM_ID_LEN;
1938127675Sbms                tmp-=SYSTEM_ID_LEN;
1939127675Sbms            }
1940127675Sbms            break;
1941127675Sbms
1942127675Sbms        case TLV_PREFIX_NEIGH:
1943127675Sbms            if (!TTEST2(*tptr, sizeof(struct isis_metric_block)))
1944127675Sbms                goto trunctlv;
1945127675Sbms            printf("\n\t      Metric Block");
1946127675Sbms            isis_print_metric_block((const struct isis_metric_block *)tptr);
1947127675Sbms            tptr+=sizeof(struct isis_metric_block);
1948127675Sbms            tmp-=sizeof(struct isis_metric_block);
1949127675Sbms
1950127675Sbms            while(tmp>0) {
1951127675Sbms                if (!TTEST2(*tptr, 1))
1952127675Sbms                    goto trunctlv;
1953127675Sbms                prefix_len=*tptr++; /* read out prefix length in semioctets*/
1954127675Sbms                tmp--;
1955127675Sbms                if (!TTEST2(*tptr, prefix_len/2))
1956127675Sbms                    goto trunctlv;
1957127675Sbms                printf("\n\t\tAddress: %s/%u",
1958127675Sbms                       print_nsap(tptr,prefix_len/2),
1959127675Sbms                       prefix_len*4);
1960127675Sbms                tptr+=prefix_len/2;
1961127675Sbms                tmp-=prefix_len/2;
1962127675Sbms            }
1963127675Sbms            break;
1964127675Sbms
1965127675Sbms        case TLV_IIH_SEQNR:
1966127675Sbms            if (!TTEST2(*tptr, 4)) /* check if four bytes are on the wire */
1967127675Sbms                goto trunctlv;
1968127675Sbms            printf("\n\t      Sequence number: %u", EXTRACT_32BITS(tptr) );
1969127675Sbms            break;
1970127675Sbms
1971127675Sbms        case TLV_VENDOR_PRIVATE:
1972127675Sbms            if (!TTEST2(*tptr, 3)) /* check if enough byte for a full oui */
1973127675Sbms                goto trunctlv;
1974127675Sbms            printf("\n\t      Vendor OUI Code: 0x%06x", EXTRACT_24BITS(tptr) );
1975127675Sbms            tptr+=3;
1976127675Sbms            tmp-=3;
1977127675Sbms            if (tmp > 0) /* hexdump the rest */
1978127675Sbms                if(!print_unknown_data(tptr,"\n\t\t",tmp))
1979127675Sbms                    return(0);
1980127675Sbms            break;
1981127675Sbms            /*
1982127675Sbms             * FIXME those are the defined TLVs that lack a decoder
1983127675Sbms             * you are welcome to contribute code ;-)
1984127675Sbms             */
1985127675Sbms
1986127675Sbms        case TLV_DECNET_PHASE4:
1987127675Sbms        case TLV_LUCENT_PRIVATE:
1988127675Sbms        case TLV_IPAUTH:
1989127675Sbms        case TLV_NORTEL_PRIVATE1:
1990127675Sbms        case TLV_NORTEL_PRIVATE2:
1991127675Sbms
199217688Spst	default:
1993127675Sbms            if (vflag <= 1) {
1994127675Sbms                if(!print_unknown_data(pptr,"\n\t\t",tlv_len))
1995127675Sbms                    return(0);
1996127675Sbms            }
199717688Spst	    break;
199817688Spst	}
1999127675Sbms        /* do we want to see an additionally hexdump ? */
2000127675Sbms        if (vflag> 1) {
2001127675Sbms	    if(!print_unknown_data(pptr,"\n\t      ",tlv_len))
2002127675Sbms	        return(0);
2003127675Sbms        }
200417688Spst
2005127675Sbms	pptr += tlv_len;
2006127675Sbms	packet_len -= tlv_len;
200717688Spst    }
200817688Spst
200917688Spst    if (packet_len != 0) {
2010127675Sbms	printf("\n\t      %u straggler bytes", packet_len);
201117688Spst    }
201298527Sfenner    return (1);
201398527Sfenner
2014127675Sbms trunc:
201598527Sfenner    fputs("[|isis]", stdout);
201698527Sfenner    return (1);
201798527Sfenner
2018127675Sbms trunctlv:
2019127675Sbms    printf("\n\t\t packet exceeded snapshot");
202017688Spst    return(1);
202117688Spst}
202217688Spst
202317751Spst/*
202417751Spst * Verify the checksum.  See 8473-1, Appendix C, section C.4.
202517751Spst */
202617751Spst
202717688Spststatic int
2028127675Sbmsosi_cksum(const u_int8_t *tptr, u_int len)
202917680Spst{
203017680Spst	int32_t c0 = 0, c1 = 0;
203117680Spst
203239300Sfenner	while ((int)--len >= 0) {
2033127675Sbms		c0 += *tptr++;
203417751Spst		c0 %= 255;
203517680Spst		c1 += c0;
203617680Spst		c1 %= 255;
203717680Spst	}
203817751Spst	return (c0 | c1);
203917680Spst}
2040