xref: /freebsd/contrib/tcpdump/print-isoclns.c (revision f0adf7f5cdd241db2f2c817683191a6ef64a4e95)
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 support.
25  *
26  * $FreeBSD$
27  */
28 
29 #ifndef lint
30 static const char rcsid[] _U_ =
31     "@(#) $Header: /tcpdump/master/tcpdump/print-isoclns.c,v 1.106.2.5 2004/03/24 01:45:26 guy Exp $ (LBL)";
32 #endif
33 
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37 
38 #include <tcpdump-stdinc.h>
39 
40 #include <stdio.h>
41 #include <string.h>
42 
43 #include "interface.h"
44 #include "addrtoname.h"
45 #include "ethertype.h"
46 #include "ether.h"
47 #include "extract.h"
48 #include "gmpls.h"
49 
50 #define	NLPID_CLNS	129	/* 0x81 */
51 #define	NLPID_ESIS	130	/* 0x82 */
52 #define	NLPID_ISIS	131	/* 0x83 */
53 #define NLPID_IP6       0x8e
54 #define NLPID_IP        0xcc
55 #define	NLPID_NULLNS	0
56 
57 #define IPV4            1       /* AFI value */
58 #define IPV6            2       /* AFI value */
59 
60 /*
61  * IS-IS is defined in ISO 10589.  Look there for protocol definitions.
62  */
63 
64 #define SYSTEM_ID_LEN	ETHER_ADDR_LEN
65 #define NODE_ID_LEN     SYSTEM_ID_LEN+1
66 #define LSP_ID_LEN      SYSTEM_ID_LEN+2
67 
68 #define ISIS_VERSION	1
69 #define PDU_TYPE_MASK	0x1F
70 #define PRIORITY_MASK	0x7F
71 
72 #define L1_LAN_IIH	15
73 #define L2_LAN_IIH	16
74 #define PTP_IIH		17
75 #define L1_LSP       	18
76 #define L2_LSP       	20
77 #define L1_CSNP  	24
78 #define L2_CSNP  	25
79 #define L1_PSNP		26
80 #define L2_PSNP		27
81 
82 static struct tok isis_pdu_values[] = {
83     { L1_LAN_IIH,       "L1 Lan IIH"},
84     { L2_LAN_IIH,       "L2 Lan IIH"},
85     { PTP_IIH,          "p2p IIH"},
86     { L1_LSP,           "L1 LSP"},
87     { L2_LSP,           "L2 LSP"},
88     { L1_CSNP,          "L1 CSNP"},
89     { L2_CSNP,          "L2 CSNP"},
90     { L1_PSNP,          "L1 PSNP"},
91     { L2_PSNP,          "L2 PSNP"},
92     { 0, NULL}
93 };
94 
95 /*
96  * A TLV is a tuple of a type, length and a value and is normally used for
97  * encoding information in all sorts of places.  This is an enumeration of
98  * the well known types.
99  *
100  * list taken from rfc3359 plus some memory from veterans ;-)
101  */
102 
103 #define TLV_AREA_ADDR           1   /* iso10589 */
104 #define TLV_IS_REACH            2   /* iso10589 */
105 #define TLV_ESNEIGH             3   /* iso10589 */
106 #define TLV_PART_DIS            4   /* iso10589 */
107 #define TLV_PREFIX_NEIGH        5   /* iso10589 */
108 #define TLV_ISNEIGH             6   /* iso10589 */
109 #define TLV_ISNEIGH_VARLEN      7   /* iso10589 */
110 #define TLV_PADDING             8   /* iso10589 */
111 #define TLV_LSP                 9   /* iso10589 */
112 #define TLV_AUTH                10  /* iso10589, rfc3567 */
113 #define TLV_CHECKSUM            12  /* rfc3358 */
114 #define TLV_LSP_BUFFERSIZE      14  /* iso10589 rev2 */
115 #define TLV_EXT_IS_REACH        22  /* draft-ietf-isis-traffic-05 */
116 #define TLV_IS_ALIAS_ID         24  /* draft-ietf-isis-ext-lsp-frags-02 */
117 #define TLV_DECNET_PHASE4       42
118 #define TLV_LUCENT_PRIVATE      66
119 #define TLV_INT_IP_REACH        128 /* rfc1195, rfc2966 */
120 #define TLV_PROTOCOLS           129 /* rfc1195 */
121 #define TLV_EXT_IP_REACH        130 /* rfc1195, rfc2966 */
122 #define TLV_IDRP_INFO           131 /* rfc1195 */
123 #define TLV_IPADDR              132 /* rfc1195 */
124 #define TLV_IPAUTH              133 /* rfc1195 */
125 #define TLV_TE_ROUTER_ID        134 /* draft-ietf-isis-traffic-05 */
126 #define TLV_EXTD_IP_REACH       135 /* draft-ietf-isis-traffic-05 */
127 #define TLV_HOSTNAME            137 /* rfc2763 */
128 #define TLV_SHARED_RISK_GROUP   138 /* draft-ietf-isis-gmpls-extensions */
129 #define TLV_NORTEL_PRIVATE1     176
130 #define TLV_NORTEL_PRIVATE2     177
131 #define TLV_HOLDTIME            198 /* ES-IS */
132 #define TLV_RESTART_SIGNALING   211 /* draft-ietf-isis-restart-01 */
133 #define TLV_MT_IS_REACH         222 /* draft-ietf-isis-wg-multi-topology-05 */
134 #define TLV_MT_SUPPORTED        229 /* draft-ietf-isis-wg-multi-topology-05 */
135 #define TLV_IP6ADDR             232 /* draft-ietf-isis-ipv6-02 */
136 #define TLV_MT_IP_REACH         235 /* draft-ietf-isis-wg-multi-topology-05 */
137 #define TLV_IP6_REACH           236 /* draft-ietf-isis-ipv6-02 */
138 #define TLV_MT_IP6_REACH        237 /* draft-ietf-isis-wg-multi-topology-05 */
139 #define TLV_PTP_ADJ             240 /* rfc3373 */
140 #define TLV_IIH_SEQNR           241 /* draft-shen-isis-iih-sequence-00 */
141 #define TLV_VENDOR_PRIVATE      250 /* draft-ietf-isis-proprietary-tlv-00 */
142 
143 static struct tok isis_tlv_values[] = {
144     { TLV_AREA_ADDR,	     "Area address(es)"},
145     { TLV_IS_REACH,          "IS Reachability"},
146     { TLV_ESNEIGH,           "ES Neighbor(s)"},
147     { TLV_PART_DIS,          "Partition DIS"},
148     { TLV_PREFIX_NEIGH,      "Prefix Neighbors"},
149     { TLV_ISNEIGH,           "IS Neighbor(s)"},
150     { TLV_ISNEIGH_VARLEN,    "IS Neighbor(s) (variable length)"},
151     { TLV_PADDING,           "Padding"},
152     { TLV_LSP,               "LSP entries"},
153     { TLV_AUTH,              "Authentication"},
154     { TLV_CHECKSUM,          "Checksum"},
155     { TLV_LSP_BUFFERSIZE,    "LSP Buffersize"},
156     { TLV_EXT_IS_REACH,      "Extended IS Reachability"},
157     { TLV_IS_ALIAS_ID,       "IS Alias ID"},
158     { TLV_DECNET_PHASE4,     "DECnet Phase IV"},
159     { TLV_LUCENT_PRIVATE,    "Lucent Proprietary"},
160     { TLV_INT_IP_REACH,      "IPv4 Internal Reachability"},
161     { TLV_PROTOCOLS,         "Protocols supported"},
162     { TLV_EXT_IP_REACH,      "IPv4 External Reachability"},
163     { TLV_IDRP_INFO,         "Inter-Domain Information Type"},
164     { TLV_IPADDR,            "IPv4 Interface address(es)"},
165     { TLV_IPAUTH,            "IPv4 authentication (deprecated)"},
166     { TLV_TE_ROUTER_ID,      "Traffic Engineering Router ID"},
167     { TLV_EXTD_IP_REACH,      "Extended IPv4 Reachability"},
168     { TLV_HOSTNAME,          "Hostname"},
169     { TLV_SHARED_RISK_GROUP, "Shared Risk Link Group"},
170     { TLV_NORTEL_PRIVATE1,   "Nortel Proprietary"},
171     { TLV_NORTEL_PRIVATE2,   "Nortel Proprietary"},
172     { TLV_HOLDTIME,          "Holdtime"},
173     { TLV_RESTART_SIGNALING, "Restart Signaling"},
174     { TLV_MT_IS_REACH,       "Multi Topology IS Reachability"},
175     { TLV_MT_SUPPORTED,      "Multi Topology"},
176     { TLV_IP6ADDR,           "IPv6 Interface address(es)"},
177     { TLV_MT_IP_REACH,       "Multi-Topology IPv4 Reachability"},
178     { TLV_IP6_REACH,         "IPv6 reachability"},
179     { TLV_MT_IP6_REACH,      "Multi-Topology IP6 Reachability"},
180     { TLV_PTP_ADJ,           "Point-to-point Adjacency State"},
181     { TLV_IIH_SEQNR,         "Hello PDU Sequence Number"},
182     { TLV_VENDOR_PRIVATE,    "Vendor Private"},
183     { 0, NULL }
184 };
185 
186 #define SUBTLV_EXT_IS_REACH_ADMIN_GROUP           3 /* draft-ietf-isis-traffic-05 */
187 #define SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID  4 /* draft-ietf-isis-gmpls-extensions */
188 #define SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID        5 /* draft-ietf-isis-traffic-05 */
189 #define SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR        6 /* draft-ietf-isis-traffic-05 */
190 #define SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR    8 /* draft-ietf-isis-traffic-05 */
191 #define SUBTLV_EXT_IS_REACH_MAX_LINK_BW           9 /* draft-ietf-isis-traffic-05 */
192 #define SUBTLV_EXT_IS_REACH_RESERVABLE_BW        10 /* draft-ietf-isis-traffic-05 */
193 #define SUBTLV_EXT_IS_REACH_UNRESERVED_BW        11 /* draft-ietf-isis-traffic-05 */
194 #define SUBTLV_EXT_IS_REACH_TE_METRIC            18 /* draft-ietf-isis-traffic-05 */
195 #define SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE 20 /* draft-ietf-isis-gmpls-extensions */
196 #define SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR    21 /* draft-ietf-isis-gmpls-extensions */
197 
198 static struct tok isis_ext_is_reach_subtlv_values[] = {
199     { SUBTLV_EXT_IS_REACH_ADMIN_GROUP,            "Administrative groups" },
200     { SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID,   "Link Local/Remote Identifier" },
201     { SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID,         "Link Remote Identifier" },
202     { SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR,         "IPv4 interface address" },
203     { SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR,     "IPv4 neighbor address" },
204     { SUBTLV_EXT_IS_REACH_MAX_LINK_BW,            "Maximum link bandwidth" },
205     { SUBTLV_EXT_IS_REACH_RESERVABLE_BW,          "Reservable link bandwidth" },
206     { SUBTLV_EXT_IS_REACH_UNRESERVED_BW,          "Unreserved bandwidth" },
207     { SUBTLV_EXT_IS_REACH_TE_METRIC,              "Traffic Engineering Metric" },
208     { SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE,   "Link Protection Type" },
209     { SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR,      "Interface Switching Capability" },
210     { 250,                                        "Reserved for cisco specific extensions" },
211     { 251,                                        "Reserved for cisco specific extensions" },
212     { 252,                                        "Reserved for cisco specific extensions" },
213     { 253,                                        "Reserved for cisco specific extensions" },
214     { 254,                                        "Reserved for cisco specific extensions" },
215     { 255,                                        "Reserved for future expansion" },
216     { 0, NULL }
217 };
218 
219 #define SUBTLV_EXTD_IP_REACH_ADMIN_TAG32          1
220 #define SUBTLV_EXTD_IP_REACH_ADMIN_TAG64          2
221 
222 static struct tok isis_ext_ip_reach_subtlv_values[] = {
223     { SUBTLV_EXTD_IP_REACH_ADMIN_TAG32,           "32-Bit Administrative tag" },
224     { SUBTLV_EXTD_IP_REACH_ADMIN_TAG64,           "64-Bit Administrative tag" },
225     { 0, NULL }
226 };
227 
228 #define SUBTLV_AUTH_SIMPLE        1
229 #define SUBTLV_AUTH_MD5          54
230 #define SUBTLV_AUTH_MD5_LEN      16
231 #define SUBTLV_AUTH_PRIVATE     255
232 
233 static struct tok isis_subtlv_auth_values[] = {
234     { SUBTLV_AUTH_SIMPLE,	"simple text password"},
235     { SUBTLV_AUTH_MD5,	        "HMAC-MD5 password"},
236     { SUBTLV_AUTH_PRIVATE,	"Routing Domain private password"},
237     { 0, NULL }
238 };
239 
240 #define SUBTLV_IDRP_RES           0
241 #define SUBTLV_IDRP_LOCAL         1
242 #define SUBTLV_IDRP_ASN           2
243 
244 static struct tok isis_subtlv_idrp_values[] = {
245     { SUBTLV_IDRP_RES,         "Reserved"},
246     { SUBTLV_IDRP_LOCAL,       "Routing-Domain Specific"},
247     { SUBTLV_IDRP_ASN,         "AS Number Tag"},
248     { 0, NULL}
249 };
250 
251 #define ISIS_8BIT_MASK(x)                  ((x)&0xff)
252 
253 #define ISIS_MASK_LSP_OL_BIT(x)            ((x)&0x4)
254 #define ISIS_MASK_LSP_ISTYPE_BITS(x)       ((x)&0x3)
255 #define ISIS_MASK_LSP_PARTITION_BIT(x)     ((x)&0x80)
256 #define ISIS_MASK_LSP_ATT_BITS(x)          ((x)&0x78)
257 #define ISIS_MASK_LSP_ATT_ERROR_BIT(x)     ((x)&0x40)
258 #define ISIS_MASK_LSP_ATT_EXPENSE_BIT(x)   ((x)&0x20)
259 #define ISIS_MASK_LSP_ATT_DELAY_BIT(x)     ((x)&0x10)
260 #define ISIS_MASK_LSP_ATT_DEFAULT_BIT(x)   ((x)&0x8)
261 
262 #define ISIS_MASK_MTID(x)                  ((x)&0x0fff)
263 #define ISIS_MASK_MTFLAGS(x)               ((x)&0xf000)
264 
265 static struct tok isis_mt_flag_values[] = {
266     { 0x4000,                  "sub-TLVs present"},
267     { 0x8000,                  "ATT bit set"},
268     { 0, NULL}
269 };
270 
271 #define ISIS_MASK_TLV_EXTD_IP_UPDOWN(x)     ((x)&0x80)
272 #define ISIS_MASK_TLV_EXTD_IP_SUBTLV(x)     ((x)&0x40)
273 
274 #define ISIS_MASK_TLV_EXTD_IP6_IE(x)        ((x)&0x40)
275 #define ISIS_MASK_TLV_EXTD_IP6_SUBTLV(x)    ((x)&0x20)
276 
277 #define ISIS_LSP_TLV_METRIC_SUPPORTED(x)   ((x)&0x80)
278 #define ISIS_LSP_TLV_METRIC_IE(x)          ((x)&0x40)
279 #define ISIS_LSP_TLV_METRIC_UPDOWN(x)      ((x)&0x80)
280 #define ISIS_LSP_TLV_METRIC_VALUE(x)	   ((x)&0x3f)
281 
282 #define ISIS_MASK_TLV_SHARED_RISK_GROUP(x) ((x)&0x1)
283 
284 static struct tok isis_mt_values[] = {
285     { 0,    "IPv4 unicast"},
286     { 1,    "In-Band Management"},
287     { 2,    "IPv6 unicast"},
288     { 3,    "Multicast"},
289     { 4095, "Development, Experimental or Proprietary"},
290     { 0, NULL }
291 };
292 
293 static struct tok isis_iih_circuit_type_values[] = {
294     { 1,    "Level 1 only"},
295     { 2,    "Level 2 only"},
296     { 3,    "Level 1, Level 2"},
297     { 0, NULL}
298 };
299 
300 #define ISIS_LSP_TYPE_UNUSED0   0
301 #define ISIS_LSP_TYPE_LEVEL_1   1
302 #define ISIS_LSP_TYPE_UNUSED2   2
303 #define ISIS_LSP_TYPE_LEVEL_2   3
304 
305 static struct tok isis_lsp_istype_values[] = {
306     { ISIS_LSP_TYPE_UNUSED0,	"Unused 0x0 (invalid)"},
307     { ISIS_LSP_TYPE_LEVEL_1,	"L1 IS"},
308     { ISIS_LSP_TYPE_UNUSED2,	"Unused 0x2 (invalid)"},
309     { ISIS_LSP_TYPE_LEVEL_2,	"L1L2 IS"},
310     { 0, NULL }
311 };
312 
313 static struct tok osi_nlpid_values[] = {
314     { NLPID_CLNS,   "CLNS"},
315     { NLPID_IP,     "IPv4"},
316     { NLPID_IP6,    "IPv6"},
317     { 0, NULL }
318 };
319 
320 /*
321  * Katz's point to point adjacency TLV uses codes to tell us the state of
322  * the remote adjacency.  Enumerate them.
323  */
324 
325 #define ISIS_PTP_ADJ_UP   0
326 #define ISIS_PTP_ADJ_INIT 1
327 #define ISIS_PTP_ADJ_DOWN 2
328 
329 
330 static struct tok isis_ptp_adjancey_values[] = {
331     { ISIS_PTP_ADJ_UP,    "Up" },
332     { ISIS_PTP_ADJ_INIT,  "Initializing" },
333     { ISIS_PTP_ADJ_DOWN,  "Down" },
334     { 0, NULL}
335 };
336 
337 struct isis_tlv_ptp_adj {
338     u_int8_t adjacency_state;
339     u_int8_t extd_local_circuit_id[4];
340     u_int8_t neighbor_sysid[SYSTEM_ID_LEN];
341     u_int8_t neighbor_extd_local_circuit_id[4];
342 };
343 
344 static int osi_cksum(const u_int8_t *, u_int);
345 static void esis_print(const u_int8_t *, u_int);
346 static int isis_print(const u_int8_t *, u_int);
347 
348 struct isis_metric_block {
349     u_int8_t metric_default;
350     u_int8_t metric_delay;
351     u_int8_t metric_expense;
352     u_int8_t metric_error;
353 };
354 
355 struct isis_tlv_is_reach {
356     struct isis_metric_block isis_metric_block;
357     u_int8_t neighbor_nodeid[NODE_ID_LEN];
358 };
359 
360 struct isis_tlv_es_reach {
361     struct isis_metric_block isis_metric_block;
362     u_int8_t neighbor_sysid[SYSTEM_ID_LEN];
363 };
364 
365 struct isis_tlv_ip_reach {
366     struct isis_metric_block isis_metric_block;
367     u_int8_t prefix[4];
368     u_int8_t mask[4];
369 };
370 
371 static struct tok isis_is_reach_virtual_values[] = {
372     { 0,    "IsNotVirtual"},
373     { 1,    "IsVirtual"},
374     { 0, NULL }
375 };
376 
377 static struct tok isis_restart_flag_values[] = {
378     { 0x1,  "Restart Request"},
379     { 0x2,  "Restart Acknowledgement"},
380     { 0, NULL }
381 };
382 
383 struct isis_common_header {
384     u_int8_t nlpid;
385     u_int8_t fixed_len;
386     u_int8_t version;			/* Protocol version */
387     u_int8_t id_length;
388     u_int8_t pdu_type;		        /* 3 MSbits are reserved */
389     u_int8_t pdu_version;		/* Packet format version */
390     u_int8_t reserved;
391     u_int8_t max_area;
392 };
393 
394 struct isis_iih_lan_header {
395     u_int8_t circuit_type;
396     u_int8_t source_id[SYSTEM_ID_LEN];
397     u_int8_t holding_time[2];
398     u_int8_t pdu_len[2];
399     u_int8_t priority;
400     u_int8_t lan_id[NODE_ID_LEN];
401 };
402 
403 struct isis_iih_ptp_header {
404     u_int8_t circuit_type;
405     u_int8_t source_id[SYSTEM_ID_LEN];
406     u_int8_t holding_time[2];
407     u_int8_t pdu_len[2];
408     u_int8_t circuit_id;
409 };
410 
411 struct isis_lsp_header {
412     u_int8_t pdu_len[2];
413     u_int8_t remaining_lifetime[2];
414     u_int8_t lsp_id[LSP_ID_LEN];
415     u_int8_t sequence_number[4];
416     u_int8_t checksum[2];
417     u_int8_t typeblock;
418 };
419 
420 struct isis_csnp_header {
421     u_int8_t pdu_len[2];
422     u_int8_t source_id[NODE_ID_LEN];
423     u_int8_t start_lsp_id[LSP_ID_LEN];
424     u_int8_t end_lsp_id[LSP_ID_LEN];
425 };
426 
427 struct isis_psnp_header {
428     u_int8_t pdu_len[2];
429     u_int8_t source_id[NODE_ID_LEN];
430 };
431 
432 struct isis_tlv_lsp {
433     u_int8_t remaining_lifetime[2];
434     u_int8_t lsp_id[LSP_ID_LEN];
435     u_int8_t sequence_number[4];
436     u_int8_t checksum[2];
437 };
438 
439 static char *
440 print_nsap(register const u_int8_t *pptr, register int nsap_length)
441 {
442 	int nsap_idx;
443 	static char nsap_ascii_output[sizeof("xx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xx")];
444         char *junk_buf = nsap_ascii_output;
445 
446         if (nsap_length < 1 || nsap_length > 20) {
447                 snprintf(nsap_ascii_output, sizeof(nsap_ascii_output),
448                     "illegal length");
449                 return (nsap_ascii_output);
450         }
451 
452 	for (nsap_idx = 0; nsap_idx < nsap_length; nsap_idx++) {
453 		if (!TTEST2(*pptr, 1))
454 			return (0);
455 		snprintf(junk_buf,
456 		    sizeof(nsap_ascii_output) - (junk_buf - nsap_ascii_output),
457 		    "%02x", *pptr++);
458 		junk_buf += strlen(junk_buf);
459 		if (((nsap_idx & 1) == 0) &&
460                      (nsap_idx + 1 < nsap_length)) {
461                      	*junk_buf++ = '.';
462 		}
463 	}
464         *(junk_buf) = '\0';
465 	return (nsap_ascii_output);
466 }
467 
468 #define ISIS_COMMON_HEADER_SIZE (sizeof(struct isis_common_header))
469 #define ISIS_IIH_LAN_HEADER_SIZE (sizeof(struct isis_iih_lan_header))
470 #define ISIS_IIH_PTP_HEADER_SIZE (sizeof(struct isis_iih_ptp_header))
471 #define ISIS_LSP_HEADER_SIZE (sizeof(struct isis_lsp_header))
472 #define ISIS_CSNP_HEADER_SIZE (sizeof(struct isis_csnp_header))
473 #define ISIS_PSNP_HEADER_SIZE (sizeof(struct isis_psnp_header))
474 
475 void isoclns_print(const u_int8_t *p, u_int length, u_int caplen)
476 {
477 	const struct isis_common_header *header;
478 
479 	header = (const struct isis_common_header *)p;
480 
481         printf("%sOSI", caplen < 1 ? "|" : "");
482 
483         if (caplen < 1) /* enough bytes on the wire ? */
484                 return;
485 
486 	switch (*p) {
487 
488 	case NLPID_CLNS:
489 		(void)printf(", CLNS, length %u", length);
490 		break;
491 
492 	case NLPID_ESIS:
493 		esis_print(p, length);
494 		return;
495 
496 	case NLPID_ISIS:
497 		if (!isis_print(p, length))
498                         print_unknown_data(p,"\n\t",caplen);
499 		break;
500 
501 	case NLPID_NULLNS:
502 		(void)printf(", ISO NULLNS, length: %u", length);
503 		break;
504 
505 	default:
506 		(void)printf(", Unknown NLPID 0x%02x, length: %u", p[0], length);
507 		if (caplen > 1)
508                         print_unknown_data(p,"\n\t",caplen);
509 		break;
510 	}
511 }
512 
513 #define	ESIS_REDIRECT	6
514 #define	ESIS_ESH	2
515 #define	ESIS_ISH	4
516 
517 static struct tok esis_values[] = {
518     { ESIS_REDIRECT, "redirect"},
519     { ESIS_ESH,      "ESH"},
520     { ESIS_ISH,      "ISH"},
521     { 0, NULL }
522 };
523 
524 struct esis_hdr {
525 	u_int8_t version;
526 	u_int8_t reserved;
527 	u_int8_t type;
528 	u_int8_t tmo[2];
529 	u_int8_t cksum[2];
530 };
531 
532 static void
533 esis_print(const u_int8_t *p, u_int length)
534 {
535 	const u_int8_t *ep;
536 	u_int li;
537 	const struct esis_hdr *eh;
538 
539 	if (length <= 2) {
540 		if (qflag)
541 			printf(" bad pkt!");
542 		else
543 			printf(" no header at all!");
544 		return;
545 	}
546 	li = p[1];
547 	eh = (const struct esis_hdr *) &p[2];
548 	ep = p + li;
549 	if (li > length) {
550 		if (qflag)
551 			printf(" bad pkt!");
552 		else
553 			printf(" LI(%d) > PDU size (%d)!", li, length);
554 		return;
555 	}
556 	if (li < sizeof(struct esis_hdr) + 2) {
557 		if (qflag)
558 			printf(" bad pkt!");
559 		else {
560 			printf(" too short for esis header %d:", li);
561 			while (--length != 0)
562 				printf("%02X", *p++);
563 		}
564 		return;
565 	}
566 
567         printf(", ES-IS, %s, length %u",
568                tok2str(esis_values,"unknown type: %u",eh->type & 0x1f),
569                length);
570 
571         if(vflag < 1)
572                return;
573 
574 	if (vflag && osi_cksum(p, li)) {
575 		printf(" bad cksum (got 0x%02x%02x)",
576 		       eh->cksum[1], eh->cksum[0]);
577 		default_print(p, length);
578 		return;
579 	}
580 	if (eh->version != 1) {
581 		printf(" unsupported version %d", eh->version);
582 		return;
583 	}
584 	p += sizeof(*eh) + 2;
585 	li -= sizeof(*eh) + 2;	/* protoid * li */
586 
587 	switch (eh->type & 0x1f) {
588 	case ESIS_REDIRECT: {
589 		const u_int8_t *dst, *snpa, *is;
590 
591 		dst = p; p += *p + 1;
592 		if (p > snapend)
593 			return;
594 		printf("\n\t\t %s", isonsap_string(dst));
595 		snpa = p; p += *p + 1;
596 		is = p;   p += *p + 1;
597 		if (p > snapend)
598 			return;
599 		if (p > ep) {
600 			printf(" [bad li]");
601 			return;
602 		}
603 		if (is[0] == 0)
604 			printf(" > %s", etheraddr_string(&snpa[1]));
605 		else
606 			printf(" > %s", isonsap_string(is));
607 		li = ep - p;
608 		break;
609 	}
610 
611 	case ESIS_ESH:
612 		break;
613 
614 	case ESIS_ISH: {
615 		const u_int8_t *is;
616 
617 		is = p; p += *p + 1;
618 		if (p > ep) {
619 			printf(" [bad li]");
620 			return;
621 		}
622 		if (p > snapend)
623 			return;
624 		if (!qflag)
625 			printf("\n\tNET: %s", print_nsap(is+1,*is));
626 		li = ep - p;
627 		break;
628 	}
629 
630 	default:
631             if (vflag <= 1) {
632 		    if (p < snapend)
633                             print_unknown_data(p,"\n\t  ",snapend-p);
634             }
635             return;
636 	}
637 
638         /* hexdump - FIXME ? */
639         if (vflag > 1) {
640                     if (p < snapend)
641                             print_unknown_data(p,"\n\t  ",snapend-p);
642         }
643 	if (vflag)
644 		while (p < ep && li) {
645 			u_int op, opli;
646 			const u_int8_t *q;
647 
648 			if (snapend - p < 2)
649 				return;
650 			if (li < 2) {
651 				printf(", bad opts/li");
652 				return;
653 			}
654 			op = *p++;
655 			opli = *p++;
656 			li -= 2;
657 			if (opli > li) {
658 				printf(", opt (%d) too long", op);
659 				return;
660 			}
661 			li -= opli;
662 			q = p;
663 			p += opli;
664 
665 			if (snapend < p)
666 				return;
667 
668 			if (op == TLV_HOLDTIME && opli == 2) {
669 				printf("\n\tholdtime: %us", EXTRACT_16BITS(q));
670 				continue;
671 			}
672 
673 			if (op == TLV_PROTOCOLS && opli >= 1) {
674 				printf("\n\t%s (length: %u): %s",
675                                        tok2str(isis_tlv_values, "unknown", op),
676                                        opli,
677                                        tok2str(osi_nlpid_values,"Unknown 0x%02x",*q));
678 				continue;
679 			}
680 
681                         print_unknown_data(q,"\n\t  ",opli);
682 		}
683 }
684 
685 /* shared routine for printing system, node and lsp-ids */
686 static char *
687 isis_print_id(const u_int8_t *cp, int id_len)
688 {
689     int i;
690     static char id[sizeof("xxxx.xxxx.xxxx.yy-zz")];
691     char *pos = id;
692 
693     for (i = 1; i <= SYSTEM_ID_LEN; i++) {
694         snprintf(pos, sizeof(id) - (pos - id), "%02x", *cp++);
695 	pos += strlen(pos);
696 	if (i == 2 || i == 4)
697 	    *pos++ = '.';
698 	}
699     if (id_len >= NODE_ID_LEN) {
700         snprintf(pos, sizeof(id) - (pos - id), ".%02x", *cp++);
701 	pos += strlen(pos);
702     }
703     if (id_len == LSP_ID_LEN)
704         snprintf(pos, sizeof(id) - (pos - id), "-%02x", *cp);
705     return (id);
706 }
707 
708 /* print the 4-byte metric block which is common found in the old-style TLVs */
709 static int
710 isis_print_metric_block (const struct isis_metric_block *isis_metric_block)
711 {
712     printf(", Default Metric: %d, %s",
713            ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_default),
714            ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_default) ? "External" : "Internal");
715     if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_delay))
716         printf("\n\t\t  Delay Metric: %d, %s",
717                ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_delay),
718                ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_delay) ? "External" : "Internal");
719     if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_expense))
720         printf("\n\t\t  Expense Metric: %d, %s",
721                ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_expense),
722                ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_expense) ? "External" : "Internal");
723     if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_error))
724         printf("\n\t\t  Error Metric: %d, %s",
725                ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_error),
726                ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_error) ? "External" : "Internal");
727 
728     return(1); /* everything is ok */
729 }
730 
731 static int
732 isis_print_tlv_ip_reach (const u_int8_t *cp, const char *ident, int length)
733 {
734 	int prefix_len;
735 	const struct isis_tlv_ip_reach *tlv_ip_reach;
736 
737 	tlv_ip_reach = (const struct isis_tlv_ip_reach *)cp;
738 
739 	while (length > 0) {
740 		if ((size_t)length < sizeof(*tlv_ip_reach)) {
741 			printf("short IPv4 Reachability (%d vs %lu)",
742                                length,
743                                (unsigned long)sizeof(*tlv_ip_reach));
744 			return (0);
745 		}
746 
747 		if (!TTEST(*tlv_ip_reach))
748 		    return (0);
749 
750 		prefix_len = mask2plen(EXTRACT_32BITS(tlv_ip_reach->mask));
751 
752 		if (prefix_len == -1)
753 			printf("%sIPv4 prefix: %s mask %s",
754                                ident,
755 			       ipaddr_string((tlv_ip_reach->prefix)),
756 			       ipaddr_string((tlv_ip_reach->mask)));
757 		else
758 			printf("%sIPv4 prefix: %15s/%u",
759                                ident,
760 			       ipaddr_string((tlv_ip_reach->prefix)),
761 			       prefix_len);
762 
763 		printf(", Distribution: %s, Metric: %u, %s",
764                        ISIS_LSP_TLV_METRIC_UPDOWN(tlv_ip_reach->isis_metric_block.metric_default) ? "down" : "up",
765                        ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_default),
766                        ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_default) ? "External" : "Internal");
767 
768 		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_delay))
769                     printf("%s  Delay Metric: %u, %s",
770                            ident,
771                            ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_delay),
772                            ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_delay) ? "External" : "Internal");
773 
774 		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_expense))
775                     printf("%s  Expense Metric: %u, %s",
776                            ident,
777                            ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_expense),
778                            ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_expense) ? "External" : "Internal");
779 
780 		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_error))
781                     printf("%s  Error Metric: %u, %s",
782                            ident,
783                            ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_error),
784                            ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_error) ? "External" : "Internal");
785 
786 		length -= sizeof(struct isis_tlv_ip_reach);
787 		tlv_ip_reach++;
788 	}
789 	return (1);
790 }
791 
792 /*
793  * this is the common IP-REACH subTLV decoder it is called
794  * from various EXTD-IP REACH TLVs (135,235,236,237)
795  */
796 
797 static int
798 isis_print_ip_reach_subtlv (const u_int8_t *tptr,int subt,int subl,const char *ident) {
799 
800         /* first lets see if we know the subTLVs name*/
801 	printf("%s%s subTLV #%u, length: %u",
802 	       ident,
803                tok2str(isis_ext_ip_reach_subtlv_values,
804                        "unknown",
805                        subt),
806                subt,
807                subl);
808 
809 	if (!TTEST2(*tptr,subl))
810 	    goto trunctlv;
811 
812     switch(subt) {
813     case SUBTLV_EXTD_IP_REACH_ADMIN_TAG32:
814         while (subl >= 4) {
815 	    printf(", 0x%08x (=%u)",
816 		   EXTRACT_32BITS(tptr),
817 		   EXTRACT_32BITS(tptr));
818 	    tptr+=4;
819 	    subl-=4;
820 	}
821 	break;
822     case SUBTLV_EXTD_IP_REACH_ADMIN_TAG64:
823         while (subl >= 8) {
824 	    printf(", 0x%08x%08x",
825 		   EXTRACT_32BITS(tptr),
826 		   EXTRACT_32BITS(tptr+4));
827 	    tptr+=8;
828 	    subl-=8;
829 	}
830 	break;
831     default:
832 	if(!print_unknown_data(tptr,"\n\t\t    ",
833 			       subl))
834 	  return(0);
835 	break;
836     }
837     return(1);
838 
839 trunctlv:
840     printf("%spacket exceeded snapshot",ident);
841     return(0);
842 }
843 
844 /*
845  * this is the common IS-REACH subTLV decoder it is called
846  * from isis_print_ext_is_reach()
847  */
848 
849 static int
850 isis_print_is_reach_subtlv (const u_int8_t *tptr,int subt,int subl,const char *ident) {
851 
852         int priority_level;
853         union { /* int to float conversion buffer for several subTLVs */
854             float f;
855             u_int32_t i;
856         } bw;
857 
858         /* first lets see if we know the subTLVs name*/
859 	printf("%s%s subTLV #%u, length: %u",
860 	       ident,
861                tok2str(isis_ext_is_reach_subtlv_values,
862                        "unknown",
863                        subt),
864                subt,
865                subl);
866 
867 	if (!TTEST2(*tptr,subl))
868 	    goto trunctlv;
869 
870         switch(subt) {
871         case SUBTLV_EXT_IS_REACH_ADMIN_GROUP:
872         case SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID:
873         case SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID:
874 	    if (subl >= 4) {
875 	      printf(", 0x%08x", EXTRACT_32BITS(tptr));
876 	      if (subl == 8) /* draft-ietf-isis-gmpls-extensions */
877 	        printf(", 0x%08x", EXTRACT_32BITS(tptr+4));
878 	    }
879 	    break;
880         case SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR:
881         case SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR:
882             if (subl >= 4)
883               printf(", %s", ipaddr_string(tptr));
884             break;
885         case SUBTLV_EXT_IS_REACH_MAX_LINK_BW :
886 	case SUBTLV_EXT_IS_REACH_RESERVABLE_BW:
887             if (subl >= 4) {
888               bw.i = EXTRACT_32BITS(tptr);
889               printf(", %.3f Mbps", bw.f*8/1000000 );
890             }
891             break;
892         case SUBTLV_EXT_IS_REACH_UNRESERVED_BW :
893             if (subl >= 32) {
894               for (priority_level = 0; priority_level < 8; priority_level++) {
895                 bw.i = EXTRACT_32BITS(tptr);
896                 printf("%s  priority level %d: %.3f Mbps",
897                        ident,
898                        priority_level,
899                        bw.f*8/1000000 );
900 		tptr+=4;
901 	      }
902             }
903             break;
904         case SUBTLV_EXT_IS_REACH_TE_METRIC:
905             if (subl >= 3)
906               printf(", %u", EXTRACT_24BITS(tptr));
907             break;
908         case SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE:
909             if (subl >= 2) {
910               printf(", %s, Priority %u",
911 		   bittok2str(gmpls_link_prot_values, "none", *tptr),
912                    *(tptr+1));
913             }
914             break;
915         case SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR:
916             if (subl >= 36) {
917               printf("%s  Interface Switching Capability:%s",
918                    ident,
919                    tok2str(gmpls_switch_cap_values, "Unknown", *(tptr)));
920               printf(", LSP Encoding: %s",
921                    tok2str(gmpls_encoding_values, "Unknown", *(tptr+1)));
922 	      tptr+=4;
923               printf("%s  Max LSP Bandwidth:",ident);
924               for (priority_level = 0; priority_level < 8; priority_level++) {
925                 bw.i = EXTRACT_32BITS(tptr);
926                 printf("%s    priority level %d: %.3f Mbps",
927                        ident,
928                        priority_level,
929                        bw.f*8/1000000 );
930 		tptr+=4;
931               }
932               subl-=36;
933               /* there is some optional stuff left to decode but this is as of yet
934                  not specified so just lets hexdump what is left */
935               if(subl>0){
936                 if(!print_unknown_data(tptr,"\n\t\t    ",
937 				       subl-36))
938                     return(0);
939               }
940             }
941             break;
942         default:
943             if(!print_unknown_data(tptr,"\n\t\t    ",
944 				   subl))
945                 return(0);
946             break;
947         }
948         return(1);
949 
950 trunctlv:
951     printf("%spacket exceeded snapshot",ident);
952     return(0);
953 }
954 
955 
956 /*
957  * this is the common IS-REACH decoder it is called
958  * from various EXTD-IS REACH style TLVs (22,24,222)
959  */
960 
961 static int
962 isis_print_ext_is_reach (const u_int8_t *tptr,const char *ident, int tlv_type) {
963 
964     char ident_buffer[20];
965     int subtlv_type,subtlv_len,subtlv_sum_len;
966     int proc_bytes = 0; /* how many bytes did we process ? */
967 
968     if (!TTEST2(*tptr, NODE_ID_LEN))
969         return(0);
970 
971     printf("%sIS Neighbor: %s", ident, isis_print_id(tptr, NODE_ID_LEN));
972     tptr+=(NODE_ID_LEN);
973 
974     if (tlv_type != TLV_IS_ALIAS_ID) { /* the Alias TLV Metric field is implicit 0 */
975         if (!TTEST2(*tptr, 3))    /* and is therefore skipped */
976 	    return(0);
977 	printf(", Metric: %d",EXTRACT_24BITS(tptr));
978 	tptr+=3;
979     }
980 
981     if (!TTEST2(*tptr, 1))
982         return(0);
983     subtlv_sum_len=*(tptr++); /* read out subTLV length */
984     proc_bytes=NODE_ID_LEN+3+1;
985     printf(", %ssub-TLVs present",subtlv_sum_len ? "" : "no ");
986     if (subtlv_sum_len) {
987         printf(" (%u)",subtlv_sum_len);
988         while (subtlv_sum_len>0) {
989             if (!TTEST2(*tptr,2))
990                 return(0);
991             subtlv_type=*(tptr++);
992             subtlv_len=*(tptr++);
993             /* prepend the ident string */
994             snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
995             if(!isis_print_is_reach_subtlv(tptr,subtlv_type,subtlv_len,ident_buffer))
996                 return(0);
997             tptr+=subtlv_len;
998             subtlv_sum_len-=(subtlv_len+2);
999             proc_bytes+=(subtlv_len+2);
1000         }
1001     }
1002     return(proc_bytes);
1003 }
1004 
1005 /*
1006  * this is the common Multi Topology ID decoder
1007  * it is called from various MT-TLVs (222,229,235,237)
1008  */
1009 
1010 static int
1011 isis_print_mtid (const u_int8_t *tptr,const char *ident) {
1012 
1013     if (!TTEST2(*tptr, 2))
1014         return(0);
1015 
1016     printf("%s%s",
1017            ident,
1018            tok2str(isis_mt_values,
1019                    "Reserved for IETF Consensus",
1020                    ISIS_MASK_MTID(EXTRACT_16BITS(tptr))));
1021 
1022     printf(" Topology (0x%03x), Flags: [%s]",
1023            ISIS_MASK_MTID(EXTRACT_16BITS(tptr)),
1024            bittok2str(isis_mt_flag_values, "none",ISIS_MASK_MTFLAGS(EXTRACT_16BITS(tptr))));
1025 
1026     return(2);
1027 }
1028 
1029 /*
1030  * this is the common extended IP reach decoder
1031  * it is called from TLVs (135,235,236,237)
1032  * we process the TLV and optional subTLVs and return
1033  * the amount of processed bytes
1034  */
1035 
1036 static int
1037 isis_print_extd_ip_reach (const u_int8_t *tptr, const char *ident, u_int16_t afi) {
1038 
1039     char ident_buffer[20];
1040     u_int8_t prefix[16]; /* shared copy buffer for IPv4 and IPv6 prefixes */
1041     u_int metric, status_byte, bit_length, byte_length, sublen, processed, subtlvtype, subtlvlen;
1042 
1043     if (!TTEST2(*tptr, 4))
1044         return (0);
1045     metric = EXTRACT_32BITS(tptr);
1046     processed=4;
1047     tptr+=4;
1048 
1049     if (afi == IPV4) {
1050         if (!TTEST2(*tptr, 1)) /* fetch status byte */
1051             return (0);
1052         status_byte=*(tptr++);
1053         bit_length = status_byte&0x3f;
1054         processed++;
1055 #ifdef INET6
1056     } else if (afi == IPV6) {
1057         if (!TTEST2(*tptr, 1)) /* fetch status & prefix_len byte */
1058             return (0);
1059         status_byte=*(tptr++);
1060         bit_length=*(tptr++);
1061         processed+=2;
1062 #endif
1063     } else
1064         return (0); /* somebody is fooling us */
1065 
1066     byte_length = (bit_length + 7) / 8; /* prefix has variable length encoding */
1067 
1068     if (!TTEST2(*tptr, byte_length))
1069         return (0);
1070     memset(prefix, 0, 16);              /* clear the copy buffer */
1071     memcpy(prefix,tptr,byte_length);    /* copy as much as is stored in the TLV */
1072     tptr+=byte_length;
1073     processed+=byte_length;
1074 
1075     if (afi == IPV4)
1076         printf("%sIPv4 prefix: %15s/%u",
1077                ident,
1078                ipaddr_string(prefix),
1079                bit_length);
1080 #ifdef INET6
1081     if (afi == IPV6)
1082         printf("%sIPv6 prefix: %s/%u",
1083                ident,
1084                ip6addr_string(prefix),
1085                bit_length);
1086 #endif
1087 
1088     printf(", Distribution: %s, Metric: %u",
1089            ISIS_MASK_TLV_EXTD_IP_UPDOWN(status_byte) ? "down" : "up",
1090            metric);
1091 
1092     if (afi == IPV4 && ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte))
1093         printf(", sub-TLVs present");
1094 #ifdef INET6
1095     if (afi == IPV6)
1096         printf(", %s%s",
1097                ISIS_MASK_TLV_EXTD_IP6_IE(status_byte) ? "External" : "Internal",
1098                ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte) ? ", sub-TLVs present" : "");
1099 #endif
1100 
1101     if ((ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte)  && afi == IPV4) ||
1102         (ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte) && afi == IPV6)) {
1103         /* assume that one prefix can hold more
1104            than one subTLV - therefore the first byte must reflect
1105            the aggregate bytecount of the subTLVs for this prefix
1106         */
1107         if (!TTEST2(*tptr, 1))
1108             return (0);
1109         sublen=*(tptr++);
1110         processed+=sublen+1;
1111         printf(" (%u)",sublen);   /* print out subTLV length */
1112 
1113         while (sublen>0) {
1114             if (!TTEST2(*tptr,2))
1115                 return (0);
1116             subtlvtype=*(tptr++);
1117             subtlvlen=*(tptr++);
1118             /* prepend the ident string */
1119             snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
1120             if(!isis_print_ip_reach_subtlv(tptr,subtlvtype,subtlvlen,ident_buffer))
1121                 return(0);
1122             tptr+=subtlvlen;
1123             sublen-=(subtlvlen+2);
1124         }
1125     }
1126     return (processed);
1127 }
1128 
1129 /*
1130  * isis_print
1131  * Decode IS-IS packets.  Return 0 on error.
1132  */
1133 
1134 static int isis_print (const u_int8_t *p, u_int length)
1135 {
1136     const struct isis_common_header *header;
1137 
1138     const struct isis_iih_lan_header *header_iih_lan;
1139     const struct isis_iih_ptp_header *header_iih_ptp;
1140     const struct isis_lsp_header *header_lsp;
1141     const struct isis_csnp_header *header_csnp;
1142     const struct isis_psnp_header *header_psnp;
1143 
1144     const struct isis_tlv_lsp *tlv_lsp;
1145     const struct isis_tlv_ptp_adj *tlv_ptp_adj;
1146     const struct isis_tlv_is_reach *tlv_is_reach;
1147     const struct isis_tlv_es_reach *tlv_es_reach;
1148 
1149     u_int8_t pdu_type, max_area, id_length, tlv_type, tlv_len, tmp, alen, lan_alen, prefix_len;
1150     u_int8_t ext_is_len, ext_ip_len, mt_len;
1151     const u_int8_t *optr, *pptr, *tptr;
1152     u_short packet_len,pdu_len;
1153     u_int i;
1154 
1155     packet_len=length;
1156     optr = p; /* initialize the _o_riginal pointer to the packet start -
1157                  need it for parsing the checksum TLV */
1158     header = (const struct isis_common_header *)p;
1159     TCHECK(*header);
1160     pptr = p+(ISIS_COMMON_HEADER_SIZE);
1161     header_iih_lan = (const struct isis_iih_lan_header *)pptr;
1162     header_iih_ptp = (const struct isis_iih_ptp_header *)pptr;
1163     header_lsp = (const struct isis_lsp_header *)pptr;
1164     header_csnp = (const struct isis_csnp_header *)pptr;
1165     header_psnp = (const struct isis_psnp_header *)pptr;
1166 
1167     /*
1168      * Sanity checking of the header.
1169      */
1170 
1171     if (header->version != ISIS_VERSION) {
1172 	printf(", version %d packet not supported", header->version);
1173 	return (0);
1174     }
1175 
1176     if ((header->id_length != SYSTEM_ID_LEN) && (header->id_length != 0)) {
1177 	printf(", system ID length of %d is not supported",
1178 	       header->id_length);
1179 	return (0);
1180     }
1181 
1182     if (header->pdu_version != ISIS_VERSION) {
1183 	printf(", version %d packet not supported", header->pdu_version);
1184 	return (0);
1185     }
1186 
1187     max_area = header->max_area;
1188     switch(max_area) {
1189     case 0:
1190 	max_area = 3;	 /* silly shit */
1191 	break;
1192     case 255:
1193 	printf(", bad packet -- 255 areas");
1194 	return (0);
1195     default:
1196 	break;
1197     }
1198 
1199     id_length = header->id_length;
1200     switch(id_length) {
1201     case 0:
1202         id_length = 6;	 /* silly shit again */
1203 	break;
1204     case 1:              /* 1-8 are valid sys-ID lenghts */
1205     case 2:
1206     case 3:
1207     case 4:
1208     case 5:
1209     case 6:
1210     case 7:
1211     case 8:
1212         break;
1213     case 255:
1214         id_length = 0;   /* entirely useless */
1215 	break;
1216     default:
1217         break;
1218     }
1219 
1220     /* toss any non 6-byte sys-ID len PDUs */
1221     if (id_length != 6 ) {
1222 	printf(", bad packet -- illegal sys-ID length (%u)", id_length);
1223 	return (0);
1224     }
1225 
1226     pdu_type=header->pdu_type;
1227 
1228     /* in non-verbose mode print the basic PDU Type plus PDU specific brief information*/
1229     if (vflag < 1) {
1230         printf(", IS-IS, %s",
1231                tok2str(isis_pdu_values,"unknown PDU-Type %u",pdu_type));
1232 
1233 	switch (pdu_type) {
1234 
1235 	case L1_LAN_IIH:
1236 	case L2_LAN_IIH:
1237 	    printf(", src-id %s",
1238                    isis_print_id(header_iih_lan->source_id,SYSTEM_ID_LEN));
1239 	    printf(", lan-id %s, prio %u",
1240                    isis_print_id(header_iih_lan->lan_id,NODE_ID_LEN),
1241                    header_iih_lan->priority);
1242 	    break;
1243 	case PTP_IIH:
1244 	    printf(", src-id %s", isis_print_id(header_iih_ptp->source_id,SYSTEM_ID_LEN));
1245 	    break;
1246 	case L1_LSP:
1247 	case L2_LSP:
1248 	    printf(", lsp-id %s, seq 0x%08x, lifetime %5us",
1249 		   isis_print_id(header_lsp->lsp_id, LSP_ID_LEN),
1250 		   EXTRACT_32BITS(header_lsp->sequence_number),
1251 		   EXTRACT_16BITS(header_lsp->remaining_lifetime));
1252 	    break;
1253 	case L1_CSNP:
1254 	case L2_CSNP:
1255 	    printf(", src-id %s", isis_print_id(header_csnp->source_id,SYSTEM_ID_LEN));
1256 	    break;
1257 	case L1_PSNP:
1258 	case L2_PSNP:
1259 	    printf(", src-id %s", isis_print_id(header_psnp->source_id,SYSTEM_ID_LEN));
1260 	    break;
1261 
1262 	}
1263 	printf(", length %u", length);
1264 
1265         return(1);
1266     }
1267 
1268     /* ok they seem to want to know everything - lets fully decode it */
1269     printf(", IS-IS, length: %u",length);
1270 
1271     printf("\n\t%s, hlen: %u, v: %u, pdu-v: %u, sys-id-len: %u (%u), max-area: %u (%u)",
1272            tok2str(isis_pdu_values,
1273                    "unknown, type %u",
1274                    pdu_type),
1275            header->fixed_len,
1276            header->version,
1277            header->pdu_version,
1278 	   id_length,
1279 	   header->id_length,
1280            max_area,
1281            header->max_area);
1282 
1283     if (vflag > 1) {
1284         if(!print_unknown_data(optr,"\n\t",8)) /* provide the _o_riginal pointer */
1285             return(0);                         /* for optionally debugging the common header */
1286     }
1287 
1288     switch (pdu_type) {
1289 
1290     case L1_LAN_IIH:
1291     case L2_LAN_IIH:
1292 	if (header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE)) {
1293 	    printf(", bogus fixed header length %u should be %lu",
1294 		   header->fixed_len, (unsigned long)ISIS_IIH_LAN_HEADER_SIZE);
1295 	    return (0);
1296 	}
1297 
1298 	pdu_len=EXTRACT_16BITS(header_iih_lan->pdu_len);
1299 	if (packet_len>pdu_len) {
1300             packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1301             length=pdu_len;
1302 	}
1303 
1304 	TCHECK(*header_iih_lan);
1305 	printf("\n\t  source-id: %s,  holding time: %us, Flags: [%s]",
1306                isis_print_id(header_iih_lan->source_id,SYSTEM_ID_LEN),
1307                EXTRACT_16BITS(header_iih_lan->holding_time),
1308                tok2str(isis_iih_circuit_type_values,
1309                        "unknown circuit type 0x%02x",
1310                        header_iih_lan->circuit_type));
1311 
1312 	printf("\n\t  lan-id:    %s, Priority: %u, PDU length: %u",
1313                isis_print_id(header_iih_lan->lan_id, NODE_ID_LEN),
1314                (header_iih_lan->priority) & PRIORITY_MASK,
1315                pdu_len);
1316 
1317         if (vflag > 1) {
1318             if(!print_unknown_data(pptr,"\n\t  ",ISIS_IIH_LAN_HEADER_SIZE))
1319                 return(0);
1320         }
1321 
1322 	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
1323 	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
1324 	break;
1325 
1326     case PTP_IIH:
1327 	if (header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE)) {
1328 	    printf(", bogus fixed header length %u should be %lu",
1329 		   header->fixed_len, (unsigned long)ISIS_IIH_PTP_HEADER_SIZE);
1330 	    return (0);
1331 	}
1332 
1333 	pdu_len=EXTRACT_16BITS(header_iih_ptp->pdu_len);
1334 	if (packet_len>pdu_len) {
1335             packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1336             length=pdu_len;
1337 	}
1338 
1339 	TCHECK(*header_iih_ptp);
1340 	printf("\n\t  source-id: %s, holding time: %us, Flags: [%s]",
1341                isis_print_id(header_iih_ptp->source_id,SYSTEM_ID_LEN),
1342                EXTRACT_16BITS(header_iih_ptp->holding_time),
1343                tok2str(isis_iih_circuit_type_values,
1344                        "unknown circuit type 0x%02x",
1345                        header_iih_ptp->circuit_type));
1346 
1347 	printf("\n\t  circuit-id: 0x%02x, PDU length: %u",
1348                header_iih_ptp->circuit_id,
1349                pdu_len);
1350 
1351         if (vflag > 1) {
1352             if(!print_unknown_data(pptr,"\n\t  ",ISIS_IIH_PTP_HEADER_SIZE))
1353                 return(0);
1354         }
1355 
1356 	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
1357 	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
1358 	break;
1359 
1360     case L1_LSP:
1361     case L2_LSP:
1362 	if (header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE)) {
1363 	    printf(", bogus fixed header length %u should be %lu",
1364 		   header->fixed_len, (unsigned long)ISIS_LSP_HEADER_SIZE);
1365 	    return (0);
1366 	}
1367 
1368 	pdu_len=EXTRACT_16BITS(header_lsp->pdu_len);
1369 	if (packet_len>pdu_len) {
1370             packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1371             length=pdu_len;
1372 	}
1373 
1374 	TCHECK(*header_lsp);
1375 	printf("\n\t  lsp-id: %s, seq: 0x%08x, lifetime: %5us\n\t  chksum: 0x%04x",
1376                isis_print_id(header_lsp->lsp_id, LSP_ID_LEN),
1377                EXTRACT_32BITS(header_lsp->sequence_number),
1378                EXTRACT_16BITS(header_lsp->remaining_lifetime),
1379                EXTRACT_16BITS(header_lsp->checksum));
1380 
1381         /* if this is a purge do not attempt to verify the checksum */
1382         if ( EXTRACT_16BITS(header_lsp->remaining_lifetime) == 0 &&
1383              EXTRACT_16BITS(header_lsp->checksum) == 0)
1384             printf(" (purged)");
1385         else
1386             /* verify the checksum -
1387              * checking starts at the lsp-id field at byte position [12]
1388              * hence the length needs to be reduced by 12 bytes */
1389             printf(" (%s)", (osi_cksum((u_int8_t *)header_lsp->lsp_id, length-12)) ? "incorrect" : "correct");
1390 
1391 	printf(", PDU length: %u, Flags: [ %s",
1392                pdu_len,
1393                ISIS_MASK_LSP_OL_BIT(header_lsp->typeblock) ? "Overload bit set, " : "");
1394 
1395 	if (ISIS_MASK_LSP_ATT_BITS(header_lsp->typeblock)) {
1396 	    printf("%s", ISIS_MASK_LSP_ATT_DEFAULT_BIT(header_lsp->typeblock) ? "default " : "");
1397 	    printf("%s", ISIS_MASK_LSP_ATT_DELAY_BIT(header_lsp->typeblock) ? "delay " : "");
1398 	    printf("%s", ISIS_MASK_LSP_ATT_EXPENSE_BIT(header_lsp->typeblock) ? "expense " : "");
1399 	    printf("%s", ISIS_MASK_LSP_ATT_ERROR_BIT(header_lsp->typeblock) ? "error " : "");
1400 	    printf("ATT bit set, ");
1401 	}
1402 	printf("%s", ISIS_MASK_LSP_PARTITION_BIT(header_lsp->typeblock) ? "P bit set, " : "");
1403 	printf("%s ]", tok2str(isis_lsp_istype_values,"Unknown(0x%x)",ISIS_MASK_LSP_ISTYPE_BITS(header_lsp->typeblock)));
1404 
1405         if (vflag > 1) {
1406             if(!print_unknown_data(pptr,"\n\t  ",ISIS_LSP_HEADER_SIZE))
1407                 return(0);
1408         }
1409 
1410 	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
1411 	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
1412 	break;
1413 
1414     case L1_CSNP:
1415     case L2_CSNP:
1416 	if (header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE)) {
1417 	    printf(", bogus fixed header length %u should be %lu",
1418 		   header->fixed_len, (unsigned long)ISIS_CSNP_HEADER_SIZE);
1419 	    return (0);
1420 	}
1421 
1422 	pdu_len=EXTRACT_16BITS(header_csnp->pdu_len);
1423 	if (packet_len>pdu_len) {
1424             packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1425             length=pdu_len;
1426 	}
1427 
1428 	TCHECK(*header_csnp);
1429 	printf("\n\t  source-id:    %s, PDU length: %u",
1430                isis_print_id(header_csnp->source_id, NODE_ID_LEN),
1431                pdu_len);
1432 	printf("\n\t  start lsp-id: %s",
1433                isis_print_id(header_csnp->start_lsp_id, LSP_ID_LEN));
1434 	printf("\n\t  end lsp-id:   %s",
1435                isis_print_id(header_csnp->end_lsp_id, LSP_ID_LEN));
1436 
1437         if (vflag > 1) {
1438             if(!print_unknown_data(pptr,"\n\t  ",ISIS_CSNP_HEADER_SIZE))
1439                 return(0);
1440         }
1441 
1442 	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
1443 	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
1444         break;
1445 
1446     case L1_PSNP:
1447     case L2_PSNP:
1448 	if (header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE)) {
1449 	    printf("- bogus fixed header length %u should be %lu",
1450 		   header->fixed_len, (unsigned long)ISIS_PSNP_HEADER_SIZE);
1451 	    return (0);
1452 	}
1453 
1454 	pdu_len=EXTRACT_16BITS(header_psnp->pdu_len);
1455 	if (packet_len>pdu_len) {
1456             packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
1457             length=pdu_len;
1458 	}
1459 
1460 	TCHECK(*header_psnp);
1461 	printf("\n\t  source-id:    %s, PDU length: %u",
1462                isis_print_id(header_psnp->source_id, NODE_ID_LEN),
1463                pdu_len);
1464 
1465         if (vflag > 1) {
1466             if(!print_unknown_data(pptr,"\n\t  ",ISIS_PSNP_HEADER_SIZE))
1467                 return(0);
1468         }
1469 
1470 	packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
1471 	pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
1472 	break;
1473 
1474     default:
1475 	if(!print_unknown_data(pptr,"\n\t  ",length))
1476 	    return(0);
1477 	return (0);
1478     }
1479 
1480     /*
1481      * Now print the TLV's.
1482      */
1483 
1484     while (packet_len >= 2) {
1485         if (pptr == snapend) {
1486 	    return (1);
1487         }
1488 
1489 	if (!TTEST2(*pptr, 2)) {
1490 	    printf("\n\t\t packet exceeded snapshot (%ld) bytes",
1491                    (long)(pptr-snapend));
1492 	    return (1);
1493 	}
1494 	tlv_type = *pptr++;
1495 	tlv_len = *pptr++;
1496         tmp =tlv_len; /* copy temporary len & pointer to packet data */
1497         tptr = pptr;
1498 	packet_len -= 2;
1499 	if (tlv_len > packet_len) {
1500 	    break;
1501 	}
1502 
1503         /* first lets see if we know the TLVs name*/
1504 	printf("\n\t    %s TLV #%u, length: %u",
1505                tok2str(isis_tlv_values,
1506                        "unknown",
1507                        tlv_type),
1508                tlv_type,
1509                tlv_len);
1510 
1511         /* now check if we have a decoder otherwise do a hexdump at the end*/
1512 	switch (tlv_type) {
1513 	case TLV_AREA_ADDR:
1514 	    if (!TTEST2(*tptr, 1))
1515 		goto trunctlv;
1516 	    alen = *tptr++;
1517 	    while (tmp && alen < tmp) {
1518 		printf("\n\t      Area address (length: %u): %s",
1519                        alen,
1520                        print_nsap(tptr, alen));
1521 		tptr += alen;
1522 		tmp -= alen + 1;
1523 		if (tmp==0) /* if this is the last area address do not attemt a boundary check */
1524                     break;
1525 		if (!TTEST2(*tptr, 1))
1526 		    goto trunctlv;
1527 		alen = *tptr++;
1528 	    }
1529 	    break;
1530 	case TLV_ISNEIGH:
1531 	    while (tmp >= ETHER_ADDR_LEN) {
1532                 if (!TTEST2(*tptr, ETHER_ADDR_LEN))
1533                     goto trunctlv;
1534                 printf("\n\t      SNPA: %s",isis_print_id(tptr,ETHER_ADDR_LEN));
1535                 tmp -= ETHER_ADDR_LEN;
1536                 tptr += ETHER_ADDR_LEN;
1537 	    }
1538 	    break;
1539 
1540         case TLV_ISNEIGH_VARLEN:
1541             if (!TTEST2(*tptr, 1))
1542 		goto trunctlv;
1543 	    lan_alen = *tptr++; /* LAN adress length */
1544             tmp --;
1545             printf("\n\t      LAN address length %u bytes ",lan_alen);
1546 	    while (tmp >= lan_alen) {
1547                 if (!TTEST2(*tptr, lan_alen))
1548                     goto trunctlv;
1549                 printf("\n\t\tIS Neighbor: %s",isis_print_id(tptr,lan_alen));
1550                 tmp -= lan_alen;
1551                 tptr +=lan_alen;
1552             }
1553             break;
1554 
1555 	case TLV_PADDING:
1556 	    break;
1557 
1558         case TLV_MT_IS_REACH:
1559             while (tmp >= 2+NODE_ID_LEN+3+1) {
1560                 mt_len = isis_print_mtid(tptr, "\n\t      ");
1561                 if (mt_len == 0) /* did something go wrong ? */
1562                     goto trunctlv;
1563                 tptr+=mt_len;
1564                 tmp-=mt_len;
1565 
1566                 ext_is_len = isis_print_ext_is_reach(tptr,"\n\t      ",tlv_type);
1567                 if (ext_is_len == 0) /* did something go wrong ? */
1568                     goto trunctlv;
1569 
1570                 tmp-=ext_is_len;
1571                 tptr+=ext_is_len;
1572             }
1573             break;
1574 
1575         case TLV_IS_ALIAS_ID:
1576 	    while (tmp >= NODE_ID_LEN+1) { /* is it worth attempting a decode ? */
1577 	        ext_is_len = isis_print_ext_is_reach(tptr,"\n\t      ",tlv_type);
1578 		if (ext_is_len == 0) /* did something go wrong ? */
1579 	            goto trunctlv;
1580 		tmp-=ext_is_len;
1581 		tptr+=ext_is_len;
1582 	    }
1583 	    break;
1584 
1585         case TLV_EXT_IS_REACH:
1586             while (tmp >= NODE_ID_LEN+3+1) { /* is it worth attempting a decode ? */
1587                 ext_is_len = isis_print_ext_is_reach(tptr,"\n\t      ",tlv_type);
1588                 if (ext_is_len == 0) /* did something go wrong ? */
1589                     goto trunctlv;
1590                 tmp-=ext_is_len;
1591                 tptr+=ext_is_len;
1592             }
1593             break;
1594         case TLV_IS_REACH:
1595 	    if (!TTEST2(*tptr,1))  /* check if there is one byte left to read out the virtual flag */
1596                 goto trunctlv;
1597             printf("\n\t      %s",
1598                    tok2str(isis_is_reach_virtual_values,
1599                            "bogus virtual flag 0x%02x",
1600                            *tptr++));
1601 	    tlv_is_reach = (const struct isis_tlv_is_reach *)tptr;
1602             while (tmp >= sizeof(struct isis_tlv_is_reach)) {
1603 		if (!TTEST(*tlv_is_reach))
1604 		    goto trunctlv;
1605 		printf("\n\t      IS Neighbor: %s",
1606 		       isis_print_id(tlv_is_reach->neighbor_nodeid, NODE_ID_LEN));
1607                 isis_print_metric_block(&tlv_is_reach->isis_metric_block);
1608 		tmp -= sizeof(struct isis_tlv_is_reach);
1609 		tlv_is_reach++;
1610 	    }
1611             break;
1612 
1613         case TLV_ESNEIGH:
1614 	    tlv_es_reach = (const struct isis_tlv_es_reach *)tptr;
1615             while (tmp >= sizeof(struct isis_tlv_es_reach)) {
1616 		if (!TTEST(*tlv_es_reach))
1617 		    goto trunctlv;
1618 		printf("\n\t      ES Neighbor: %s",
1619                        isis_print_id(tlv_es_reach->neighbor_sysid,SYSTEM_ID_LEN));
1620                 isis_print_metric_block(&tlv_es_reach->isis_metric_block);
1621 		tmp -= sizeof(struct isis_tlv_es_reach);
1622 		tlv_es_reach++;
1623 	    }
1624             break;
1625 
1626             /* those two TLVs share the same format */
1627 	case TLV_INT_IP_REACH:
1628 	case TLV_EXT_IP_REACH:
1629 	    if (!isis_print_tlv_ip_reach(pptr, "\n\t      ", tlv_len))
1630 		return (1);
1631 	    break;
1632 
1633 	case TLV_EXTD_IP_REACH:
1634 	    while (tmp>0) {
1635                 ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", IPV4);
1636                 if (ext_ip_len == 0) /* did something go wrong ? */
1637                     goto trunctlv;
1638                 tptr+=ext_ip_len;
1639 		tmp-=ext_ip_len;
1640 	    }
1641 	    break;
1642 
1643         case TLV_MT_IP_REACH:
1644 	    while (tmp>0) {
1645                 mt_len = isis_print_mtid(tptr, "\n\t      ");
1646                 if (mt_len == 0) /* did something go wrong ? */
1647                     goto trunctlv;
1648                 tptr+=mt_len;
1649                 tmp-=mt_len;
1650 
1651                 ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", IPV4);
1652                 if (ext_ip_len == 0) /* did something go wrong ? */
1653                     goto trunctlv;
1654                 tptr+=ext_ip_len;
1655 		tmp-=ext_ip_len;
1656 	    }
1657 	    break;
1658 
1659 #ifdef INET6
1660 	case TLV_IP6_REACH:
1661 	    while (tmp>0) {
1662                 ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", IPV6);
1663                 if (ext_ip_len == 0) /* did something go wrong ? */
1664                     goto trunctlv;
1665                 tptr+=ext_ip_len;
1666 		tmp-=ext_ip_len;
1667 	    }
1668 	    break;
1669 
1670 	case TLV_MT_IP6_REACH:
1671 	    while (tmp>0) {
1672                 mt_len = isis_print_mtid(tptr, "\n\t      ");
1673                 if (mt_len == 0) /* did something go wrong ? */
1674                     goto trunctlv;
1675                 tptr+=mt_len;
1676                 tmp-=mt_len;
1677 
1678                 ext_ip_len = isis_print_extd_ip_reach(tptr, "\n\t      ", IPV6);
1679                 if (ext_ip_len == 0) /* did something go wrong ? */
1680                     goto trunctlv;
1681                 tptr+=ext_ip_len;
1682 		tmp-=ext_ip_len;
1683 	    }
1684 	    break;
1685 
1686 	case TLV_IP6ADDR:
1687 	    while (tmp>0) {
1688 		if (!TTEST2(*tptr, 16))
1689 		    goto trunctlv;
1690 
1691                 printf("\n\t      IPv6 interface address: %s",
1692 		       ip6addr_string(tptr));
1693 
1694 		tptr += 16;
1695 		tmp -= 16;
1696 	    }
1697 	    break;
1698 #endif
1699 	case TLV_AUTH:
1700 	    if (!TTEST2(*tptr, 1))
1701 		goto trunctlv;
1702 
1703             printf("\n\t      %s: ",
1704                    tok2str(isis_subtlv_auth_values,
1705                            "unknown Authentication type 0x%02x",
1706                            *tptr));
1707 
1708 	    switch (*tptr) {
1709 	    case SUBTLV_AUTH_SIMPLE:
1710 		for(i=1;i<tlv_len;i++) {
1711 		    if (!TTEST2(*(tptr+i), 1))
1712 			goto trunctlv;
1713 		    printf("%c",*(tptr+i));
1714 		}
1715 		break;
1716 	    case SUBTLV_AUTH_MD5:
1717 		for(i=1;i<tlv_len;i++) {
1718 		    if (!TTEST2(*(tptr+i), 1))
1719 			goto trunctlv;
1720 		    printf("%02x",*(tptr+i));
1721 		}
1722 		if (tlv_len != SUBTLV_AUTH_MD5_LEN+1)
1723                     printf(", (malformed subTLV) ");
1724 		break;
1725 	    case SUBTLV_AUTH_PRIVATE:
1726 	    default:
1727 		if(!print_unknown_data(tptr+1,"\n\t\t  ",tlv_len-1))
1728 		    return(0);
1729 		break;
1730 	    }
1731 	    break;
1732 
1733 	case TLV_PTP_ADJ:
1734 	    tlv_ptp_adj = (const struct isis_tlv_ptp_adj *)tptr;
1735 	    if(tmp>=1) {
1736 		if (!TTEST2(*tptr, 1))
1737 		    goto trunctlv;
1738 		printf("\n\t      Adjacency State: %s (%u)",
1739 		       tok2str(isis_ptp_adjancey_values, "unknown", *tptr),
1740                         *tptr);
1741 		tmp--;
1742 	    }
1743 	    if(tmp>sizeof(tlv_ptp_adj->extd_local_circuit_id)) {
1744 		if (!TTEST2(tlv_ptp_adj->extd_local_circuit_id,
1745                             sizeof(tlv_ptp_adj->extd_local_circuit_id)))
1746 		    goto trunctlv;
1747 		printf("\n\t      Extended Local circuit-ID: 0x%08x",
1748 		       EXTRACT_32BITS(tlv_ptp_adj->extd_local_circuit_id));
1749 		tmp-=sizeof(tlv_ptp_adj->extd_local_circuit_id);
1750 	    }
1751 	    if(tmp>=SYSTEM_ID_LEN) {
1752 		if (!TTEST2(tlv_ptp_adj->neighbor_sysid, SYSTEM_ID_LEN))
1753 		    goto trunctlv;
1754 		printf("\n\t      Neighbor System-ID: %s",
1755 		       isis_print_id(tlv_ptp_adj->neighbor_sysid,SYSTEM_ID_LEN));
1756 		tmp-=SYSTEM_ID_LEN;
1757 	    }
1758 	    if(tmp>=sizeof(tlv_ptp_adj->neighbor_extd_local_circuit_id)) {
1759 		if (!TTEST2(tlv_ptp_adj->neighbor_extd_local_circuit_id,
1760                             sizeof(tlv_ptp_adj->neighbor_extd_local_circuit_id)))
1761 		    goto trunctlv;
1762 		printf("\n\t      Neighbor Extended Local circuit-ID: 0x%08x",
1763 		       EXTRACT_32BITS(tlv_ptp_adj->neighbor_extd_local_circuit_id));
1764 	    }
1765 	    break;
1766 
1767 	case TLV_PROTOCOLS:
1768 	    printf("\n\t      NLPID(s): ");
1769 	    while (tmp>0) {
1770 		if (!TTEST2(*(tptr), 1))
1771 		    goto trunctlv;
1772 		printf("%s (0x%02x)",
1773                        tok2str(osi_nlpid_values,
1774                                "unknown",
1775                                *tptr),
1776                        *tptr);
1777 		if (tmp>1) /* further NPLIDs ? - put comma */
1778 		    printf(", ");
1779                 tptr++;
1780                 tmp--;
1781 	    }
1782 	    break;
1783 
1784 	case TLV_TE_ROUTER_ID:
1785 	    if (!TTEST2(*pptr, 4))
1786 		goto trunctlv;
1787 	    printf("\n\t      Traffic Engineering Router ID: %s", ipaddr_string(pptr));
1788 	    break;
1789 
1790 	case TLV_IPADDR:
1791 	    while (tmp>0) {
1792 		if (!TTEST2(*tptr, 4))
1793 		    goto trunctlv;
1794 		printf("\n\t      IPv4 interface address: %s", ipaddr_string(tptr));
1795 		tptr += 4;
1796 		tmp -= 4;
1797 	    }
1798 	    break;
1799 
1800 	case TLV_HOSTNAME:
1801 	    printf("\n\t      Hostname: ");
1802 	    while (tmp>0) {
1803 		if (!TTEST2(*tptr, 1))
1804 		    goto trunctlv;
1805 		printf("%c",*tptr++);
1806                 tmp--;
1807 	    }
1808 	    break;
1809 
1810 	case TLV_SHARED_RISK_GROUP:
1811 	    if (!TTEST2(*tptr, NODE_ID_LEN))
1812                 goto trunctlv;
1813 	    printf("\n\t      IS Neighbor: %s", isis_print_id(tptr, NODE_ID_LEN));
1814 	    tptr+=(NODE_ID_LEN);
1815 	    tmp-=(NODE_ID_LEN);
1816 
1817 	    if (!TTEST2(*tptr, 1))
1818                 goto trunctlv;
1819 	    printf(", Flags: [%s]", ISIS_MASK_TLV_SHARED_RISK_GROUP(*tptr++) ? "numbered" : "unnumbered");
1820 	    tmp--;
1821 
1822 	    if (!TTEST2(*tptr,4))
1823                 goto trunctlv;
1824 	    printf("\n\t      IPv4 interface address: %s", ipaddr_string(tptr));
1825 	    tptr+=4;
1826 	    tmp-=4;
1827 
1828 	    if (!TTEST2(*tptr,4))
1829                 goto trunctlv;
1830 	    printf("\n\t      IPv4 neighbor address: %s", ipaddr_string(tptr));
1831 	    tptr+=4;
1832 	    tmp-=4;
1833 
1834 	    while (tmp>0) {
1835                 if (!TTEST2(*tptr, 4))
1836                     goto trunctlv;
1837                 printf("\n\t      Link-ID: 0x%08x", EXTRACT_32BITS(tptr));
1838                 tptr+=4;
1839                 tmp-=4;
1840 	    }
1841 	    break;
1842 
1843 	case TLV_LSP:
1844 	    tlv_lsp = (const struct isis_tlv_lsp *)tptr;
1845 	    while(tmp>0) {
1846 		if (!TTEST((tlv_lsp->lsp_id)[LSP_ID_LEN-1]))
1847 		    goto trunctlv;
1848 		printf("\n\t      lsp-id: %s",
1849                        isis_print_id(tlv_lsp->lsp_id, LSP_ID_LEN));
1850 		if (!TTEST2(tlv_lsp->sequence_number, 4))
1851 		    goto trunctlv;
1852 		printf(", seq: 0x%08x",EXTRACT_32BITS(tlv_lsp->sequence_number));
1853 		if (!TTEST2(tlv_lsp->remaining_lifetime, 2))
1854 		    goto trunctlv;
1855 		printf(", lifetime: %5ds",EXTRACT_16BITS(tlv_lsp->remaining_lifetime));
1856 		if (!TTEST2(tlv_lsp->checksum, 2))
1857 		    goto trunctlv;
1858 		printf(", chksum: 0x%04x",EXTRACT_16BITS(tlv_lsp->checksum));
1859 		tmp-=sizeof(struct isis_tlv_lsp);
1860 		tlv_lsp++;
1861 	    }
1862 	    break;
1863 
1864 	case TLV_CHECKSUM:
1865 	    if (!TTEST2(*tptr, 2))
1866 		goto trunctlv;
1867 	    printf("\n\t      checksum: 0x%04x ", EXTRACT_16BITS(tptr));
1868             /* do not attempt to verify the checksum if it is zero
1869              * most likely a HMAC-MD5 TLV is also present and
1870              * to avoid conflicts the checksum TLV is zeroed.
1871              * see rfc3358 for details
1872              */
1873             if (EXTRACT_16BITS(tptr) == 0)
1874                 printf("(unverified)");
1875             else printf("(%s)", osi_cksum(optr, length) ? "incorrect" : "correct");
1876 	    break;
1877 
1878 	case TLV_MT_SUPPORTED:
1879 	    while (tmp>1) {
1880 		/* length can only be a multiple of 2, otherwise there is
1881 		   something broken -> so decode down until length is 1 */
1882 		if (tmp!=1) {
1883                     mt_len = isis_print_mtid(tptr, "\n\t      ");
1884                     if (mt_len == 0) /* did something go wrong ? */
1885                         goto trunctlv;
1886                     tptr+=mt_len;
1887                     tmp-=mt_len;
1888 		} else {
1889 		    printf("\n\t      malformed MT-ID");
1890 		    break;
1891 		}
1892 	    }
1893 	    break;
1894 
1895 	case TLV_RESTART_SIGNALING:
1896             if (!TTEST2(*tptr, 3))
1897                 goto trunctlv;
1898             printf("\n\t      Flags [%s], Remaining holding time %us",
1899                    bittok2str(isis_restart_flag_values, "none", *tptr),
1900                    EXTRACT_16BITS(tptr+1));
1901 	    tptr+=3;
1902 	    break;
1903 
1904         case TLV_IDRP_INFO:
1905             if (!TTEST2(*tptr, 1))
1906                 goto trunctlv;
1907             printf("\n\t      Inter-Domain Information Type: %s",
1908                    tok2str(isis_subtlv_idrp_values,
1909                            "Unknown (0x%02x)",
1910                            *tptr));
1911             switch (*tptr++) {
1912             case SUBTLV_IDRP_ASN:
1913                 if (!TTEST2(*tptr, 2)) /* fetch AS number */
1914                     goto trunctlv;
1915                 printf("AS Number: %u",EXTRACT_16BITS(tptr));
1916                 break;
1917             case SUBTLV_IDRP_LOCAL:
1918             case SUBTLV_IDRP_RES:
1919             default:
1920                 if(!print_unknown_data(tptr,"\n\t      ",tlv_len-1))
1921                     return(0);
1922                 break;
1923             }
1924             break;
1925 
1926         case TLV_LSP_BUFFERSIZE:
1927             if (!TTEST2(*tptr, 2))
1928                 goto trunctlv;
1929             printf("\n\t      LSP Buffersize: %u",EXTRACT_16BITS(tptr));
1930             break;
1931 
1932         case TLV_PART_DIS:
1933             while (tmp >= SYSTEM_ID_LEN) {
1934                 if (!TTEST2(*tptr, SYSTEM_ID_LEN))
1935                     goto trunctlv;
1936                 printf("\n\t      %s",isis_print_id(tptr,SYSTEM_ID_LEN));
1937                 tptr+=SYSTEM_ID_LEN;
1938                 tmp-=SYSTEM_ID_LEN;
1939             }
1940             break;
1941 
1942         case TLV_PREFIX_NEIGH:
1943             if (!TTEST2(*tptr, sizeof(struct isis_metric_block)))
1944                 goto trunctlv;
1945             printf("\n\t      Metric Block");
1946             isis_print_metric_block((const struct isis_metric_block *)tptr);
1947             tptr+=sizeof(struct isis_metric_block);
1948             tmp-=sizeof(struct isis_metric_block);
1949 
1950             while(tmp>0) {
1951                 if (!TTEST2(*tptr, 1))
1952                     goto trunctlv;
1953                 prefix_len=*tptr++; /* read out prefix length in semioctets*/
1954                 tmp--;
1955                 if (!TTEST2(*tptr, prefix_len/2))
1956                     goto trunctlv;
1957                 printf("\n\t\tAddress: %s/%u",
1958                        print_nsap(tptr,prefix_len/2),
1959                        prefix_len*4);
1960                 tptr+=prefix_len/2;
1961                 tmp-=prefix_len/2;
1962             }
1963             break;
1964 
1965         case TLV_IIH_SEQNR:
1966             if (!TTEST2(*tptr, 4)) /* check if four bytes are on the wire */
1967                 goto trunctlv;
1968             printf("\n\t      Sequence number: %u", EXTRACT_32BITS(tptr) );
1969             break;
1970 
1971         case TLV_VENDOR_PRIVATE:
1972             if (!TTEST2(*tptr, 3)) /* check if enough byte for a full oui */
1973                 goto trunctlv;
1974             printf("\n\t      Vendor OUI Code: 0x%06x", EXTRACT_24BITS(tptr) );
1975             tptr+=3;
1976             tmp-=3;
1977             if (tmp > 0) /* hexdump the rest */
1978                 if(!print_unknown_data(tptr,"\n\t\t",tmp))
1979                     return(0);
1980             break;
1981             /*
1982              * FIXME those are the defined TLVs that lack a decoder
1983              * you are welcome to contribute code ;-)
1984              */
1985 
1986         case TLV_DECNET_PHASE4:
1987         case TLV_LUCENT_PRIVATE:
1988         case TLV_IPAUTH:
1989         case TLV_NORTEL_PRIVATE1:
1990         case TLV_NORTEL_PRIVATE2:
1991 
1992 	default:
1993             if (vflag <= 1) {
1994                 if(!print_unknown_data(pptr,"\n\t\t",tlv_len))
1995                     return(0);
1996             }
1997 	    break;
1998 	}
1999         /* do we want to see an additionally hexdump ? */
2000         if (vflag> 1) {
2001 	    if(!print_unknown_data(pptr,"\n\t      ",tlv_len))
2002 	        return(0);
2003         }
2004 
2005 	pptr += tlv_len;
2006 	packet_len -= tlv_len;
2007     }
2008 
2009     if (packet_len != 0) {
2010 	printf("\n\t      %u straggler bytes", packet_len);
2011     }
2012     return (1);
2013 
2014  trunc:
2015     fputs("[|isis]", stdout);
2016     return (1);
2017 
2018  trunctlv:
2019     printf("\n\t\t packet exceeded snapshot");
2020     return(1);
2021 }
2022 
2023 /*
2024  * Verify the checksum.  See 8473-1, Appendix C, section C.4.
2025  */
2026 
2027 static int
2028 osi_cksum(const u_int8_t *tptr, u_int len)
2029 {
2030 	int32_t c0 = 0, c1 = 0;
2031 
2032 	while ((int)--len >= 0) {
2033 		c0 += *tptr++;
2034 		c0 %= 255;
2035 		c1 += c0;
2036 		c1 %= 255;
2037 	}
2038 	return (c0 | c1);
2039 }
2040