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