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