xref: /netbsd-src/external/bsd/tcpdump/dist/print-isoclns.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
10f74e101Schristos /*
20f74e101Schristos  * Copyright (c) 1992, 1993, 1994, 1995, 1996
30f74e101Schristos  *	The Regents of the University of California.  All rights reserved.
40f74e101Schristos  *
50f74e101Schristos  * Redistribution and use in source and binary forms, with or without
60f74e101Schristos  * modification, are permitted provided that: (1) source code distributions
70f74e101Schristos  * retain the above copyright notice and this paragraph in its entirety, (2)
80f74e101Schristos  * distributions including binary code include the above copyright notice and
90f74e101Schristos  * this paragraph in its entirety in the documentation or other materials
100f74e101Schristos  * provided with the distribution, and (3) all advertising materials mentioning
110f74e101Schristos  * features or use of this software display the following acknowledgement:
120f74e101Schristos  * ``This product includes software developed by the University of California,
130f74e101Schristos  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
140f74e101Schristos  * the University nor the names of its contributors may be used to endorse
150f74e101Schristos  * or promote products derived from this software without specific prior
160f74e101Schristos  * written permission.
170f74e101Schristos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
180f74e101Schristos  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
190f74e101Schristos  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
200f74e101Schristos  *
210f74e101Schristos  * Original code by Matt Thomas, Digital Equipment Corporation
220f74e101Schristos  *
2372c96ff3Schristos  * Extensively modified by Hannes Gredler (hannes@gredler.at) for more
240f74e101Schristos  * complete IS-IS & CLNP support.
250f74e101Schristos  */
260f74e101Schristos 
2711b3aaa1Schristos #include <sys/cdefs.h>
280f74e101Schristos #ifndef lint
29*26ba0b50Schristos __RCSID("$NetBSD: print-isoclns.c,v 1.11 2024/09/02 16:15:31 christos Exp $");
300f74e101Schristos #endif
310f74e101Schristos 
32dc860a36Sspz /* \summary: ISO CLNS, ESIS, and ISIS printer */
33dc860a36Sspz 
34c74ad251Schristos /*
35c74ad251Schristos  * specification:
36c74ad251Schristos  *
37c74ad251Schristos  * CLNP: ISO 8473 (respective ITU version is at https://www.itu.int/rec/T-REC-X.233/en/)
38c74ad251Schristos  * ES-IS: ISO 9542
39c74ad251Schristos  * IS-IS: ISO 10589
40c74ad251Schristos  */
41c74ad251Schristos 
42c74ad251Schristos #include <config.h>
430f74e101Schristos 
44c74ad251Schristos #include "netdissect-stdinc.h"
450f74e101Schristos 
460f74e101Schristos #include <string.h>
470f74e101Schristos 
48fdccd7e4Schristos #include "netdissect.h"
490f74e101Schristos #include "addrtoname.h"
500f74e101Schristos #include "nlpid.h"
510f74e101Schristos #include "extract.h"
520f74e101Schristos #include "gmpls.h"
530f74e101Schristos #include "oui.h"
540f74e101Schristos #include "signature.h"
550f74e101Schristos 
56fdccd7e4Schristos 
570f74e101Schristos /*
580f74e101Schristos  * IS-IS is defined in ISO 10589.  Look there for protocol definitions.
590f74e101Schristos  */
600f74e101Schristos 
61c74ad251Schristos #define SYSTEM_ID_LEN	MAC_ADDR_LEN
62c74ad251Schristos #define NODE_ID_LEN     (SYSTEM_ID_LEN+1)
63c74ad251Schristos #define LSP_ID_LEN      (SYSTEM_ID_LEN+2)
640f74e101Schristos 
650f74e101Schristos #define ISIS_VERSION	1
660f74e101Schristos #define ESIS_VERSION	1
670f74e101Schristos #define CLNP_VERSION	1
680f74e101Schristos 
690f74e101Schristos #define ISIS_PDU_TYPE_MASK      0x1F
700f74e101Schristos #define ESIS_PDU_TYPE_MASK      0x1F
710f74e101Schristos #define CLNP_PDU_TYPE_MASK      0x1F
720f74e101Schristos #define CLNP_FLAG_MASK          0xE0
730f74e101Schristos #define ISIS_LAN_PRIORITY_MASK  0x7F
740f74e101Schristos 
750f74e101Schristos #define ISIS_PDU_L1_LAN_IIH	15
760f74e101Schristos #define ISIS_PDU_L2_LAN_IIH	16
770f74e101Schristos #define ISIS_PDU_PTP_IIH	17
780f74e101Schristos #define ISIS_PDU_L1_LSP		18
790f74e101Schristos #define ISIS_PDU_L2_LSP		20
800f74e101Schristos #define ISIS_PDU_L1_CSNP	24
810f74e101Schristos #define ISIS_PDU_L2_CSNP	25
820f74e101Schristos #define ISIS_PDU_L1_PSNP        26
830f74e101Schristos #define ISIS_PDU_L2_PSNP        27
840f74e101Schristos 
85870189d2Schristos static const struct tok isis_pdu_values[] = {
860f74e101Schristos     { ISIS_PDU_L1_LAN_IIH,       "L1 Lan IIH"},
870f74e101Schristos     { ISIS_PDU_L2_LAN_IIH,       "L2 Lan IIH"},
880f74e101Schristos     { ISIS_PDU_PTP_IIH,          "p2p IIH"},
890f74e101Schristos     { ISIS_PDU_L1_LSP,           "L1 LSP"},
900f74e101Schristos     { ISIS_PDU_L2_LSP,           "L2 LSP"},
910f74e101Schristos     { ISIS_PDU_L1_CSNP,          "L1 CSNP"},
920f74e101Schristos     { ISIS_PDU_L2_CSNP,          "L2 CSNP"},
930f74e101Schristos     { ISIS_PDU_L1_PSNP,          "L1 PSNP"},
940f74e101Schristos     { ISIS_PDU_L2_PSNP,          "L2 PSNP"},
950f74e101Schristos     { 0, NULL}
960f74e101Schristos };
970f74e101Schristos 
980f74e101Schristos /*
990f74e101Schristos  * A TLV is a tuple of a type, length and a value and is normally used for
1000f74e101Schristos  * encoding information in all sorts of places.  This is an enumeration of
1010f74e101Schristos  * the well known types.
1020f74e101Schristos  *
1030f74e101Schristos  * list taken from rfc3359 plus some memory from veterans ;-)
1040f74e101Schristos  */
1050f74e101Schristos 
1060f74e101Schristos #define ISIS_TLV_AREA_ADDR           1   /* iso10589 */
1070f74e101Schristos #define ISIS_TLV_IS_REACH            2   /* iso10589 */
1080f74e101Schristos #define ISIS_TLV_ESNEIGH             3   /* iso10589 */
1090f74e101Schristos #define ISIS_TLV_PART_DIS            4   /* iso10589 */
1100f74e101Schristos #define ISIS_TLV_PREFIX_NEIGH        5   /* iso10589 */
1110f74e101Schristos #define ISIS_TLV_ISNEIGH             6   /* iso10589 */
112c74ad251Schristos #define ISIS_TLV_INSTANCE_ID         7   /* rfc8202 */
1130f74e101Schristos #define ISIS_TLV_PADDING             8   /* iso10589 */
1140f74e101Schristos #define ISIS_TLV_LSP                 9   /* iso10589 */
1150f74e101Schristos #define ISIS_TLV_AUTH                10  /* iso10589, rfc3567 */
1160f74e101Schristos #define ISIS_TLV_CHECKSUM            12  /* rfc3358 */
1170f74e101Schristos #define ISIS_TLV_CHECKSUM_MINLEN 2
118fdccd7e4Schristos #define ISIS_TLV_POI                 13  /* rfc6232 */
1190f74e101Schristos #define ISIS_TLV_LSP_BUFFERSIZE      14  /* iso10589 rev2 */
120c74ad251Schristos #define ISIS_TLV_EXT_IS_REACH        22  /* rfc5305 */
121c74ad251Schristos #define ISIS_TLV_IS_ALIAS_ID         24  /* rfc5311 */
1220f74e101Schristos #define ISIS_TLV_DECNET_PHASE4       42
1230f74e101Schristos #define ISIS_TLV_LUCENT_PRIVATE      66
1240f74e101Schristos #define ISIS_TLV_INT_IP_REACH        128 /* rfc1195, rfc2966 */
1250f74e101Schristos #define ISIS_TLV_PROTOCOLS           129 /* rfc1195 */
1260f74e101Schristos #define ISIS_TLV_EXT_IP_REACH        130 /* rfc1195, rfc2966 */
1270f74e101Schristos #define ISIS_TLV_IDRP_INFO           131 /* rfc1195 */
1280f74e101Schristos #define ISIS_TLV_IPADDR              132 /* rfc1195 */
1290f74e101Schristos #define ISIS_TLV_IPAUTH              133 /* rfc1195 */
130c74ad251Schristos #define ISIS_TLV_TE_ROUTER_ID        134 /* rfc5305 */
131c74ad251Schristos #define ISIS_TLV_EXTD_IP_REACH       135 /* rfc5305 */
1320f74e101Schristos #define ISIS_TLV_HOSTNAME            137 /* rfc2763 */
1330f74e101Schristos #define ISIS_TLV_SHARED_RISK_GROUP   138 /* draft-ietf-isis-gmpls-extensions */
134870189d2Schristos #define ISIS_TLV_MT_PORT_CAP         143 /* rfc6165 */
135870189d2Schristos #define ISIS_TLV_MT_CAPABILITY       144 /* rfc6329 */
1360f74e101Schristos #define ISIS_TLV_NORTEL_PRIVATE1     176
1370f74e101Schristos #define ISIS_TLV_NORTEL_PRIVATE2     177
1380f74e101Schristos #define ISIS_TLV_RESTART_SIGNALING   211 /* rfc3847 */
1390f74e101Schristos #define ISIS_TLV_RESTART_SIGNALING_FLAGLEN 1
1400f74e101Schristos #define ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN 2
1410f74e101Schristos #define ISIS_TLV_MT_IS_REACH         222 /* draft-ietf-isis-wg-multi-topology-05 */
1420f74e101Schristos #define ISIS_TLV_MT_SUPPORTED        229 /* draft-ietf-isis-wg-multi-topology-05 */
1430f74e101Schristos #define ISIS_TLV_IP6ADDR             232 /* draft-ietf-isis-ipv6-02 */
1440f74e101Schristos #define ISIS_TLV_MT_IP_REACH         235 /* draft-ietf-isis-wg-multi-topology-05 */
1450f74e101Schristos #define ISIS_TLV_IP6_REACH           236 /* draft-ietf-isis-ipv6-02 */
1460f74e101Schristos #define ISIS_TLV_MT_IP6_REACH        237 /* draft-ietf-isis-wg-multi-topology-05 */
1470f74e101Schristos #define ISIS_TLV_PTP_ADJ             240 /* rfc3373 */
1480f74e101Schristos #define ISIS_TLV_IIH_SEQNR           241 /* draft-shen-isis-iih-sequence-00 */
149c74ad251Schristos #define ISIS_TLV_ROUTER_CAPABILITY   242 /* rfc7981 */
1500f74e101Schristos #define ISIS_TLV_VENDOR_PRIVATE      250 /* draft-ietf-isis-experimental-tlv-01 */
1510f74e101Schristos #define ISIS_TLV_VENDOR_PRIVATE_MINLEN 3
1520f74e101Schristos 
153870189d2Schristos static const struct tok isis_tlv_values[] = {
1540f74e101Schristos     { ISIS_TLV_AREA_ADDR,	   "Area address(es)"},
1550f74e101Schristos     { ISIS_TLV_IS_REACH,           "IS Reachability"},
1560f74e101Schristos     { ISIS_TLV_ESNEIGH,            "ES Neighbor(s)"},
1570f74e101Schristos     { ISIS_TLV_PART_DIS,           "Partition DIS"},
1580f74e101Schristos     { ISIS_TLV_PREFIX_NEIGH,       "Prefix Neighbors"},
1590f74e101Schristos     { ISIS_TLV_ISNEIGH,            "IS Neighbor(s)"},
160c74ad251Schristos     { ISIS_TLV_INSTANCE_ID,        "Instance Identifier"},
1610f74e101Schristos     { ISIS_TLV_PADDING,            "Padding"},
1620f74e101Schristos     { ISIS_TLV_LSP,                "LSP entries"},
1630f74e101Schristos     { ISIS_TLV_AUTH,               "Authentication"},
1640f74e101Schristos     { ISIS_TLV_CHECKSUM,           "Checksum"},
165fdccd7e4Schristos     { ISIS_TLV_POI,                "Purge Originator Identifier"},
1660f74e101Schristos     { ISIS_TLV_LSP_BUFFERSIZE,     "LSP Buffersize"},
1670f74e101Schristos     { ISIS_TLV_EXT_IS_REACH,       "Extended IS Reachability"},
1680f74e101Schristos     { ISIS_TLV_IS_ALIAS_ID,        "IS Alias ID"},
1690f74e101Schristos     { ISIS_TLV_DECNET_PHASE4,      "DECnet Phase IV"},
1700f74e101Schristos     { ISIS_TLV_LUCENT_PRIVATE,     "Lucent Proprietary"},
1710f74e101Schristos     { ISIS_TLV_INT_IP_REACH,       "IPv4 Internal Reachability"},
1720f74e101Schristos     { ISIS_TLV_PROTOCOLS,          "Protocols supported"},
1730f74e101Schristos     { ISIS_TLV_EXT_IP_REACH,       "IPv4 External Reachability"},
1740f74e101Schristos     { ISIS_TLV_IDRP_INFO,          "Inter-Domain Information Type"},
1750f74e101Schristos     { ISIS_TLV_IPADDR,             "IPv4 Interface address(es)"},
1760f74e101Schristos     { ISIS_TLV_IPAUTH,             "IPv4 authentication (deprecated)"},
1770f74e101Schristos     { ISIS_TLV_TE_ROUTER_ID,       "Traffic Engineering Router ID"},
1780f74e101Schristos     { ISIS_TLV_EXTD_IP_REACH,      "Extended IPv4 Reachability"},
1790f74e101Schristos     { ISIS_TLV_SHARED_RISK_GROUP,  "Shared Risk Link Group"},
180870189d2Schristos     { ISIS_TLV_MT_PORT_CAP,        "Multi-Topology-Aware Port Capability"},
181870189d2Schristos     { ISIS_TLV_MT_CAPABILITY,      "Multi-Topology Capability"},
1820f74e101Schristos     { ISIS_TLV_NORTEL_PRIVATE1,    "Nortel Proprietary"},
1830f74e101Schristos     { ISIS_TLV_NORTEL_PRIVATE2,    "Nortel Proprietary"},
1840f74e101Schristos     { ISIS_TLV_HOSTNAME,           "Hostname"},
1850f74e101Schristos     { ISIS_TLV_RESTART_SIGNALING,  "Restart Signaling"},
1860f74e101Schristos     { ISIS_TLV_MT_IS_REACH,        "Multi Topology IS Reachability"},
1870f74e101Schristos     { ISIS_TLV_MT_SUPPORTED,       "Multi Topology"},
1880f74e101Schristos     { ISIS_TLV_IP6ADDR,            "IPv6 Interface address(es)"},
1890f74e101Schristos     { ISIS_TLV_MT_IP_REACH,        "Multi-Topology IPv4 Reachability"},
1900f74e101Schristos     { ISIS_TLV_IP6_REACH,          "IPv6 reachability"},
1910f74e101Schristos     { ISIS_TLV_MT_IP6_REACH,       "Multi-Topology IP6 Reachability"},
1920f74e101Schristos     { ISIS_TLV_PTP_ADJ,            "Point-to-point Adjacency State"},
1930f74e101Schristos     { ISIS_TLV_IIH_SEQNR,          "Hello PDU Sequence Number"},
194c74ad251Schristos     { ISIS_TLV_ROUTER_CAPABILITY,  "IS-IS Router Capability"},
1950f74e101Schristos     { ISIS_TLV_VENDOR_PRIVATE,     "Vendor Private"},
1960f74e101Schristos     { 0, NULL }
1970f74e101Schristos };
1980f74e101Schristos 
1990f74e101Schristos #define ESIS_OPTION_PROTOCOLS        129
2000f74e101Schristos #define ESIS_OPTION_QOS_MAINTENANCE  195 /* iso9542 */
2010f74e101Schristos #define ESIS_OPTION_SECURITY         197 /* iso9542 */
2020f74e101Schristos #define ESIS_OPTION_ES_CONF_TIME     198 /* iso9542 */
2030f74e101Schristos #define ESIS_OPTION_PRIORITY         205 /* iso9542 */
2040f74e101Schristos #define ESIS_OPTION_ADDRESS_MASK     225 /* iso9542 */
2050f74e101Schristos #define ESIS_OPTION_SNPA_MASK        226 /* iso9542 */
2060f74e101Schristos 
207870189d2Schristos static const struct tok esis_option_values[] = {
2080f74e101Schristos     { ESIS_OPTION_PROTOCOLS,       "Protocols supported"},
2090f74e101Schristos     { ESIS_OPTION_QOS_MAINTENANCE, "QoS Maintenance" },
2100f74e101Schristos     { ESIS_OPTION_SECURITY,        "Security" },
2110f74e101Schristos     { ESIS_OPTION_ES_CONF_TIME,    "ES Configuration Time" },
2120f74e101Schristos     { ESIS_OPTION_PRIORITY,        "Priority" },
213*26ba0b50Schristos     { ESIS_OPTION_ADDRESS_MASK,    "Address Mask" },
2140f74e101Schristos     { ESIS_OPTION_SNPA_MASK,       "SNPA Mask" },
2150f74e101Schristos     { 0, NULL }
2160f74e101Schristos };
2170f74e101Schristos 
2180f74e101Schristos #define CLNP_OPTION_DISCARD_REASON   193
2190f74e101Schristos #define CLNP_OPTION_QOS_MAINTENANCE  195 /* iso8473 */
2200f74e101Schristos #define CLNP_OPTION_SECURITY         197 /* iso8473 */
2210f74e101Schristos #define CLNP_OPTION_SOURCE_ROUTING   200 /* iso8473 */
2220f74e101Schristos #define CLNP_OPTION_ROUTE_RECORDING  203 /* iso8473 */
2230f74e101Schristos #define CLNP_OPTION_PADDING          204 /* iso8473 */
2240f74e101Schristos #define CLNP_OPTION_PRIORITY         205 /* iso8473 */
2250f74e101Schristos 
226870189d2Schristos static const struct tok clnp_option_values[] = {
2270f74e101Schristos     { CLNP_OPTION_DISCARD_REASON,  "Discard Reason"},
2280f74e101Schristos     { CLNP_OPTION_PRIORITY,        "Priority"},
2290f74e101Schristos     { CLNP_OPTION_QOS_MAINTENANCE, "QoS Maintenance"},
2300f74e101Schristos     { CLNP_OPTION_SECURITY, "Security"},
2310f74e101Schristos     { CLNP_OPTION_SOURCE_ROUTING, "Source Routing"},
2320f74e101Schristos     { CLNP_OPTION_ROUTE_RECORDING, "Route Recording"},
2330f74e101Schristos     { CLNP_OPTION_PADDING, "Padding"},
2340f74e101Schristos     { 0, NULL }
2350f74e101Schristos };
2360f74e101Schristos 
237870189d2Schristos static const struct tok clnp_option_rfd_class_values[] = {
2380f74e101Schristos     { 0x0, "General"},
2390f74e101Schristos     { 0x8, "Address"},
2400f74e101Schristos     { 0x9, "Source Routeing"},
2410f74e101Schristos     { 0xa, "Lifetime"},
2420f74e101Schristos     { 0xb, "PDU Discarded"},
2430f74e101Schristos     { 0xc, "Reassembly"},
2440f74e101Schristos     { 0, NULL }
2450f74e101Schristos };
2460f74e101Schristos 
247870189d2Schristos static const struct tok clnp_option_rfd_general_values[] = {
2480f74e101Schristos     { 0x0, "Reason not specified"},
2490f74e101Schristos     { 0x1, "Protocol procedure error"},
2500f74e101Schristos     { 0x2, "Incorrect checksum"},
2510f74e101Schristos     { 0x3, "PDU discarded due to congestion"},
2520f74e101Schristos     { 0x4, "Header syntax error (cannot be parsed)"},
2530f74e101Schristos     { 0x5, "Segmentation needed but not permitted"},
2540f74e101Schristos     { 0x6, "Incomplete PDU received"},
2550f74e101Schristos     { 0x7, "Duplicate option"},
2560f74e101Schristos     { 0, NULL }
2570f74e101Schristos };
2580f74e101Schristos 
259870189d2Schristos static const struct tok clnp_option_rfd_address_values[] = {
2600f74e101Schristos     { 0x0, "Destination address unreachable"},
2610f74e101Schristos     { 0x1, "Destination address unknown"},
2620f74e101Schristos     { 0, NULL }
2630f74e101Schristos };
2640f74e101Schristos 
265870189d2Schristos static const struct tok clnp_option_rfd_source_routeing_values[] = {
2660f74e101Schristos     { 0x0, "Unspecified source routeing error"},
2670f74e101Schristos     { 0x1, "Syntax error in source routeing field"},
2680f74e101Schristos     { 0x2, "Unknown address in source routeing field"},
2690f74e101Schristos     { 0x3, "Path not acceptable"},
2700f74e101Schristos     { 0, NULL }
2710f74e101Schristos };
2720f74e101Schristos 
273870189d2Schristos static const struct tok clnp_option_rfd_lifetime_values[] = {
2740f74e101Schristos     { 0x0, "Lifetime expired while data unit in transit"},
2750f74e101Schristos     { 0x1, "Lifetime expired during reassembly"},
2760f74e101Schristos     { 0, NULL }
2770f74e101Schristos };
2780f74e101Schristos 
279870189d2Schristos static const struct tok clnp_option_rfd_pdu_discard_values[] = {
2800f74e101Schristos     { 0x0, "Unsupported option not specified"},
2810f74e101Schristos     { 0x1, "Unsupported protocol version"},
2820f74e101Schristos     { 0x2, "Unsupported security option"},
2830f74e101Schristos     { 0x3, "Unsupported source routeing option"},
2840f74e101Schristos     { 0x4, "Unsupported recording of route option"},
2850f74e101Schristos     { 0, NULL }
2860f74e101Schristos };
2870f74e101Schristos 
288870189d2Schristos static const struct tok clnp_option_rfd_reassembly_values[] = {
2890f74e101Schristos     { 0x0, "Reassembly interference"},
2900f74e101Schristos     { 0, NULL }
2910f74e101Schristos };
2920f74e101Schristos 
2930f74e101Schristos /* array of 16 error-classes */
294870189d2Schristos static const struct tok *clnp_option_rfd_error_class[] = {
2950f74e101Schristos     clnp_option_rfd_general_values,
2960f74e101Schristos     NULL,
2970f74e101Schristos     NULL,
2980f74e101Schristos     NULL,
2990f74e101Schristos     NULL,
3000f74e101Schristos     NULL,
3010f74e101Schristos     NULL,
3020f74e101Schristos     NULL,
3030f74e101Schristos     clnp_option_rfd_address_values,
3040f74e101Schristos     clnp_option_rfd_source_routeing_values,
3050f74e101Schristos     clnp_option_rfd_lifetime_values,
3060f74e101Schristos     clnp_option_rfd_pdu_discard_values,
3070f74e101Schristos     clnp_option_rfd_reassembly_values,
3080f74e101Schristos     NULL,
3090f74e101Schristos     NULL,
3100f74e101Schristos     NULL
3110f74e101Schristos };
3120f74e101Schristos 
3130f74e101Schristos #define CLNP_OPTION_OPTION_QOS_MASK 0x3f
3140f74e101Schristos #define CLNP_OPTION_SCOPE_MASK      0xc0
3150f74e101Schristos #define CLNP_OPTION_SCOPE_SA_SPEC   0x40
3160f74e101Schristos #define CLNP_OPTION_SCOPE_DA_SPEC   0x80
3170f74e101Schristos #define CLNP_OPTION_SCOPE_GLOBAL    0xc0
3180f74e101Schristos 
319870189d2Schristos static const struct tok clnp_option_scope_values[] = {
3200f74e101Schristos     { CLNP_OPTION_SCOPE_SA_SPEC, "Source Address Specific"},
3210f74e101Schristos     { CLNP_OPTION_SCOPE_DA_SPEC, "Destination Address Specific"},
3220f74e101Schristos     { CLNP_OPTION_SCOPE_GLOBAL, "Globally unique"},
3230f74e101Schristos     { 0, NULL }
3240f74e101Schristos };
3250f74e101Schristos 
326870189d2Schristos static const struct tok clnp_option_sr_rr_values[] = {
3270f74e101Schristos     { 0x0, "partial"},
3280f74e101Schristos     { 0x1, "complete"},
3290f74e101Schristos     { 0, NULL }
3300f74e101Schristos };
3310f74e101Schristos 
332870189d2Schristos static const struct tok clnp_option_sr_rr_string_values[] = {
3330f74e101Schristos     { CLNP_OPTION_SOURCE_ROUTING, "source routing"},
3340f74e101Schristos     { CLNP_OPTION_ROUTE_RECORDING, "recording of route in progress"},
3350f74e101Schristos     { 0, NULL }
3360f74e101Schristos };
3370f74e101Schristos 
338870189d2Schristos static const struct tok clnp_option_qos_global_values[] = {
3390f74e101Schristos     { 0x20, "reserved"},
3400f74e101Schristos     { 0x10, "sequencing vs. delay"},
3410f74e101Schristos     { 0x08, "congested"},
3420f74e101Schristos     { 0x04, "delay vs. cost"},
3430f74e101Schristos     { 0x02, "error vs. delay"},
3440f74e101Schristos     { 0x01, "error vs. cost"},
3450f74e101Schristos     { 0, NULL }
3460f74e101Schristos };
3470f74e101Schristos 
348c74ad251Schristos static const struct tok isis_tlv_router_capability_flags[] = {
349c74ad251Schristos     { 0x01, "S bit"},
350c74ad251Schristos     { 0x02, "D bit"},
351c74ad251Schristos     { 0, NULL }
352c74ad251Schristos };
353c74ad251Schristos 
354c74ad251Schristos #define ISIS_SUBTLV_ROUTER_CAP_SR 2 /* rfc 8667 */
355c74ad251Schristos 
356c74ad251Schristos static const struct tok isis_router_capability_subtlv_values[] = {
357c74ad251Schristos     { ISIS_SUBTLV_ROUTER_CAP_SR, "SR-Capabilities"},
358c74ad251Schristos     { 0, NULL }
359c74ad251Schristos };
360c74ad251Schristos 
361c74ad251Schristos static const struct tok isis_router_capability_sr_flags[] = {
362c74ad251Schristos     { 0x80, "ipv4"},
363c74ad251Schristos     { 0x40, "ipv6"},
364c74ad251Schristos     { 0, NULL }
365c74ad251Schristos };
366c74ad251Schristos 
367c74ad251Schristos #define ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP           3 /* rfc5305 */
3680f74e101Schristos #define ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID  4 /* rfc4205 */
369c74ad251Schristos #define ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID        5 /* rfc5305 */
370c74ad251Schristos #define ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR        6 /* rfc5305 */
371c74ad251Schristos #define ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR    8 /* rfc5305 */
372c74ad251Schristos #define ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW           9 /* rfc5305 */
373c74ad251Schristos #define ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW        10 /* rfc5305 */
3740f74e101Schristos #define ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW        11 /* rfc4124 */
3750f74e101Schristos #define ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS_OLD   12 /* draft-ietf-tewg-diff-te-proto-06 */
376c74ad251Schristos #define ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC            18 /* rfc5305 */
3770f74e101Schristos #define ISIS_SUBTLV_EXT_IS_REACH_LINK_ATTRIBUTE       19 /* draft-ietf-isis-link-attr-01 */
3780f74e101Schristos #define ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE 20 /* rfc4205 */
3790f74e101Schristos #define ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR    21 /* rfc4205 */
3800f74e101Schristos #define ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS       22 /* rfc4124 */
381c74ad251Schristos #define ISIS_SUBTLV_EXT_IS_REACH_LAN_ADJ_SEGMENT_ID   32 /* rfc8667 */
3820f74e101Schristos 
383870189d2Schristos #define ISIS_SUBTLV_SPB_METRIC                        29 /* rfc6329 */
384870189d2Schristos 
385870189d2Schristos static const struct tok isis_ext_is_reach_subtlv_values[] = {
3860f74e101Schristos     { ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP,            "Administrative groups" },
3870f74e101Schristos     { ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID,   "Link Local/Remote Identifier" },
3880f74e101Schristos     { ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID,         "Link Remote Identifier" },
3890f74e101Schristos     { ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR,         "IPv4 interface address" },
3900f74e101Schristos     { ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR,     "IPv4 neighbor address" },
3910f74e101Schristos     { ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW,            "Maximum link bandwidth" },
3920f74e101Schristos     { ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW,          "Reservable link bandwidth" },
3930f74e101Schristos     { ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW,          "Unreserved bandwidth" },
3940f74e101Schristos     { ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC,              "Traffic Engineering Metric" },
3950f74e101Schristos     { ISIS_SUBTLV_EXT_IS_REACH_LINK_ATTRIBUTE,         "Link Attribute" },
3960f74e101Schristos     { ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE,   "Link Protection Type" },
3970f74e101Schristos     { ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR,      "Interface Switching Capability" },
3980f74e101Schristos     { ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS_OLD,     "Bandwidth Constraints (old)" },
3990f74e101Schristos     { ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS,         "Bandwidth Constraints" },
400c74ad251Schristos     { ISIS_SUBTLV_EXT_IS_REACH_LAN_ADJ_SEGMENT_ID,     "LAN Adjacency Segment Identifier" },
401870189d2Schristos     { ISIS_SUBTLV_SPB_METRIC,                          "SPB Metric" },
4020f74e101Schristos     { 250,                                             "Reserved for cisco specific extensions" },
4030f74e101Schristos     { 251,                                             "Reserved for cisco specific extensions" },
4040f74e101Schristos     { 252,                                             "Reserved for cisco specific extensions" },
4050f74e101Schristos     { 253,                                             "Reserved for cisco specific extensions" },
4060f74e101Schristos     { 254,                                             "Reserved for cisco specific extensions" },
4070f74e101Schristos     { 255,                                             "Reserved for future expansion" },
4080f74e101Schristos     { 0, NULL }
4090f74e101Schristos };
4100f74e101Schristos 
4110f74e101Schristos #define ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32          1 /* draft-ietf-isis-admin-tags-01 */
4120f74e101Schristos #define ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64          2 /* draft-ietf-isis-admin-tags-01 */
413c74ad251Schristos #define ISIS_SUBTLV_EXTD_IP_REACH_PREFIX_SID           3 /* rfc8667 */
4140f74e101Schristos #define ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR  117 /* draft-ietf-isis-wg-multi-topology-05 */
4150f74e101Schristos 
416870189d2Schristos static const struct tok isis_ext_ip_reach_subtlv_values[] = {
4170f74e101Schristos     { ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32,           "32-Bit Administrative tag" },
4180f74e101Schristos     { ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64,           "64-Bit Administrative tag" },
419c74ad251Schristos     { ISIS_SUBTLV_EXTD_IP_REACH_PREFIX_SID,            "Prefix SID" },
4200f74e101Schristos     { ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR,     "Management Prefix Color" },
4210f74e101Schristos     { 0, NULL }
4220f74e101Schristos };
4230f74e101Schristos 
424c74ad251Schristos #define ISIS_PREFIX_SID_FLAG_R 0x80 /* rfc 8667 */
425c74ad251Schristos #define ISIS_PREFIX_SID_FLAG_N 0x40 /* rfc 8667 */
426c74ad251Schristos #define ISIS_PREFIX_SID_FLAG_P 0x20 /* rfc 8667 */
427c74ad251Schristos #define ISIS_PREFIX_SID_FLAG_E 0x10 /* rfc 8667 */
428c74ad251Schristos #define ISIS_PREFIX_SID_FLAG_V 0x08 /* rfc 8667 */
429c74ad251Schristos #define ISIS_PREFIX_SID_FLAG_L 0x04 /* rfc 8667 */
430c74ad251Schristos 
431c74ad251Schristos static const struct tok prefix_sid_flag_values[] = {
432c74ad251Schristos     { ISIS_PREFIX_SID_FLAG_R, "Readvertisement"},
433c74ad251Schristos     { ISIS_PREFIX_SID_FLAG_N, "Node"},
434c74ad251Schristos     { ISIS_PREFIX_SID_FLAG_P, "No-PHP"},
435c74ad251Schristos     { ISIS_PREFIX_SID_FLAG_E, "Explicit NULL"},
436c74ad251Schristos     { ISIS_PREFIX_SID_FLAG_V, "Value"},
437c74ad251Schristos     { ISIS_PREFIX_SID_FLAG_L, "Local"},
438c74ad251Schristos     { 0, NULL}
439c74ad251Schristos };
440c74ad251Schristos 
441c74ad251Schristos 
442c74ad251Schristos /* rfc 8667 */
443c74ad251Schristos static const struct tok prefix_sid_algo_values[] = {
444c74ad251Schristos     { 0, "SPF"},
445c74ad251Schristos     { 1, "strict-SPF"},
446c74ad251Schristos     { 0, NULL}
447c74ad251Schristos };
448c74ad251Schristos 
449870189d2Schristos static const struct tok isis_subtlv_link_attribute_values[] = {
4500f74e101Schristos     { 0x01, "Local Protection Available" },
4510f74e101Schristos     { 0x02, "Link excluded from local protection path" },
4520f74e101Schristos     { 0x04, "Local maintenance required"},
4530f74e101Schristos     { 0, NULL }
4540f74e101Schristos };
4550f74e101Schristos 
456c74ad251Schristos static const struct tok isis_lan_adj_sid_flag_values[] = {
457c74ad251Schristos     { 0x80, "Address family IPv6" },
458c74ad251Schristos     { 0x40, "Backup" },
459c74ad251Schristos     { 0x20, "Value" },
460c74ad251Schristos     { 0x10, "Local significance" },
461c74ad251Schristos     { 0x08, "Set of adjacencies" },
462c74ad251Schristos     { 0x04, "Persistent" },
463c74ad251Schristos     { 0, NULL }
464c74ad251Schristos };
465c74ad251Schristos 
4660f74e101Schristos #define ISIS_SUBTLV_AUTH_SIMPLE        1
4670e9868baSchristos #define ISIS_SUBTLV_AUTH_GENERIC       3 /* rfc 5310 */
4680f74e101Schristos #define ISIS_SUBTLV_AUTH_MD5          54
4690f74e101Schristos #define ISIS_SUBTLV_AUTH_MD5_LEN      16
4700f74e101Schristos #define ISIS_SUBTLV_AUTH_PRIVATE     255
4710f74e101Schristos 
472870189d2Schristos static const struct tok isis_subtlv_auth_values[] = {
4730f74e101Schristos     { ISIS_SUBTLV_AUTH_SIMPLE,	"simple text password"},
4740e9868baSchristos     { ISIS_SUBTLV_AUTH_GENERIC, "Generic Crypto key-id"},
4750f74e101Schristos     { ISIS_SUBTLV_AUTH_MD5,	"HMAC-MD5 password"},
4760f74e101Schristos     { ISIS_SUBTLV_AUTH_PRIVATE,	"Routing Domain private password"},
4770f74e101Schristos     { 0, NULL }
4780f74e101Schristos };
4790f74e101Schristos 
4800f74e101Schristos #define ISIS_SUBTLV_IDRP_RES           0
4810f74e101Schristos #define ISIS_SUBTLV_IDRP_LOCAL         1
4820f74e101Schristos #define ISIS_SUBTLV_IDRP_ASN           2
4830f74e101Schristos 
484870189d2Schristos static const struct tok isis_subtlv_idrp_values[] = {
4850f74e101Schristos     { ISIS_SUBTLV_IDRP_RES,         "Reserved"},
4860f74e101Schristos     { ISIS_SUBTLV_IDRP_LOCAL,       "Routing-Domain Specific"},
4870f74e101Schristos     { ISIS_SUBTLV_IDRP_ASN,         "AS Number Tag"},
4880f74e101Schristos     { 0, NULL}
4890f74e101Schristos };
4900f74e101Schristos 
491870189d2Schristos #define ISIS_SUBTLV_SPB_MCID          4
492870189d2Schristos #define ISIS_SUBTLV_SPB_DIGEST        5
493870189d2Schristos #define ISIS_SUBTLV_SPB_BVID          6
494870189d2Schristos 
495870189d2Schristos #define ISIS_SUBTLV_SPB_INSTANCE      1
496870189d2Schristos #define ISIS_SUBTLV_SPBM_SI           3
497870189d2Schristos 
498870189d2Schristos #define ISIS_SPB_MCID_LEN                         51
499870189d2Schristos #define ISIS_SUBTLV_SPB_MCID_MIN_LEN              102
500870189d2Schristos #define ISIS_SUBTLV_SPB_DIGEST_MIN_LEN            33
501870189d2Schristos #define ISIS_SUBTLV_SPB_BVID_MIN_LEN              6
502870189d2Schristos #define ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN          19
503870189d2Schristos #define ISIS_SUBTLV_SPB_INSTANCE_VLAN_TUPLE_LEN   8
504870189d2Schristos 
505870189d2Schristos static const struct tok isis_mt_port_cap_subtlv_values[] = {
506870189d2Schristos     { ISIS_SUBTLV_SPB_MCID,           "SPB MCID" },
507870189d2Schristos     { ISIS_SUBTLV_SPB_DIGEST,         "SPB Digest" },
508870189d2Schristos     { ISIS_SUBTLV_SPB_BVID,           "SPB BVID" },
509870189d2Schristos     { 0, NULL }
510870189d2Schristos };
511870189d2Schristos 
512870189d2Schristos static const struct tok isis_mt_capability_subtlv_values[] = {
513870189d2Schristos     { ISIS_SUBTLV_SPB_INSTANCE,      "SPB Instance" },
514870189d2Schristos     { ISIS_SUBTLV_SPBM_SI,      "SPBM Service Identifier and Unicast Address" },
515870189d2Schristos     { 0, NULL }
516870189d2Schristos };
517870189d2Schristos 
518870189d2Schristos struct isis_spb_mcid {
519c74ad251Schristos   nd_uint8_t  format_id;
520c74ad251Schristos   nd_byte     name[32];
521c74ad251Schristos   nd_uint16_t revision_lvl;
522c74ad251Schristos   nd_byte     digest[16];
523870189d2Schristos };
524870189d2Schristos 
525870189d2Schristos struct isis_subtlv_spb_mcid {
526870189d2Schristos   struct isis_spb_mcid mcid;
527870189d2Schristos   struct isis_spb_mcid aux_mcid;
528870189d2Schristos };
529870189d2Schristos 
530870189d2Schristos struct isis_subtlv_spb_instance {
531c74ad251Schristos   nd_byte     cist_root_id[8];
532c74ad251Schristos   nd_uint32_t cist_external_root_path_cost;
533c74ad251Schristos   nd_uint16_t bridge_priority;
534c74ad251Schristos   nd_uint32_t spsourceid;
535c74ad251Schristos   nd_uint8_t  no_of_trees;
536870189d2Schristos };
537870189d2Schristos 
5380f74e101Schristos #define CLNP_SEGMENT_PART  0x80
5390f74e101Schristos #define CLNP_MORE_SEGMENTS 0x40
5400f74e101Schristos #define CLNP_REQUEST_ER    0x20
5410f74e101Schristos 
542870189d2Schristos static const struct tok clnp_flag_values[] = {
5430f74e101Schristos     { CLNP_SEGMENT_PART, "Segmentation permitted"},
5440f74e101Schristos     { CLNP_MORE_SEGMENTS, "more Segments"},
5450f74e101Schristos     { CLNP_REQUEST_ER, "request Error Report"},
5460f74e101Schristos     { 0, NULL}
5470f74e101Schristos };
5480f74e101Schristos 
549c74ad251Schristos #define ISIS_MASK_LSP_OL_BIT(x)            (GET_U_1(x)&0x4)
550c74ad251Schristos #define ISIS_MASK_LSP_ISTYPE_BITS(x)       (GET_U_1(x)&0x3)
551c74ad251Schristos #define ISIS_MASK_LSP_PARTITION_BIT(x)     (GET_U_1(x)&0x80)
552c74ad251Schristos #define ISIS_MASK_LSP_ATT_BITS(x)          (GET_U_1(x)&0x78)
553c74ad251Schristos #define ISIS_MASK_LSP_ATT_ERROR_BIT(x)     (GET_U_1(x)&0x40)
554c74ad251Schristos #define ISIS_MASK_LSP_ATT_EXPENSE_BIT(x)   (GET_U_1(x)&0x20)
555c74ad251Schristos #define ISIS_MASK_LSP_ATT_DELAY_BIT(x)     (GET_U_1(x)&0x10)
556c74ad251Schristos #define ISIS_MASK_LSP_ATT_DEFAULT_BIT(x)   (GET_U_1(x)&0x8)
5570f74e101Schristos 
5580f74e101Schristos #define ISIS_MASK_MTID(x)                  ((x)&0x0fff)
5590f74e101Schristos #define ISIS_MASK_MTFLAGS(x)               ((x)&0xf000)
5600f74e101Schristos 
561870189d2Schristos static const struct tok isis_mt_flag_values[] = {
5620e9868baSchristos     { 0x4000,                  "ATT bit set"},
5630e9868baSchristos     { 0x8000,                  "Overload bit set"},
5640f74e101Schristos     { 0, NULL}
5650f74e101Schristos };
5660f74e101Schristos 
5670f74e101Schristos #define ISIS_MASK_TLV_EXTD_IP_UPDOWN(x)     ((x)&0x80)
5680f74e101Schristos #define ISIS_MASK_TLV_EXTD_IP_SUBTLV(x)     ((x)&0x40)
5690f74e101Schristos 
5700f74e101Schristos #define ISIS_MASK_TLV_EXTD_IP6_IE(x)        ((x)&0x40)
5710f74e101Schristos #define ISIS_MASK_TLV_EXTD_IP6_SUBTLV(x)    ((x)&0x20)
5720f74e101Schristos 
573c74ad251Schristos #define ISIS_LSP_TLV_METRIC_SUPPORTED(x)   (GET_U_1(x)&0x80)
574c74ad251Schristos #define ISIS_LSP_TLV_METRIC_IE(x)          (GET_U_1(x)&0x40)
575c74ad251Schristos #define ISIS_LSP_TLV_METRIC_UPDOWN(x)      (GET_U_1(x)&0x80)
576c74ad251Schristos #define ISIS_LSP_TLV_METRIC_VALUE(x)	   (GET_U_1(x)&0x3f)
5770f74e101Schristos 
5780f74e101Schristos #define ISIS_MASK_TLV_SHARED_RISK_GROUP(x) ((x)&0x1)
5790f74e101Schristos 
580870189d2Schristos static const struct tok isis_mt_values[] = {
5810f74e101Schristos     { 0,    "IPv4 unicast"},
5820f74e101Schristos     { 1,    "In-Band Management"},
5830f74e101Schristos     { 2,    "IPv6 unicast"},
5840f74e101Schristos     { 3,    "Multicast"},
5850f74e101Schristos     { 4095, "Development, Experimental or Proprietary"},
5860f74e101Schristos     { 0, NULL }
5870f74e101Schristos };
5880f74e101Schristos 
589870189d2Schristos static const struct tok isis_iih_circuit_type_values[] = {
5900f74e101Schristos     { 1,    "Level 1 only"},
5910f74e101Schristos     { 2,    "Level 2 only"},
5920f74e101Schristos     { 3,    "Level 1, Level 2"},
5930f74e101Schristos     { 0, NULL}
5940f74e101Schristos };
5950f74e101Schristos 
5960f74e101Schristos #define ISIS_LSP_TYPE_UNUSED0   0
5970f74e101Schristos #define ISIS_LSP_TYPE_LEVEL_1   1
5980f74e101Schristos #define ISIS_LSP_TYPE_UNUSED2   2
5990f74e101Schristos #define ISIS_LSP_TYPE_LEVEL_2   3
6000f74e101Schristos 
601870189d2Schristos static const struct tok isis_lsp_istype_values[] = {
6020f74e101Schristos     { ISIS_LSP_TYPE_UNUSED0,	"Unused 0x0 (invalid)"},
6030f74e101Schristos     { ISIS_LSP_TYPE_LEVEL_1,	"L1 IS"},
6040f74e101Schristos     { ISIS_LSP_TYPE_UNUSED2,	"Unused 0x2 (invalid)"},
6050f74e101Schristos     { ISIS_LSP_TYPE_LEVEL_2,	"L2 IS"},
6060f74e101Schristos     { 0, NULL }
6070f74e101Schristos };
6080f74e101Schristos 
6090f74e101Schristos /*
6100f74e101Schristos  * Katz's point to point adjacency TLV uses codes to tell us the state of
6110f74e101Schristos  * the remote adjacency.  Enumerate them.
6120f74e101Schristos  */
6130f74e101Schristos 
6140f74e101Schristos #define ISIS_PTP_ADJ_UP   0
6150f74e101Schristos #define ISIS_PTP_ADJ_INIT 1
6160f74e101Schristos #define ISIS_PTP_ADJ_DOWN 2
6170f74e101Schristos 
618*26ba0b50Schristos static const struct tok isis_ptp_adjacency_values[] = {
6190f74e101Schristos     { ISIS_PTP_ADJ_UP,    "Up" },
6200f74e101Schristos     { ISIS_PTP_ADJ_INIT,  "Initializing" },
6210f74e101Schristos     { ISIS_PTP_ADJ_DOWN,  "Down" },
6220f74e101Schristos     { 0, NULL}
6230f74e101Schristos };
6240f74e101Schristos 
6250f74e101Schristos struct isis_tlv_ptp_adj {
626c74ad251Schristos     nd_uint8_t  adjacency_state;
627c74ad251Schristos     nd_uint32_t extd_local_circuit_id;
628c74ad251Schristos     nd_byte     neighbor_sysid[SYSTEM_ID_LEN];
629c74ad251Schristos     nd_uint32_t neighbor_extd_local_circuit_id;
6300f74e101Schristos };
6310f74e101Schristos 
63272c96ff3Schristos static void osi_print_cksum(netdissect_options *, const uint8_t *pptr,
63372c96ff3Schristos 			    uint16_t checksum, int checksum_offset, u_int length);
634b3a00663Schristos static int clnp_print(netdissect_options *, const uint8_t *, u_int);
635b3a00663Schristos static void esis_print(netdissect_options *, const uint8_t *, u_int);
636b3a00663Schristos static int isis_print(netdissect_options *, const uint8_t *, u_int);
6370f74e101Schristos 
6380f74e101Schristos struct isis_metric_block {
639c74ad251Schristos     nd_uint8_t metric_default;
640c74ad251Schristos     nd_uint8_t metric_delay;
641c74ad251Schristos     nd_uint8_t metric_expense;
642c74ad251Schristos     nd_uint8_t metric_error;
6430f74e101Schristos };
6440f74e101Schristos 
6450f74e101Schristos struct isis_tlv_is_reach {
6460f74e101Schristos     struct isis_metric_block isis_metric_block;
647c74ad251Schristos     nd_byte neighbor_nodeid[NODE_ID_LEN];
6480f74e101Schristos };
6490f74e101Schristos 
6500f74e101Schristos struct isis_tlv_es_reach {
6510f74e101Schristos     struct isis_metric_block isis_metric_block;
652c74ad251Schristos     nd_byte neighbor_sysid[SYSTEM_ID_LEN];
6530f74e101Schristos };
6540f74e101Schristos 
6550f74e101Schristos struct isis_tlv_ip_reach {
6560f74e101Schristos     struct isis_metric_block isis_metric_block;
657c74ad251Schristos     nd_ipv4 prefix;
658c74ad251Schristos     nd_ipv4 mask;
6590f74e101Schristos };
6600f74e101Schristos 
661870189d2Schristos static const struct tok isis_is_reach_virtual_values[] = {
6620f74e101Schristos     { 0,    "IsNotVirtual"},
6630f74e101Schristos     { 1,    "IsVirtual"},
6640f74e101Schristos     { 0, NULL }
6650f74e101Schristos };
6660f74e101Schristos 
667870189d2Schristos static const struct tok isis_restart_flag_values[] = {
6680f74e101Schristos     { 0x1,  "Restart Request"},
6690f74e101Schristos     { 0x2,  "Restart Acknowledgement"},
6700f74e101Schristos     { 0x4,  "Suppress adjacency advertisement"},
6710f74e101Schristos     { 0, NULL }
6720f74e101Schristos };
6730f74e101Schristos 
6740f74e101Schristos struct isis_common_header {
675c74ad251Schristos     nd_uint8_t nlpid;
676c74ad251Schristos     nd_uint8_t fixed_len;
677c74ad251Schristos     nd_uint8_t version;			/* Protocol version */
678c74ad251Schristos     nd_uint8_t id_length;
679c74ad251Schristos     nd_uint8_t pdu_type;		/* 3 MSbits are reserved */
680c74ad251Schristos     nd_uint8_t pdu_version;		/* Packet format version */
681c74ad251Schristos     nd_byte reserved;
682c74ad251Schristos     nd_uint8_t max_area;
6830f74e101Schristos };
6840f74e101Schristos 
6850f74e101Schristos struct isis_iih_lan_header {
686c74ad251Schristos     nd_uint8_t  circuit_type;
687c74ad251Schristos     nd_byte     source_id[SYSTEM_ID_LEN];
688c74ad251Schristos     nd_uint16_t holding_time;
689c74ad251Schristos     nd_uint16_t pdu_len;
690c74ad251Schristos     nd_uint8_t  priority;
691c74ad251Schristos     nd_byte     lan_id[NODE_ID_LEN];
6920f74e101Schristos };
6930f74e101Schristos 
6940f74e101Schristos struct isis_iih_ptp_header {
695c74ad251Schristos     nd_uint8_t  circuit_type;
696c74ad251Schristos     nd_byte     source_id[SYSTEM_ID_LEN];
697c74ad251Schristos     nd_uint16_t holding_time;
698c74ad251Schristos     nd_uint16_t pdu_len;
699c74ad251Schristos     nd_uint8_t  circuit_id;
7000f74e101Schristos };
7010f74e101Schristos 
7020f74e101Schristos struct isis_lsp_header {
703c74ad251Schristos     nd_uint16_t pdu_len;
704c74ad251Schristos     nd_uint16_t remaining_lifetime;
705c74ad251Schristos     nd_byte     lsp_id[LSP_ID_LEN];
706c74ad251Schristos     nd_uint32_t sequence_number;
707c74ad251Schristos     nd_uint16_t checksum;
708c74ad251Schristos     nd_uint8_t  typeblock;
7090f74e101Schristos };
7100f74e101Schristos 
7110f74e101Schristos struct isis_csnp_header {
712c74ad251Schristos     nd_uint16_t pdu_len;
713c74ad251Schristos     nd_byte     source_id[NODE_ID_LEN];
714c74ad251Schristos     nd_byte     start_lsp_id[LSP_ID_LEN];
715c74ad251Schristos     nd_byte     end_lsp_id[LSP_ID_LEN];
7160f74e101Schristos };
7170f74e101Schristos 
7180f74e101Schristos struct isis_psnp_header {
719c74ad251Schristos     nd_uint16_t pdu_len;
720c74ad251Schristos     nd_byte     source_id[NODE_ID_LEN];
7210f74e101Schristos };
7220f74e101Schristos 
7230f74e101Schristos struct isis_tlv_lsp {
724c74ad251Schristos     nd_uint16_t remaining_lifetime;
725c74ad251Schristos     nd_byte     lsp_id[LSP_ID_LEN];
726c74ad251Schristos     nd_uint32_t sequence_number;
727c74ad251Schristos     nd_uint16_t checksum;
7280f74e101Schristos };
7290f74e101Schristos 
7300f74e101Schristos #define ISIS_COMMON_HEADER_SIZE (sizeof(struct isis_common_header))
7310f74e101Schristos #define ISIS_IIH_LAN_HEADER_SIZE (sizeof(struct isis_iih_lan_header))
7320f74e101Schristos #define ISIS_IIH_PTP_HEADER_SIZE (sizeof(struct isis_iih_ptp_header))
7330f74e101Schristos #define ISIS_LSP_HEADER_SIZE (sizeof(struct isis_lsp_header))
7340f74e101Schristos #define ISIS_CSNP_HEADER_SIZE (sizeof(struct isis_csnp_header))
7350f74e101Schristos #define ISIS_PSNP_HEADER_SIZE (sizeof(struct isis_psnp_header))
7360f74e101Schristos 
737fdccd7e4Schristos void
738c74ad251Schristos isoclns_print(netdissect_options *ndo, const u_char *p, u_int length)
7390f74e101Schristos {
740c74ad251Schristos 	ndo->ndo_protocol = "isoclns";
7410f74e101Schristos 
742b3a00663Schristos 	if (ndo->ndo_eflag)
743c74ad251Schristos 		ND_PRINT("OSI NLPID %s (0x%02x): ",
744c74ad251Schristos 			 tok2str(nlpid_values, "Unknown", GET_U_1(p)),
745c74ad251Schristos 			 GET_U_1(p));
7460f74e101Schristos 
747c74ad251Schristos 	switch (GET_U_1(p)) {
7480f74e101Schristos 
7490f74e101Schristos 	case NLPID_CLNP:
750b3a00663Schristos 		if (!clnp_print(ndo, p, length))
75172c96ff3Schristos 			print_unknown_data(ndo, p, "\n\t", length);
7520f74e101Schristos 		break;
7530f74e101Schristos 
7540f74e101Schristos 	case NLPID_ESIS:
755b3a00663Schristos 		esis_print(ndo, p, length);
7560f74e101Schristos 		return;
7570f74e101Schristos 
7580f74e101Schristos 	case NLPID_ISIS:
759b3a00663Schristos 		if (!isis_print(ndo, p, length))
76072c96ff3Schristos 			print_unknown_data(ndo, p, "\n\t", length);
7610f74e101Schristos 		break;
7620f74e101Schristos 
7630f74e101Schristos 	case NLPID_NULLNS:
764c74ad251Schristos 		ND_PRINT("%slength: %u", ndo->ndo_eflag ? "" : ", ", length);
7650f74e101Schristos 		break;
7660f74e101Schristos 
7670f74e101Schristos 	case NLPID_Q933:
768b3a00663Schristos 		q933_print(ndo, p + 1, length - 1);
7690f74e101Schristos 		break;
7700f74e101Schristos 
7710f74e101Schristos 	case NLPID_IP:
772b3a00663Schristos 		ip_print(ndo, p + 1, length - 1);
7730f74e101Schristos 		break;
7740f74e101Schristos 
7750f74e101Schristos 	case NLPID_IP6:
776b3a00663Schristos 		ip6_print(ndo, p + 1, length - 1);
7770f74e101Schristos 		break;
7780f74e101Schristos 
7790f74e101Schristos 	case NLPID_PPP:
780b3a00663Schristos 		ppp_print(ndo, p + 1, length - 1);
7810f74e101Schristos 		break;
7820f74e101Schristos 
7830f74e101Schristos 	default:
784b3a00663Schristos 		if (!ndo->ndo_eflag)
785c74ad251Schristos 			ND_PRINT("OSI NLPID 0x%02x unknown", GET_U_1(p));
786c74ad251Schristos 		ND_PRINT("%slength: %u", ndo->ndo_eflag ? "" : ", ", length);
78772c96ff3Schristos 		if (length > 1)
78872c96ff3Schristos 			print_unknown_data(ndo, p, "\n\t", length);
7890f74e101Schristos 		break;
7900f74e101Schristos 	}
7910f74e101Schristos }
7920f74e101Schristos 
7930f74e101Schristos #define	CLNP_PDU_ER	 1
7940f74e101Schristos #define	CLNP_PDU_DT	28
7950f74e101Schristos #define	CLNP_PDU_MD	29
7960f74e101Schristos #define	CLNP_PDU_ERQ	30
7970f74e101Schristos #define	CLNP_PDU_ERP	31
7980f74e101Schristos 
799870189d2Schristos static const struct tok clnp_pdu_values[] = {
8000f74e101Schristos     { CLNP_PDU_ER,  "Error Report"},
8010f74e101Schristos     { CLNP_PDU_MD,  "MD"},
8020f74e101Schristos     { CLNP_PDU_DT,  "Data"},
8030f74e101Schristos     { CLNP_PDU_ERQ, "Echo Request"},
8040f74e101Schristos     { CLNP_PDU_ERP, "Echo Response"},
8050f74e101Schristos     { 0, NULL }
8060f74e101Schristos };
8070f74e101Schristos 
8080f74e101Schristos struct clnp_header_t {
809c74ad251Schristos     nd_uint8_t  nlpid;
810c74ad251Schristos     nd_uint8_t  length_indicator;
811c74ad251Schristos     nd_uint8_t  version;
812c74ad251Schristos     nd_uint8_t  lifetime; /* units of 500ms */
813c74ad251Schristos     nd_uint8_t  type;
814c74ad251Schristos     nd_uint16_t segment_length;
815c74ad251Schristos     nd_uint16_t cksum;
8160f74e101Schristos };
8170f74e101Schristos 
8180f74e101Schristos struct clnp_segment_header_t {
819c74ad251Schristos     nd_uint16_t data_unit_id;
820c74ad251Schristos     nd_uint16_t segment_offset;
821c74ad251Schristos     nd_uint16_t total_length;
8220f74e101Schristos };
8230f74e101Schristos 
8240f74e101Schristos /*
8250f74e101Schristos  * clnp_print
8260f74e101Schristos  * Decode CLNP packets.  Return 0 on error.
8270f74e101Schristos  */
8280f74e101Schristos 
829b3a00663Schristos static int
830b3a00663Schristos clnp_print(netdissect_options *ndo,
831b3a00663Schristos            const uint8_t *pptr, u_int length)
8320f74e101Schristos {
833b3a00663Schristos 	const uint8_t *optr,*source_address,*dest_address;
834c74ad251Schristos         u_int li,li_remaining,tlen,nsap_offset,source_address_length,dest_address_length, clnp_pdu_type, clnp_flags;
8350f74e101Schristos 	const struct clnp_header_t *clnp_header;
8360f74e101Schristos 	const struct clnp_segment_header_t *clnp_segment_header;
837c74ad251Schristos         uint8_t rfd_error,rfd_error_major,rfd_error_minor;
8380f74e101Schristos 
839c74ad251Schristos 	ndo->ndo_protocol = "clnp";
8400f74e101Schristos 	clnp_header = (const struct clnp_header_t *) pptr;
841c74ad251Schristos         ND_TCHECK_SIZE(clnp_header);
8420f74e101Schristos 
843c74ad251Schristos         li = GET_U_1(clnp_header->length_indicator);
844c74ad251Schristos         li_remaining = li;
8450f74e101Schristos         optr = pptr;
8460f74e101Schristos 
847b3a00663Schristos         if (!ndo->ndo_eflag)
848c74ad251Schristos             nd_print_protocol_caps(ndo);
8490f74e101Schristos 
8500f74e101Schristos         /*
8510f74e101Schristos          * Sanity checking of the header.
8520f74e101Schristos          */
8530f74e101Schristos 
854c74ad251Schristos         if (GET_U_1(clnp_header->version) != CLNP_VERSION) {
855c74ad251Schristos             ND_PRINT("version %u packet not supported",
856c74ad251Schristos                      GET_U_1(clnp_header->version));
8570f74e101Schristos             return (0);
8580f74e101Schristos         }
8590f74e101Schristos 
860dc860a36Sspz 	if (li > length) {
861c74ad251Schristos             ND_PRINT(" length indicator(%u) > PDU size (%u)!", li, length);
862dc860a36Sspz             return (0);
863dc860a36Sspz 	}
864dc860a36Sspz 
865dc860a36Sspz         if (li < sizeof(struct clnp_header_t)) {
866c74ad251Schristos             ND_PRINT(" length indicator %u < min PDU size:", li);
867c74ad251Schristos             while (pptr < ndo->ndo_snapend) {
868c74ad251Schristos                 ND_PRINT("%02X", GET_U_1(pptr));
869c74ad251Schristos                 pptr++;
870c74ad251Schristos             }
871dc860a36Sspz             return (0);
872dc860a36Sspz         }
873dc860a36Sspz 
8740f74e101Schristos         /* FIXME further header sanity checking */
8750f74e101Schristos 
876c74ad251Schristos         clnp_pdu_type = GET_U_1(clnp_header->type) & CLNP_PDU_TYPE_MASK;
877c74ad251Schristos         clnp_flags = GET_U_1(clnp_header->type) & CLNP_FLAG_MASK;
8780f74e101Schristos 
8790f74e101Schristos         pptr += sizeof(struct clnp_header_t);
880c74ad251Schristos         li_remaining -= sizeof(struct clnp_header_t);
881dc860a36Sspz 
882c74ad251Schristos         if (li_remaining < 1) {
883c74ad251Schristos             ND_PRINT("li < size of fixed part of CLNP header and addresses");
884dc860a36Sspz             return (0);
885dc860a36Sspz         }
886c74ad251Schristos         dest_address_length = GET_U_1(pptr);
887dc860a36Sspz         pptr += 1;
888c74ad251Schristos         li_remaining -= 1;
889c74ad251Schristos         if (li_remaining < dest_address_length) {
890c74ad251Schristos             ND_PRINT("li < size of fixed part of CLNP header and addresses");
891dc860a36Sspz             return (0);
892dc860a36Sspz         }
893c74ad251Schristos         ND_TCHECK_LEN(pptr, dest_address_length);
894dc860a36Sspz         dest_address = pptr;
895dc860a36Sspz         pptr += dest_address_length;
896c74ad251Schristos         li_remaining -= dest_address_length;
8970f74e101Schristos 
898c74ad251Schristos         if (li_remaining < 1) {
899c74ad251Schristos             ND_PRINT("li < size of fixed part of CLNP header and addresses");
900dc860a36Sspz             return (0);
901dc860a36Sspz         }
902c74ad251Schristos         source_address_length = GET_U_1(pptr);
903dc860a36Sspz         pptr += 1;
904c74ad251Schristos         li_remaining -= 1;
905c74ad251Schristos         if (li_remaining < source_address_length) {
906c74ad251Schristos             ND_PRINT("li < size of fixed part of CLNP header and addresses");
907dc860a36Sspz             return (0);
908dc860a36Sspz         }
909c74ad251Schristos         ND_TCHECK_LEN(pptr, source_address_length);
910dc860a36Sspz         source_address = pptr;
911dc860a36Sspz         pptr += source_address_length;
912c74ad251Schristos         li_remaining -= source_address_length;
9130f74e101Schristos 
914b3a00663Schristos         if (ndo->ndo_vflag < 1) {
915c74ad251Schristos             ND_PRINT("%s%s > %s, %s, length %u",
916b3a00663Schristos                    ndo->ndo_eflag ? "" : ", ",
917c74ad251Schristos                    GET_ISONSAP_STRING(source_address, source_address_length),
918c74ad251Schristos                    GET_ISONSAP_STRING(dest_address, dest_address_length),
9190f74e101Schristos                    tok2str(clnp_pdu_values,"unknown (%u)",clnp_pdu_type),
920c74ad251Schristos                    length);
9210f74e101Schristos             return (1);
9220f74e101Schristos         }
923c74ad251Schristos         ND_PRINT("%slength %u", ndo->ndo_eflag ? "" : ", ", length);
9240f74e101Schristos 
925c74ad251Schristos         ND_PRINT("\n\t%s PDU, hlen: %u, v: %u, lifetime: %u.%us, Segment PDU length: %u, checksum: 0x%04x",
9260f74e101Schristos                tok2str(clnp_pdu_values, "unknown (%u)",clnp_pdu_type),
927c74ad251Schristos                GET_U_1(clnp_header->length_indicator),
928c74ad251Schristos                GET_U_1(clnp_header->version),
929c74ad251Schristos                GET_U_1(clnp_header->lifetime)/2,
930c74ad251Schristos                (GET_U_1(clnp_header->lifetime)%2)*5,
931c74ad251Schristos                GET_BE_U_2(clnp_header->segment_length),
932c74ad251Schristos                GET_BE_U_2(clnp_header->cksum));
9330f74e101Schristos 
934c74ad251Schristos         osi_print_cksum(ndo, optr, GET_BE_U_2(clnp_header->cksum), 7,
935c74ad251Schristos                         GET_U_1(clnp_header->length_indicator));
9360f74e101Schristos 
937c74ad251Schristos         ND_PRINT("\n\tFlags [%s]",
938c74ad251Schristos                bittok2str(clnp_flag_values, "none", clnp_flags));
9390f74e101Schristos 
940c74ad251Schristos         ND_PRINT("\n\tsource address (length %u): %s\n\tdest   address (length %u): %s",
9410f74e101Schristos                source_address_length,
942c74ad251Schristos                GET_ISONSAP_STRING(source_address, source_address_length),
9430f74e101Schristos                dest_address_length,
944c74ad251Schristos                GET_ISONSAP_STRING(dest_address, dest_address_length));
9450f74e101Schristos 
9460f74e101Schristos         if (clnp_flags & CLNP_SEGMENT_PART) {
947c74ad251Schristos                 if (li_remaining < sizeof(struct clnp_segment_header_t)) {
948c74ad251Schristos                     ND_PRINT("li < size of fixed part of CLNP header, addresses, and segment part");
949dc860a36Sspz                     return (0);
950dc860a36Sspz                 }
9510f74e101Schristos 		clnp_segment_header = (const struct clnp_segment_header_t *) pptr;
952c74ad251Schristos                 ND_TCHECK_SIZE(clnp_segment_header);
953c74ad251Schristos                 ND_PRINT("\n\tData Unit ID: 0x%04x, Segment Offset: %u, Total PDU Length: %u",
954c74ad251Schristos                        GET_BE_U_2(clnp_segment_header->data_unit_id),
955c74ad251Schristos                        GET_BE_U_2(clnp_segment_header->segment_offset),
956c74ad251Schristos                        GET_BE_U_2(clnp_segment_header->total_length));
957c74ad251Schristos                 pptr+=sizeof(struct clnp_segment_header_t);
958c74ad251Schristos                 li_remaining-=sizeof(struct clnp_segment_header_t);
9590f74e101Schristos         }
9600f74e101Schristos 
9610f74e101Schristos         /* now walk the options */
962c74ad251Schristos         while (li_remaining != 0) {
9630f74e101Schristos             u_int op, opli;
964b3a00663Schristos             const uint8_t *tptr;
9650f74e101Schristos 
966c74ad251Schristos             if (li_remaining < 2) {
967c74ad251Schristos                 ND_PRINT(", bad opts/li");
9680f74e101Schristos                 return (0);
9690f74e101Schristos             }
970c74ad251Schristos             op = GET_U_1(pptr);
971c74ad251Schristos             opli = GET_U_1(pptr + 1);
972c74ad251Schristos             pptr += 2;
973c74ad251Schristos             li_remaining -= 2;
974c74ad251Schristos             if (opli > li_remaining) {
975c74ad251Schristos                 ND_PRINT(", opt (%u) too long", op);
9760f74e101Schristos                 return (0);
9770f74e101Schristos             }
978c74ad251Schristos             ND_TCHECK_LEN(pptr, opli);
979c74ad251Schristos             li_remaining -= opli;
9800f74e101Schristos             tptr = pptr;
9810f74e101Schristos             tlen = opli;
9820f74e101Schristos 
983c74ad251Schristos             ND_PRINT("\n\t  %s Option #%u, length %u, value: ",
9840f74e101Schristos                    tok2str(clnp_option_values,"Unknown",op),
9850f74e101Schristos                    op,
986c74ad251Schristos                    opli);
9870f74e101Schristos 
988dc860a36Sspz             /*
989dc860a36Sspz              * We've already checked that the entire option is present
990c74ad251Schristos              * in the captured packet with the ND_TCHECK_LEN() call.
991c74ad251Schristos              * Therefore, we don't need to do ND_TCHECK()/ND_TCHECK_LEN()
992dc860a36Sspz              * checks.
993dc860a36Sspz              * We do, however, need to check tlen, to make sure we
994dc860a36Sspz              * don't run past the end of the option.
995dc860a36Sspz 	     */
9960f74e101Schristos             switch (op) {
9970f74e101Schristos 
9980f74e101Schristos 
9990f74e101Schristos             case CLNP_OPTION_ROUTE_RECORDING: /* those two options share the format */
10000f74e101Schristos             case CLNP_OPTION_SOURCE_ROUTING:
1001dc860a36Sspz                     if (tlen < 2) {
1002c74ad251Schristos                             ND_PRINT(", bad opt len");
1003dc860a36Sspz                             return (0);
1004dc860a36Sspz                     }
1005c74ad251Schristos                     ND_PRINT("%s %s",
1006c74ad251Schristos                            tok2str(clnp_option_sr_rr_values,"Unknown",GET_U_1(tptr)),
1007c74ad251Schristos                            tok2str(clnp_option_sr_rr_string_values, "Unknown Option %u", op));
1008c74ad251Schristos                     nsap_offset=GET_U_1(tptr + 1);
10090f74e101Schristos                     if (nsap_offset == 0) {
1010c74ad251Schristos                             ND_PRINT(" Bad NSAP offset (0)");
10110f74e101Schristos                             break;
10120f74e101Schristos                     }
10130f74e101Schristos                     nsap_offset-=1; /* offset to nsap list */
10140f74e101Schristos                     if (nsap_offset > tlen) {
1015c74ad251Schristos                             ND_PRINT(" Bad NSAP offset (past end of option)");
10160f74e101Schristos                             break;
10170f74e101Schristos                     }
10180f74e101Schristos                     tptr+=nsap_offset;
10190f74e101Schristos                     tlen-=nsap_offset;
10200f74e101Schristos                     while (tlen > 0) {
1021c74ad251Schristos                             source_address_length=GET_U_1(tptr);
10220f74e101Schristos                             if (tlen < source_address_length+1) {
1023c74ad251Schristos                                     ND_PRINT("\n\t    NSAP address goes past end of option");
10240f74e101Schristos                                     break;
10250f74e101Schristos                             }
10260f74e101Schristos                             if (source_address_length > 0) {
10270f74e101Schristos                                     source_address=(tptr+1);
1028c74ad251Schristos                                     ND_PRINT("\n\t    NSAP address (length %u): %s",
10290f74e101Schristos                                            source_address_length,
1030c74ad251Schristos                                            GET_ISONSAP_STRING(source_address, source_address_length));
10310f74e101Schristos                             }
10320f74e101Schristos                             tlen-=source_address_length+1;
10330f74e101Schristos                     }
10340f74e101Schristos                     break;
10350f74e101Schristos 
10360f74e101Schristos             case CLNP_OPTION_PRIORITY:
1037dc860a36Sspz                     if (tlen < 1) {
1038c74ad251Schristos                             ND_PRINT(", bad opt len");
1039dc860a36Sspz                             return (0);
1040dc860a36Sspz                     }
1041c74ad251Schristos                     ND_PRINT("0x%1x", GET_U_1(tptr)&0x0f);
10420f74e101Schristos                     break;
10430f74e101Schristos 
10440f74e101Schristos             case CLNP_OPTION_QOS_MAINTENANCE:
1045dc860a36Sspz                     if (tlen < 1) {
1046c74ad251Schristos                             ND_PRINT(", bad opt len");
1047dc860a36Sspz                             return (0);
1048dc860a36Sspz                     }
1049c74ad251Schristos                     ND_PRINT("\n\t    Format Code: %s",
1050c74ad251Schristos                            tok2str(clnp_option_scope_values, "Reserved", GET_U_1(tptr) & CLNP_OPTION_SCOPE_MASK));
10510f74e101Schristos 
1052c74ad251Schristos                     if ((GET_U_1(tptr)&CLNP_OPTION_SCOPE_MASK) == CLNP_OPTION_SCOPE_GLOBAL)
1053c74ad251Schristos                             ND_PRINT("\n\t    QoS Flags [%s]",
10540f74e101Schristos                                    bittok2str(clnp_option_qos_global_values,
10550f74e101Schristos                                               "none",
1056c74ad251Schristos                                               GET_U_1(tptr)&CLNP_OPTION_OPTION_QOS_MASK));
10570f74e101Schristos                     break;
10580f74e101Schristos 
10590f74e101Schristos             case CLNP_OPTION_SECURITY:
1060dc860a36Sspz                     if (tlen < 2) {
1061c74ad251Schristos                             ND_PRINT(", bad opt len");
1062dc860a36Sspz                             return (0);
1063dc860a36Sspz                     }
1064c74ad251Schristos                     ND_PRINT("\n\t    Format Code: %s, Security-Level %u",
1065c74ad251Schristos                            tok2str(clnp_option_scope_values,"Reserved",GET_U_1(tptr)&CLNP_OPTION_SCOPE_MASK),
1066c74ad251Schristos                            GET_U_1(tptr + 1));
10670f74e101Schristos                     break;
10680f74e101Schristos 
10690f74e101Schristos             case CLNP_OPTION_DISCARD_REASON:
1070dc860a36Sspz                 if (tlen < 1) {
1071c74ad251Schristos                         ND_PRINT(", bad opt len");
1072dc860a36Sspz                         return (0);
1073dc860a36Sspz                 }
1074c74ad251Schristos                 rfd_error = GET_U_1(tptr);
1075c74ad251Schristos                 rfd_error_major = (rfd_error&0xf0) >> 4;
1076c74ad251Schristos                 rfd_error_minor = rfd_error&0x0f;
1077c74ad251Schristos                 ND_PRINT("\n\t    Class: %s Error (0x%01x), %s (0x%01x)",
10780f74e101Schristos                        tok2str(clnp_option_rfd_class_values,"Unknown",rfd_error_major),
10790f74e101Schristos                        rfd_error_major,
10800f74e101Schristos                        tok2str(clnp_option_rfd_error_class[rfd_error_major],"Unknown",rfd_error_minor),
1081c74ad251Schristos                        rfd_error_minor);
10820f74e101Schristos                 break;
10830f74e101Schristos 
10840f74e101Schristos             case CLNP_OPTION_PADDING:
1085c74ad251Schristos                     ND_PRINT("padding data");
10860f74e101Schristos                 break;
10870f74e101Schristos 
10880f74e101Schristos                 /*
10890f74e101Schristos                  * FIXME those are the defined Options that lack a decoder
10900f74e101Schristos                  * you are welcome to contribute code ;-)
10910f74e101Schristos                  */
10920f74e101Schristos 
10930f74e101Schristos             default:
1094b3a00663Schristos                 print_unknown_data(ndo, tptr, "\n\t  ", opli);
10950f74e101Schristos                 break;
10960f74e101Schristos             }
1097b3a00663Schristos             if (ndo->ndo_vflag > 1)
1098b3a00663Schristos                 print_unknown_data(ndo, pptr, "\n\t  ", opli);
10990f74e101Schristos             pptr += opli;
11000f74e101Schristos         }
11010f74e101Schristos 
11020f74e101Schristos         switch (clnp_pdu_type) {
11030f74e101Schristos 
11040f74e101Schristos         case    CLNP_PDU_ER: /* fall through */
11050f74e101Schristos         case	CLNP_PDU_ERP:
1106c74ad251Schristos             if (GET_U_1(pptr) == NLPID_CLNP) {
1107c74ad251Schristos                 ND_PRINT("\n\t-----original packet-----\n\t");
11080f74e101Schristos                 /* FIXME recursion protection */
1109c74ad251Schristos                 clnp_print(ndo, pptr, length - li);
11100f74e101Schristos                 break;
11110f74e101Schristos             }
11120f74e101Schristos 
1113c74ad251Schristos         /* The cases above break from the switch block if they see and print
1114c74ad251Schristos          * a CLNP header in the Data part. For an Error Report PDU this is
1115c74ad251Schristos          * described in Section 7.9.6 of ITU X.233 (1997 E), also known as
1116c74ad251Schristos          * ISO/IEC 8473-1:1998(E). It is not clear why in this code the same
1117c74ad251Schristos          * applies to an Echo Response PDU, as the standard does not specify
1118c74ad251Schristos          * the contents -- could be a proprietary extension or a bug. In either
1119c74ad251Schristos          * case, if the Data part does not contain a CLNP header, its structure
1120c74ad251Schristos          * is considered unknown and the decoding falls through to print the
1121c74ad251Schristos          * contents as-is.
1122c74ad251Schristos          */
1123c74ad251Schristos         ND_FALL_THROUGH;
1124c74ad251Schristos 
11250f74e101Schristos         case	CLNP_PDU_DT:
11260f74e101Schristos         case	CLNP_PDU_MD:
11270f74e101Schristos         case	CLNP_PDU_ERQ:
11280f74e101Schristos 
11290f74e101Schristos         default:
11300f74e101Schristos             /* dump the PDU specific data */
1131*26ba0b50Schristos             if (length > ND_BYTES_BETWEEN(optr, pptr)) {
1132c74ad251Schristos                 ND_PRINT("\n\t  undecoded non-header data, length %u", length-li);
1133*26ba0b50Schristos                 print_unknown_data(ndo, pptr, "\n\t  ",
1134*26ba0b50Schristos                                    length - ND_BYTES_BETWEEN(optr, pptr));
11350f74e101Schristos             }
11360f74e101Schristos         }
11370f74e101Schristos 
11380f74e101Schristos         return (1);
11390f74e101Schristos 
11400f74e101Schristos  trunc:
1141c74ad251Schristos     nd_print_trunc(ndo);
11420f74e101Schristos     return (1);
11430f74e101Schristos 
11440f74e101Schristos }
11450f74e101Schristos 
11460f74e101Schristos 
11470f74e101Schristos #define	ESIS_PDU_REDIRECT	6
11480f74e101Schristos #define	ESIS_PDU_ESH	        2
11490f74e101Schristos #define	ESIS_PDU_ISH	        4
11500f74e101Schristos 
1151870189d2Schristos static const struct tok esis_pdu_values[] = {
11520f74e101Schristos     { ESIS_PDU_REDIRECT, "redirect"},
11530f74e101Schristos     { ESIS_PDU_ESH,      "ESH"},
11540f74e101Schristos     { ESIS_PDU_ISH,      "ISH"},
11550f74e101Schristos     { 0, NULL }
11560f74e101Schristos };
11570f74e101Schristos 
11580f74e101Schristos struct esis_header_t {
1159c74ad251Schristos 	nd_uint8_t  nlpid;
1160c74ad251Schristos 	nd_uint8_t  length_indicator;
1161c74ad251Schristos 	nd_uint8_t  version;
1162c74ad251Schristos 	nd_byte     reserved;
1163c74ad251Schristos 	nd_uint8_t  type;
1164c74ad251Schristos 	nd_uint16_t holdtime;
1165c74ad251Schristos 	nd_uint16_t cksum;
11660f74e101Schristos };
11670f74e101Schristos 
11680f74e101Schristos static void
1169b3a00663Schristos esis_print(netdissect_options *ndo,
1170b3a00663Schristos            const uint8_t *pptr, u_int length)
11710f74e101Schristos {
1172b3a00663Schristos 	const uint8_t *optr;
1173c74ad251Schristos 	u_int li, version, esis_pdu_type, source_address_length, source_address_number;
11740f74e101Schristos 	const struct esis_header_t *esis_header;
11750f74e101Schristos 
1176c74ad251Schristos 	ndo->ndo_protocol = "esis";
1177b3a00663Schristos 	if (!ndo->ndo_eflag)
1178c74ad251Schristos 		ND_PRINT("ES-IS");
11790f74e101Schristos 
11800f74e101Schristos 	if (length <= 2) {
1181c74ad251Schristos 		ND_PRINT(ndo->ndo_qflag ? "bad pkt!" : "no header at all!");
11820f74e101Schristos 		return;
11830f74e101Schristos 	}
11840f74e101Schristos 
11850f74e101Schristos 	esis_header = (const struct esis_header_t *) pptr;
1186c74ad251Schristos         ND_TCHECK_SIZE(esis_header);
1187c74ad251Schristos         li = GET_U_1(esis_header->length_indicator);
11880f74e101Schristos         optr = pptr;
11890f74e101Schristos 
11900f74e101Schristos         /*
11910f74e101Schristos          * Sanity checking of the header.
11920f74e101Schristos          */
11930f74e101Schristos 
1194c74ad251Schristos         if (GET_U_1(esis_header->nlpid) != NLPID_ESIS) {
1195c74ad251Schristos             ND_PRINT(" nlpid 0x%02x packet not supported",
1196c74ad251Schristos 		     GET_U_1(esis_header->nlpid));
11970f74e101Schristos             return;
11980f74e101Schristos         }
11990f74e101Schristos 
1200c74ad251Schristos         version = GET_U_1(esis_header->version);
1201c74ad251Schristos         if (version != ESIS_VERSION) {
1202c74ad251Schristos             ND_PRINT(" version %u packet not supported", version);
12030f74e101Schristos             return;
12040f74e101Schristos         }
12050f74e101Schristos 
12060f74e101Schristos 	if (li > length) {
1207c74ad251Schristos             ND_PRINT(" length indicator(%u) > PDU size (%u)!", li, length);
12080f74e101Schristos             return;
12090f74e101Schristos 	}
12100f74e101Schristos 
12110f74e101Schristos 	if (li < sizeof(struct esis_header_t) + 2) {
1212c74ad251Schristos             ND_PRINT(" length indicator %u < min PDU size:", li);
1213c74ad251Schristos             while (pptr < ndo->ndo_snapend) {
1214c74ad251Schristos                 ND_PRINT("%02X", GET_U_1(pptr));
1215c74ad251Schristos                 pptr++;
1216c74ad251Schristos             }
12170f74e101Schristos             return;
12180f74e101Schristos 	}
12190f74e101Schristos 
1220c74ad251Schristos         esis_pdu_type = GET_U_1(esis_header->type) & ESIS_PDU_TYPE_MASK;
12210f74e101Schristos 
1222b3a00663Schristos         if (ndo->ndo_vflag < 1) {
1223c74ad251Schristos             ND_PRINT("%s%s, length %u",
1224b3a00663Schristos                    ndo->ndo_eflag ? "" : ", ",
12250f74e101Schristos                    tok2str(esis_pdu_values,"unknown type (%u)",esis_pdu_type),
1226c74ad251Schristos                    length);
12270f74e101Schristos             return;
12280f74e101Schristos         } else
1229c74ad251Schristos             ND_PRINT("%slength %u\n\t%s (%u)",
1230b3a00663Schristos                    ndo->ndo_eflag ? "" : ", ",
12310f74e101Schristos                    length,
12320f74e101Schristos                    tok2str(esis_pdu_values,"unknown type: %u", esis_pdu_type),
1233c74ad251Schristos                    esis_pdu_type);
12340f74e101Schristos 
1235c74ad251Schristos         ND_PRINT(", v: %u%s", version, version == ESIS_VERSION ? "" : "unsupported" );
1236c74ad251Schristos         ND_PRINT(", checksum: 0x%04x", GET_BE_U_2(esis_header->cksum));
12370f74e101Schristos 
1238c74ad251Schristos         osi_print_cksum(ndo, pptr, GET_BE_U_2(esis_header->cksum), 7,
1239c74ad251Schristos                         li);
12400f74e101Schristos 
1241c74ad251Schristos         ND_PRINT(", holding time: %us, length indicator: %u",
1242c74ad251Schristos                   GET_BE_U_2(esis_header->holdtime), li);
12430f74e101Schristos 
1244b3a00663Schristos         if (ndo->ndo_vflag > 1)
1245b3a00663Schristos             print_unknown_data(ndo, optr, "\n\t", sizeof(struct esis_header_t));
12460f74e101Schristos 
12470f74e101Schristos 	pptr += sizeof(struct esis_header_t);
12480f74e101Schristos 	li -= sizeof(struct esis_header_t);
12490f74e101Schristos 
12500f74e101Schristos 	switch (esis_pdu_type) {
12510f74e101Schristos 	case ESIS_PDU_REDIRECT: {
1252b3a00663Schristos 		const uint8_t *dst, *snpa, *neta;
12530f74e101Schristos 		u_int dstl, snpal, netal;
12540f74e101Schristos 
1255c74ad251Schristos 		ND_TCHECK_1(pptr);
12560f74e101Schristos 		if (li < 1) {
1257c74ad251Schristos 			ND_PRINT(", bad redirect/li");
12580f74e101Schristos 			return;
12590f74e101Schristos 		}
1260c74ad251Schristos 		dstl = GET_U_1(pptr);
12610f74e101Schristos 		pptr++;
12620f74e101Schristos 		li--;
1263c74ad251Schristos 		ND_TCHECK_LEN(pptr, dstl);
12640f74e101Schristos 		if (li < dstl) {
1265c74ad251Schristos 			ND_PRINT(", bad redirect/li");
12660f74e101Schristos 			return;
12670f74e101Schristos 		}
12680f74e101Schristos 		dst = pptr;
12690f74e101Schristos 		pptr += dstl;
12700f74e101Schristos                 li -= dstl;
1271c74ad251Schristos 		ND_PRINT("\n\t  %s", GET_ISONSAP_STRING(dst, dstl));
12720f74e101Schristos 
1273c74ad251Schristos 		ND_TCHECK_1(pptr);
12740f74e101Schristos 		if (li < 1) {
1275c74ad251Schristos 			ND_PRINT(", bad redirect/li");
12760f74e101Schristos 			return;
12770f74e101Schristos 		}
1278c74ad251Schristos 		snpal = GET_U_1(pptr);
12790f74e101Schristos 		pptr++;
12800f74e101Schristos 		li--;
1281c74ad251Schristos 		ND_TCHECK_LEN(pptr, snpal);
12820f74e101Schristos 		if (li < snpal) {
1283c74ad251Schristos 			ND_PRINT(", bad redirect/li");
12840f74e101Schristos 			return;
12850f74e101Schristos 		}
12860f74e101Schristos 		snpa = pptr;
12870f74e101Schristos 		pptr += snpal;
12880f74e101Schristos                 li -= snpal;
1289c74ad251Schristos 		ND_TCHECK_1(pptr);
12900f74e101Schristos 		if (li < 1) {
1291c74ad251Schristos 			ND_PRINT(", bad redirect/li");
12920f74e101Schristos 			return;
12930f74e101Schristos 		}
1294c74ad251Schristos 		netal = GET_U_1(pptr);
12950f74e101Schristos 		pptr++;
1296c74ad251Schristos 		ND_TCHECK_LEN(pptr, netal);
12970f74e101Schristos 		if (li < netal) {
1298c74ad251Schristos 			ND_PRINT(", bad redirect/li");
12990f74e101Schristos 			return;
13000f74e101Schristos 		}
13010f74e101Schristos 		neta = pptr;
13020f74e101Schristos 		pptr += netal;
13030f74e101Schristos                 li -= netal;
13040f74e101Schristos 
1305c74ad251Schristos 		if (snpal == MAC_ADDR_LEN)
1306c74ad251Schristos 			ND_PRINT("\n\t  SNPA (length: %u): %s",
130772c96ff3Schristos 			       snpal,
1308c74ad251Schristos 			       GET_ETHERADDR_STRING(snpa));
13090f74e101Schristos 		else
1310c74ad251Schristos 			ND_PRINT("\n\t  SNPA (length: %u): %s",
131172c96ff3Schristos 			       snpal,
1312c74ad251Schristos 			       GET_LINKADDR_STRING(snpa, LINKADDR_OTHER, snpal));
131372c96ff3Schristos 		if (netal != 0)
1314c74ad251Schristos 			ND_PRINT("\n\t  NET (length: %u) %s",
131572c96ff3Schristos 			       netal,
1316c74ad251Schristos 			       GET_ISONSAP_STRING(neta, netal));
13170f74e101Schristos 		break;
13180f74e101Schristos 	}
13190f74e101Schristos 
13200f74e101Schristos 	case ESIS_PDU_ESH:
1321c74ad251Schristos             ND_TCHECK_1(pptr);
13220f74e101Schristos             if (li < 1) {
1323c74ad251Schristos                 ND_PRINT(", bad esh/li");
13240f74e101Schristos                 return;
13250f74e101Schristos             }
1326c74ad251Schristos             source_address_number = GET_U_1(pptr);
13270f74e101Schristos             pptr++;
13280f74e101Schristos             li--;
13290f74e101Schristos 
1330c74ad251Schristos             ND_PRINT("\n\t  Number of Source Addresses: %u", source_address_number);
13310f74e101Schristos 
13320f74e101Schristos             while (source_address_number > 0) {
1333c74ad251Schristos                 ND_TCHECK_1(pptr);
13340f74e101Schristos 		if (li < 1) {
1335c74ad251Schristos                     ND_PRINT(", bad esh/li");
13360f74e101Schristos 		    return;
13370f74e101Schristos 		}
1338c74ad251Schristos                 source_address_length = GET_U_1(pptr);
13390f74e101Schristos                 pptr++;
13400f74e101Schristos 		li--;
13410f74e101Schristos 
1342c74ad251Schristos                 ND_TCHECK_LEN(pptr, source_address_length);
13430f74e101Schristos 		if (li < source_address_length) {
1344c74ad251Schristos                     ND_PRINT(", bad esh/li");
13450f74e101Schristos 		    return;
13460f74e101Schristos 		}
1347c74ad251Schristos                 ND_PRINT("\n\t  NET (length: %u): %s",
13480f74e101Schristos                        source_address_length,
1349c74ad251Schristos                        GET_ISONSAP_STRING(pptr, source_address_length));
13500f74e101Schristos                 pptr += source_address_length;
13510f74e101Schristos                 li -= source_address_length;
13520f74e101Schristos                 source_address_number--;
13530f74e101Schristos             }
13540f74e101Schristos 
13550f74e101Schristos             break;
13560f74e101Schristos 
13570f74e101Schristos 	case ESIS_PDU_ISH: {
1358c74ad251Schristos             ND_TCHECK_1(pptr);
13590f74e101Schristos             if (li < 1) {
1360c74ad251Schristos                 ND_PRINT(", bad ish/li");
13610f74e101Schristos                 return;
13620f74e101Schristos             }
1363c74ad251Schristos             source_address_length = GET_U_1(pptr);
13640f74e101Schristos             pptr++;
13650f74e101Schristos             li--;
1366c74ad251Schristos             ND_TCHECK_LEN(pptr, source_address_length);
13670f74e101Schristos             if (li < source_address_length) {
1368c74ad251Schristos                 ND_PRINT(", bad ish/li");
13690f74e101Schristos                 return;
13700f74e101Schristos             }
1371c74ad251Schristos             ND_PRINT("\n\t  NET (length: %u): %s", source_address_length, GET_ISONSAP_STRING(pptr, source_address_length));
13720f74e101Schristos             pptr += source_address_length;
13730f74e101Schristos             li -= source_address_length;
13740f74e101Schristos             break;
13750f74e101Schristos 	}
13760f74e101Schristos 
13770f74e101Schristos 	default:
1378b3a00663Schristos 		if (ndo->ndo_vflag <= 1) {
1379c74ad251Schristos 			/*
1380c74ad251Schristos 			 * If there's at least one byte to print, print
1381c74ad251Schristos 			 * it/them.
1382c74ad251Schristos 			 */
1383c74ad251Schristos 			if (ND_TTEST_LEN(pptr, 1))
1384c74ad251Schristos 				print_unknown_data(ndo, pptr, "\n\t  ", ND_BYTES_AVAILABLE_AFTER(pptr));
13850f74e101Schristos 		}
13860f74e101Schristos 		return;
13870f74e101Schristos 	}
13880f74e101Schristos 
13890f74e101Schristos         /* now walk the options */
13900e9868baSchristos         while (li != 0) {
13910f74e101Schristos             u_int op, opli;
1392b3a00663Schristos             const uint8_t *tptr;
13930f74e101Schristos 
13940f74e101Schristos             if (li < 2) {
1395c74ad251Schristos                 ND_PRINT(", bad opts/li");
13960f74e101Schristos                 return;
13970f74e101Schristos             }
1398c74ad251Schristos             op = GET_U_1(pptr);
1399c74ad251Schristos             opli = GET_U_1(pptr + 1);
1400c74ad251Schristos             pptr += 2;
14010f74e101Schristos             li -= 2;
14020f74e101Schristos             if (opli > li) {
1403c74ad251Schristos                 ND_PRINT(", opt (%u) too long", op);
14040f74e101Schristos                 return;
14050f74e101Schristos             }
14060f74e101Schristos             li -= opli;
14070f74e101Schristos             tptr = pptr;
14080f74e101Schristos 
1409c74ad251Schristos             ND_PRINT("\n\t  %s Option #%u, length %u, value: ",
14100f74e101Schristos                    tok2str(esis_option_values,"Unknown",op),
14110f74e101Schristos                    op,
1412c74ad251Schristos                    opli);
14130f74e101Schristos 
14140f74e101Schristos             switch (op) {
14150f74e101Schristos 
14160f74e101Schristos             case ESIS_OPTION_ES_CONF_TIME:
14170e9868baSchristos                 if (opli == 2) {
1418c74ad251Schristos                     ND_TCHECK_2(pptr);
1419c74ad251Schristos                     ND_PRINT("%us", GET_BE_U_2(tptr));
14200e9868baSchristos                 } else
1421c74ad251Schristos                     ND_PRINT("(bad length)");
14220f74e101Schristos                 break;
14230f74e101Schristos 
14240f74e101Schristos             case ESIS_OPTION_PROTOCOLS:
14250f74e101Schristos                 while (opli>0) {
1426c74ad251Schristos                     ND_PRINT("%s (0x%02x)",
14270f74e101Schristos                            tok2str(nlpid_values,
14280f74e101Schristos                                    "unknown",
1429c74ad251Schristos                                    GET_U_1(tptr)),
1430c74ad251Schristos                            GET_U_1(tptr));
14310f74e101Schristos                     if (opli>1) /* further NPLIDs ? - put comma */
1432c74ad251Schristos                         ND_PRINT(", ");
14330f74e101Schristos                     tptr++;
14340f74e101Schristos                     opli--;
14350f74e101Schristos                 }
14360f74e101Schristos                 break;
14370f74e101Schristos 
14380f74e101Schristos                 /*
14390f74e101Schristos                  * FIXME those are the defined Options that lack a decoder
14400f74e101Schristos                  * you are welcome to contribute code ;-)
14410f74e101Schristos                  */
14420f74e101Schristos 
14430f74e101Schristos             case ESIS_OPTION_QOS_MAINTENANCE:
14440f74e101Schristos             case ESIS_OPTION_SECURITY:
14450f74e101Schristos             case ESIS_OPTION_PRIORITY:
14460f74e101Schristos             case ESIS_OPTION_ADDRESS_MASK:
14470f74e101Schristos             case ESIS_OPTION_SNPA_MASK:
14480f74e101Schristos 
14490f74e101Schristos             default:
1450b3a00663Schristos                 print_unknown_data(ndo, tptr, "\n\t  ", opli);
14510f74e101Schristos                 break;
14520f74e101Schristos             }
1453b3a00663Schristos             if (ndo->ndo_vflag > 1)
1454b3a00663Schristos                 print_unknown_data(ndo, pptr, "\n\t  ", opli);
14550f74e101Schristos             pptr += opli;
14560f74e101Schristos         }
1457c74ad251Schristos         return;
1458c74ad251Schristos 
14590f74e101Schristos trunc:
1460c74ad251Schristos 	nd_print_trunc(ndo);
14610f74e101Schristos }
14620f74e101Schristos 
1463870189d2Schristos static void
1464b3a00663Schristos isis_print_mcid(netdissect_options *ndo,
1465b3a00663Schristos                 const struct isis_spb_mcid *mcid)
1466870189d2Schristos {
1467870189d2Schristos   int i;
1468870189d2Schristos 
1469c74ad251Schristos   ND_TCHECK_SIZE(mcid);
1470c74ad251Schristos   ND_PRINT("ID: %u, Name: ", GET_U_1(mcid->format_id));
1471870189d2Schristos 
1472c74ad251Schristos   nd_printjnp(ndo, mcid->name, sizeof(mcid->name));
1473870189d2Schristos 
1474c74ad251Schristos   ND_PRINT("\n\t              Lvl: %u", GET_BE_U_2(mcid->revision_lvl));
1475870189d2Schristos 
1476c74ad251Schristos   ND_PRINT(", Digest: ");
1477870189d2Schristos 
1478870189d2Schristos   for(i=0;i<16;i++)
1479c74ad251Schristos     ND_PRINT("%.2x ", mcid->digest[i]);
1480c74ad251Schristos   return;
1481fdccd7e4Schristos 
1482fdccd7e4Schristos trunc:
1483c74ad251Schristos   nd_print_trunc(ndo);
1484870189d2Schristos }
1485870189d2Schristos 
1486870189d2Schristos static int
1487b3a00663Schristos isis_print_mt_port_cap_subtlv(netdissect_options *ndo,
1488c74ad251Schristos                               const uint8_t *tptr, u_int len)
1489870189d2Schristos {
1490c74ad251Schristos   u_int stlv_type, stlv_len;
1491870189d2Schristos   const struct isis_subtlv_spb_mcid *subtlv_spb_mcid;
1492870189d2Schristos   int i;
1493870189d2Schristos 
1494*26ba0b50Schristos   while (len > 2) {
1495c74ad251Schristos     stlv_type = GET_U_1(tptr);
1496c74ad251Schristos     stlv_len  = GET_U_1(tptr + 1);
1497870189d2Schristos 
1498870189d2Schristos     /* first lets see if we know the subTLVs name*/
1499c74ad251Schristos     ND_PRINT("\n\t       %s subTLV #%u, length: %u",
1500870189d2Schristos                tok2str(isis_mt_port_cap_subtlv_values, "unknown", stlv_type),
1501870189d2Schristos                stlv_type,
1502c74ad251Schristos                stlv_len);
1503870189d2Schristos 
1504c74ad251Schristos     tptr += 2;
1505870189d2Schristos     /*len -= TLV_TYPE_LEN_OFFSET;*/
1506c74ad251Schristos     len -= 2;
1507870189d2Schristos 
150872c96ff3Schristos     /* Make sure the subTLV fits within the space left */
150972c96ff3Schristos     if (len < stlv_len)
1510c74ad251Schristos       goto subtlv_too_long;
151172c96ff3Schristos     /* Make sure the entire subTLV is in the captured data */
1512c74ad251Schristos     ND_TCHECK_LEN(tptr, stlv_len);
151372c96ff3Schristos 
1514*26ba0b50Schristos     switch (stlv_type) {
1515870189d2Schristos       case ISIS_SUBTLV_SPB_MCID:
1516870189d2Schristos       {
151772c96ff3Schristos 	if (stlv_len < ISIS_SUBTLV_SPB_MCID_MIN_LEN)
1518c74ad251Schristos           goto subtlv_too_short;
1519870189d2Schristos 
1520fdccd7e4Schristos         subtlv_spb_mcid = (const struct isis_subtlv_spb_mcid *)tptr;
1521870189d2Schristos 
1522c74ad251Schristos         ND_PRINT("\n\t         MCID: ");
1523b3a00663Schristos         isis_print_mcid(ndo, &(subtlv_spb_mcid->mcid));
1524870189d2Schristos 
1525870189d2Schristos           /*tptr += SPB_MCID_MIN_LEN;
1526870189d2Schristos             len -= SPB_MCID_MIN_LEN; */
1527870189d2Schristos 
1528c74ad251Schristos         ND_PRINT("\n\t         AUX-MCID: ");
1529b3a00663Schristos         isis_print_mcid(ndo, &(subtlv_spb_mcid->aux_mcid));
1530870189d2Schristos 
1531870189d2Schristos           /*tptr += SPB_MCID_MIN_LEN;
1532870189d2Schristos             len -= SPB_MCID_MIN_LEN; */
1533c74ad251Schristos         tptr += ISIS_SUBTLV_SPB_MCID_MIN_LEN;
1534c74ad251Schristos         len -= ISIS_SUBTLV_SPB_MCID_MIN_LEN;
1535c74ad251Schristos         stlv_len -= ISIS_SUBTLV_SPB_MCID_MIN_LEN;
1536870189d2Schristos 
1537870189d2Schristos         break;
1538870189d2Schristos       }
1539870189d2Schristos 
1540870189d2Schristos       case ISIS_SUBTLV_SPB_DIGEST:
1541870189d2Schristos       {
154272c96ff3Schristos         if (stlv_len < ISIS_SUBTLV_SPB_DIGEST_MIN_LEN)
1543c74ad251Schristos           goto subtlv_too_short;
1544870189d2Schristos 
1545c74ad251Schristos         ND_PRINT("\n\t        RES: %u V: %u A: %u D: %u",
1546c74ad251Schristos                         (GET_U_1(tptr) >> 5),
1547c74ad251Schristos                         ((GET_U_1(tptr) >> 4) & 0x01),
1548c74ad251Schristos                         ((GET_U_1(tptr) >> 2) & 0x03),
1549c74ad251Schristos                         (GET_U_1(tptr) & 0x03));
1550870189d2Schristos 
1551870189d2Schristos         tptr++;
1552870189d2Schristos 
1553c74ad251Schristos         ND_PRINT("\n\t         Digest: ");
1554870189d2Schristos 
1555*26ba0b50Schristos         for(i=1;i<=8; i++) {
1556c74ad251Schristos             ND_PRINT("%08x ", GET_BE_U_4(tptr));
1557870189d2Schristos             if (i%4 == 0 && i != 8)
1558c74ad251Schristos               ND_PRINT("\n\t                 ");
1559c74ad251Schristos             tptr += 4;
1560870189d2Schristos         }
1561870189d2Schristos 
1562c74ad251Schristos         len -= ISIS_SUBTLV_SPB_DIGEST_MIN_LEN;
1563c74ad251Schristos         stlv_len -= ISIS_SUBTLV_SPB_DIGEST_MIN_LEN;
1564870189d2Schristos 
1565870189d2Schristos         break;
1566870189d2Schristos       }
1567870189d2Schristos 
1568870189d2Schristos       case ISIS_SUBTLV_SPB_BVID:
1569870189d2Schristos       {
1570*26ba0b50Schristos         while (stlv_len != 0) {
1571c74ad251Schristos           if (stlv_len < 4)
1572c74ad251Schristos             goto subtlv_too_short;
1573c74ad251Schristos           ND_PRINT("\n\t           ECT: %08x",
1574c74ad251Schristos                       GET_BE_U_4(tptr));
1575870189d2Schristos 
1576c74ad251Schristos           tptr += 4;
1577c74ad251Schristos           len -= 4;
1578c74ad251Schristos           stlv_len -= 4;
1579870189d2Schristos 
1580c74ad251Schristos           if (stlv_len < 2)
1581c74ad251Schristos             goto subtlv_too_short;
1582c74ad251Schristos           ND_PRINT(" BVID: %u, U:%01x M:%01x ",
1583c74ad251Schristos                      (GET_BE_U_2(tptr) >> 4) ,
1584c74ad251Schristos                      (GET_BE_U_2(tptr) >> 3) & 0x01,
1585c74ad251Schristos                      (GET_BE_U_2(tptr) >> 2) & 0x01);
1586870189d2Schristos 
1587c74ad251Schristos           tptr += 2;
1588c74ad251Schristos           len -= 2;
1589c74ad251Schristos           stlv_len -= 2;
1590870189d2Schristos         }
1591870189d2Schristos 
1592870189d2Schristos         break;
1593870189d2Schristos       }
1594870189d2Schristos 
1595870189d2Schristos       default:
1596870189d2Schristos         break;
1597870189d2Schristos     }
159872c96ff3Schristos     tptr += stlv_len;
159972c96ff3Schristos     len -= stlv_len;
1600870189d2Schristos   }
1601c74ad251Schristos   return (0);
1602870189d2Schristos 
1603dc860a36Sspz trunc:
1604c74ad251Schristos   nd_print_trunc(ndo);
1605c74ad251Schristos   return (1);
1606c74ad251Schristos 
1607c74ad251Schristos subtlv_too_long:
1608c74ad251Schristos   ND_PRINT(" (> containing TLV length)");
1609c74ad251Schristos   return (1);
1610c74ad251Schristos 
1611c74ad251Schristos subtlv_too_short:
1612c74ad251Schristos   ND_PRINT(" (too short)");
1613870189d2Schristos   return (1);
1614870189d2Schristos }
1615870189d2Schristos 
1616870189d2Schristos static int
1617b3a00663Schristos isis_print_mt_capability_subtlv(netdissect_options *ndo,
1618c74ad251Schristos                                 const uint8_t *tptr, u_int len)
1619870189d2Schristos {
1620c74ad251Schristos   u_int stlv_type, stlv_len, treecount;
1621870189d2Schristos 
1622*26ba0b50Schristos   while (len > 2) {
1623c74ad251Schristos     stlv_type = GET_U_1(tptr);
1624c74ad251Schristos     stlv_len  = GET_U_1(tptr + 1);
1625c74ad251Schristos     tptr += 2;
1626c74ad251Schristos     len -= 2;
1627870189d2Schristos 
1628870189d2Schristos     /* first lets see if we know the subTLVs name*/
1629c74ad251Schristos     ND_PRINT("\n\t      %s subTLV #%u, length: %u",
1630870189d2Schristos                tok2str(isis_mt_capability_subtlv_values, "unknown", stlv_type),
1631870189d2Schristos                stlv_type,
1632c74ad251Schristos                stlv_len);
1633870189d2Schristos 
163472c96ff3Schristos     /* Make sure the subTLV fits within the space left */
163572c96ff3Schristos     if (len < stlv_len)
1636c74ad251Schristos       goto subtlv_too_long;
163772c96ff3Schristos     /* Make sure the entire subTLV is in the captured data */
1638c74ad251Schristos     ND_TCHECK_LEN(tptr, stlv_len);
163972c96ff3Schristos 
1640*26ba0b50Schristos     switch (stlv_type) {
1641870189d2Schristos       case ISIS_SUBTLV_SPB_INSTANCE:
164272c96ff3Schristos           if (stlv_len < ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN)
1643c74ad251Schristos             goto subtlv_too_short;
1644870189d2Schristos 
1645c74ad251Schristos           ND_PRINT("\n\t        CIST Root-ID: %08x", GET_BE_U_4(tptr));
1646c74ad251Schristos           tptr += 4;
1647c74ad251Schristos           ND_PRINT(" %08x", GET_BE_U_4(tptr));
1648c74ad251Schristos           tptr += 4;
1649c74ad251Schristos           ND_PRINT(", Path Cost: %08x", GET_BE_U_4(tptr));
1650c74ad251Schristos           tptr += 4;
1651c74ad251Schristos           ND_PRINT(", Prio: %u", GET_BE_U_2(tptr));
1652c74ad251Schristos           tptr += 2;
1653c74ad251Schristos           ND_PRINT("\n\t        RES: %u",
1654c74ad251Schristos                     GET_BE_U_2(tptr) >> 5);
1655c74ad251Schristos           ND_PRINT(", V: %u",
1656c74ad251Schristos                     (GET_BE_U_2(tptr) >> 4) & 0x0001);
1657c74ad251Schristos           ND_PRINT(", SPSource-ID: %u",
1658c74ad251Schristos                     (GET_BE_U_4(tptr) & 0x000fffff));
1659c74ad251Schristos           tptr += 4;
1660c74ad251Schristos           ND_PRINT(", No of Trees: %x", GET_U_1(tptr));
1661870189d2Schristos 
1662c74ad251Schristos           treecount = GET_U_1(tptr);
1663c74ad251Schristos           tptr++;
1664870189d2Schristos 
1665c74ad251Schristos           len -= ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN;
1666c74ad251Schristos           stlv_len -= ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN;
1667870189d2Schristos 
1668*26ba0b50Schristos           while (treecount) {
166972c96ff3Schristos             if (stlv_len < ISIS_SUBTLV_SPB_INSTANCE_VLAN_TUPLE_LEN)
167072c96ff3Schristos               goto trunc;
1671870189d2Schristos 
1672c74ad251Schristos             ND_PRINT("\n\t         U:%u, M:%u, A:%u, RES:%u",
1673c74ad251Schristos                       GET_U_1(tptr) >> 7,
1674c74ad251Schristos                       (GET_U_1(tptr) >> 6) & 0x01,
1675c74ad251Schristos                       (GET_U_1(tptr) >> 5) & 0x01,
1676c74ad251Schristos                       (GET_U_1(tptr) & 0x1f));
1677870189d2Schristos 
1678870189d2Schristos             tptr++;
1679870189d2Schristos 
1680c74ad251Schristos             ND_PRINT(", ECT: %08x", GET_BE_U_4(tptr));
1681870189d2Schristos 
1682c74ad251Schristos             tptr += 4;
1683870189d2Schristos 
1684c74ad251Schristos             ND_PRINT(", BVID: %u, SPVID: %u",
1685c74ad251Schristos                       (GET_BE_U_3(tptr) >> 12) & 0x000fff,
1686c74ad251Schristos                       GET_BE_U_3(tptr) & 0x000fff);
1687870189d2Schristos 
1688c74ad251Schristos             tptr += 3;
1689c74ad251Schristos             len -= ISIS_SUBTLV_SPB_INSTANCE_VLAN_TUPLE_LEN;
1690c74ad251Schristos             stlv_len -= ISIS_SUBTLV_SPB_INSTANCE_VLAN_TUPLE_LEN;
1691c74ad251Schristos             treecount--;
1692870189d2Schristos           }
1693870189d2Schristos 
1694870189d2Schristos           break;
1695870189d2Schristos 
1696870189d2Schristos       case ISIS_SUBTLV_SPBM_SI:
169772c96ff3Schristos           if (stlv_len < 8)
169872c96ff3Schristos             goto trunc;
1699870189d2Schristos 
1700c74ad251Schristos           ND_PRINT("\n\t        BMAC: %08x", GET_BE_U_4(tptr));
1701c74ad251Schristos           tptr += 4;
1702c74ad251Schristos           ND_PRINT("%04x", GET_BE_U_2(tptr));
1703c74ad251Schristos           tptr += 2;
1704870189d2Schristos 
1705c74ad251Schristos           ND_PRINT(", RES: %u, VID: %u", GET_BE_U_2(tptr) >> 12,
1706c74ad251Schristos                     (GET_BE_U_2(tptr)) & 0x0fff);
1707870189d2Schristos 
1708c74ad251Schristos           tptr += 2;
1709c74ad251Schristos           len -= 8;
1710c74ad251Schristos           stlv_len -= 8;
1711870189d2Schristos 
1712fdccd7e4Schristos           while (stlv_len >= 4) {
1713c74ad251Schristos             ND_PRINT("\n\t        T: %u, R: %u, RES: %u, ISID: %u",
1714c74ad251Schristos                     (GET_BE_U_4(tptr) >> 31),
1715c74ad251Schristos                     (GET_BE_U_4(tptr) >> 30) & 0x01,
1716c74ad251Schristos                     (GET_BE_U_4(tptr) >> 24) & 0x03f,
1717c74ad251Schristos                     (GET_BE_U_4(tptr)) & 0x0ffffff);
1718870189d2Schristos 
1719c74ad251Schristos             tptr += 4;
1720c74ad251Schristos             len -= 4;
1721c74ad251Schristos             stlv_len -= 4;
1722870189d2Schristos           }
1723870189d2Schristos 
1724870189d2Schristos         break;
1725870189d2Schristos 
1726870189d2Schristos       default:
1727870189d2Schristos         break;
1728870189d2Schristos     }
172972c96ff3Schristos     tptr += stlv_len;
173072c96ff3Schristos     len -= stlv_len;
1731870189d2Schristos   }
1732c74ad251Schristos   return (0);
1733870189d2Schristos 
1734fdccd7e4Schristos trunc:
1735c74ad251Schristos   nd_print_trunc(ndo);
1736c74ad251Schristos   return (1);
1737c74ad251Schristos 
1738c74ad251Schristos subtlv_too_long:
1739c74ad251Schristos   ND_PRINT(" (> containing TLV length)");
1740c74ad251Schristos   return (1);
1741c74ad251Schristos 
1742c74ad251Schristos subtlv_too_short:
1743c74ad251Schristos   ND_PRINT(" (too short)");
1744870189d2Schristos   return (1);
1745870189d2Schristos }
1746870189d2Schristos 
17470f74e101Schristos /* shared routine for printing system, node and lsp-ids */
17480f74e101Schristos static char *
1749c74ad251Schristos isis_print_id(netdissect_options *ndo, const uint8_t *cp, u_int id_len)
17500f74e101Schristos {
1751c74ad251Schristos     u_int i;
17520f74e101Schristos     static char id[sizeof("xxxx.xxxx.xxxx.yy-zz")];
17530f74e101Schristos     char *pos = id;
1754c74ad251Schristos     u_int sysid_len;
17550f74e101Schristos 
175672c96ff3Schristos     sysid_len = SYSTEM_ID_LEN;
175772c96ff3Schristos     if (sysid_len > id_len)
175872c96ff3Schristos         sysid_len = id_len;
175972c96ff3Schristos     for (i = 1; i <= sysid_len; i++) {
1760c74ad251Schristos         snprintf(pos, sizeof(id) - (pos - id), "%02x", GET_U_1(cp));
1761c74ad251Schristos 	cp++;
17620f74e101Schristos 	pos += strlen(pos);
17630f74e101Schristos 	if (i == 2 || i == 4)
17640f74e101Schristos 	    *pos++ = '.';
17650f74e101Schristos 	}
17660f74e101Schristos     if (id_len >= NODE_ID_LEN) {
1767c74ad251Schristos         snprintf(pos, sizeof(id) - (pos - id), ".%02x", GET_U_1(cp));
1768c74ad251Schristos 	cp++;
17690f74e101Schristos 	pos += strlen(pos);
17700f74e101Schristos     }
17710f74e101Schristos     if (id_len == LSP_ID_LEN)
1772c74ad251Schristos         snprintf(pos, sizeof(id) - (pos - id), "-%02x", GET_U_1(cp));
17730f74e101Schristos     return (id);
17740f74e101Schristos }
17750f74e101Schristos 
17760f74e101Schristos /* print the 4-byte metric block which is common found in the old-style TLVs */
17770f74e101Schristos static int
1778b3a00663Schristos isis_print_metric_block(netdissect_options *ndo,
1779b3a00663Schristos                         const struct isis_metric_block *isis_metric_block)
17800f74e101Schristos {
1781c74ad251Schristos     ND_PRINT(", Default Metric: %u, %s",
17820f74e101Schristos            ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_default),
1783c74ad251Schristos            ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_default) ? "External" : "Internal");
17840f74e101Schristos     if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_delay))
1785c74ad251Schristos         ND_PRINT("\n\t\t  Delay Metric: %u, %s",
17860f74e101Schristos                ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_delay),
1787c74ad251Schristos                ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_delay) ? "External" : "Internal");
17880f74e101Schristos     if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_expense))
1789c74ad251Schristos         ND_PRINT("\n\t\t  Expense Metric: %u, %s",
17900f74e101Schristos                ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_expense),
1791c74ad251Schristos                ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_expense) ? "External" : "Internal");
17920f74e101Schristos     if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_error))
1793c74ad251Schristos         ND_PRINT("\n\t\t  Error Metric: %u, %s",
17940f74e101Schristos                ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_error),
1795c74ad251Schristos                ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_error) ? "External" : "Internal");
17960f74e101Schristos 
17970f74e101Schristos     return(1); /* everything is ok */
17980f74e101Schristos }
17990f74e101Schristos 
18000f74e101Schristos static int
1801b3a00663Schristos isis_print_tlv_ip_reach(netdissect_options *ndo,
1802c74ad251Schristos                         const uint8_t *cp, const char *ident, u_int length)
18030f74e101Schristos {
18040f74e101Schristos 	int prefix_len;
18050f74e101Schristos 	const struct isis_tlv_ip_reach *tlv_ip_reach;
18060f74e101Schristos 
18070f74e101Schristos 	tlv_ip_reach = (const struct isis_tlv_ip_reach *)cp;
18080f74e101Schristos 
18090f74e101Schristos 	while (length > 0) {
18100f74e101Schristos 		if ((size_t)length < sizeof(*tlv_ip_reach)) {
1811c74ad251Schristos 			ND_PRINT("short IPv4 Reachability (%u vs %zu)",
18120f74e101Schristos                                length,
1813c74ad251Schristos                                sizeof(*tlv_ip_reach));
18140f74e101Schristos 			return (0);
18150f74e101Schristos 		}
18160f74e101Schristos 
1817c74ad251Schristos 		ND_TCHECK_SIZE(tlv_ip_reach);
18180f74e101Schristos 
1819c74ad251Schristos 		prefix_len = mask2plen(GET_IPV4_TO_HOST_ORDER(tlv_ip_reach->mask));
18200f74e101Schristos 
18210f74e101Schristos 		if (prefix_len == -1)
1822c74ad251Schristos 			ND_PRINT("%sIPv4 prefix: %s mask %s",
18230f74e101Schristos                                ident,
1824c74ad251Schristos 			       GET_IPADDR_STRING(tlv_ip_reach->prefix),
1825c74ad251Schristos 			       GET_IPADDR_STRING(tlv_ip_reach->mask));
18260f74e101Schristos 		else
1827c74ad251Schristos 			ND_PRINT("%sIPv4 prefix: %15s/%u",
18280f74e101Schristos                                ident,
1829c74ad251Schristos 			       GET_IPADDR_STRING(tlv_ip_reach->prefix),
1830c74ad251Schristos 			       prefix_len);
18310f74e101Schristos 
1832c74ad251Schristos 		ND_PRINT(", Distribution: %s, Metric: %u, %s",
18330f74e101Schristos                        ISIS_LSP_TLV_METRIC_UPDOWN(tlv_ip_reach->isis_metric_block.metric_default) ? "down" : "up",
18340f74e101Schristos                        ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_default),
1835c74ad251Schristos                        ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_default) ? "External" : "Internal");
18360f74e101Schristos 
18370f74e101Schristos 		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_delay))
1838c74ad251Schristos                     ND_PRINT("%s  Delay Metric: %u, %s",
18390f74e101Schristos                            ident,
18400f74e101Schristos                            ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_delay),
1841c74ad251Schristos                            ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_delay) ? "External" : "Internal");
18420f74e101Schristos 
18430f74e101Schristos 		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_expense))
1844c74ad251Schristos                     ND_PRINT("%s  Expense Metric: %u, %s",
18450f74e101Schristos                            ident,
18460f74e101Schristos                            ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_expense),
1847c74ad251Schristos                            ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_expense) ? "External" : "Internal");
18480f74e101Schristos 
18490f74e101Schristos 		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_error))
1850c74ad251Schristos                     ND_PRINT("%s  Error Metric: %u, %s",
18510f74e101Schristos                            ident,
18520f74e101Schristos                            ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_error),
1853c74ad251Schristos                            ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_error) ? "External" : "Internal");
18540f74e101Schristos 
18550f74e101Schristos 		length -= sizeof(struct isis_tlv_ip_reach);
18560f74e101Schristos 		tlv_ip_reach++;
18570f74e101Schristos 	}
18580f74e101Schristos 	return (1);
1859c74ad251Schristos trunc:
1860c74ad251Schristos 	return 0;
18610f74e101Schristos }
18620f74e101Schristos 
18630f74e101Schristos /*
18640f74e101Schristos  * this is the common IP-REACH subTLV decoder it is called
18650f74e101Schristos  * from various EXTD-IP REACH TLVs (135,235,236,237)
18660f74e101Schristos  */
18670f74e101Schristos 
18680f74e101Schristos static int
1869b3a00663Schristos isis_print_ip_reach_subtlv(netdissect_options *ndo,
1870c74ad251Schristos                            const uint8_t *tptr, u_int subt, u_int subl,
1871ba2ff121Schristos                            const char *ident)
1872ba2ff121Schristos {
18730f74e101Schristos     /* first lets see if we know the subTLVs name*/
1874c74ad251Schristos     ND_PRINT("%s%s subTLV #%u, length: %u",
1875b3a00663Schristos               ident, tok2str(isis_ext_ip_reach_subtlv_values, "unknown", subt),
1876c74ad251Schristos               subt, subl);
18770f74e101Schristos 
1878c74ad251Schristos     ND_TCHECK_LEN(tptr, subl);
18790f74e101Schristos 
18800f74e101Schristos     switch(subt) {
18810f74e101Schristos     case ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR: /* fall through */
18820f74e101Schristos     case ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32:
18830f74e101Schristos         while (subl >= 4) {
1884c74ad251Schristos 	    ND_PRINT(", 0x%08x (=%u)",
1885c74ad251Schristos 		   GET_BE_U_4(tptr),
1886c74ad251Schristos 		   GET_BE_U_4(tptr));
18870f74e101Schristos 	    tptr+=4;
18880f74e101Schristos 	    subl-=4;
18890f74e101Schristos 	}
18900f74e101Schristos 	break;
18910f74e101Schristos     case ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64:
18920f74e101Schristos         while (subl >= 8) {
1893c74ad251Schristos 	    ND_PRINT(", 0x%08x%08x",
1894c74ad251Schristos 		   GET_BE_U_4(tptr),
1895c74ad251Schristos 		   GET_BE_U_4(tptr + 4));
18960f74e101Schristos 	    tptr+=8;
18970f74e101Schristos 	    subl-=8;
18980f74e101Schristos 	}
18990f74e101Schristos 	break;
1900c74ad251Schristos     case ISIS_SUBTLV_EXTD_IP_REACH_PREFIX_SID:
1901ba2ff121Schristos 	{
1902c74ad251Schristos 	    uint8_t algo, flags;
1903c74ad251Schristos 	    uint32_t sid;
19040f74e101Schristos 
1905c74ad251Schristos 	    flags = GET_U_1(tptr);
1906c74ad251Schristos 	    algo = GET_U_1(tptr+1);
19070f74e101Schristos 
1908c74ad251Schristos 	    if (flags & ISIS_PREFIX_SID_FLAG_V) {
1909c74ad251Schristos 	        if (subl < 5)
1910c74ad251Schristos 	            goto trunc;
1911c74ad251Schristos 		sid = GET_BE_U_3(tptr+2);
1912c74ad251Schristos 		tptr+=5;
1913c74ad251Schristos 		subl-=5;
1914c74ad251Schristos 	    } else {
191572c96ff3Schristos 	        if (subl < 6)
1916c74ad251Schristos 	            goto trunc;
1917c74ad251Schristos 		sid = GET_BE_U_4(tptr+2);
1918c74ad251Schristos 		tptr+=6;
1919c74ad251Schristos 		subl-=6;
19200f74e101Schristos 	    }
1921c74ad251Schristos 
1922c74ad251Schristos 	    ND_PRINT(", Flags [%s], Algo %s (%u), %s %u",
1923c74ad251Schristos 		     bittok2str(prefix_sid_flag_values, "None", flags),
1924c74ad251Schristos 		     tok2str(prefix_sid_algo_values, "Unknown", algo), algo,
1925c74ad251Schristos 		     flags & ISIS_PREFIX_SID_FLAG_V ? "label" : "index",
1926c74ad251Schristos 		     sid);
19270f74e101Schristos 	}
19280f74e101Schristos 	break;
19290f74e101Schristos     default:
1930b3a00663Schristos 	if (!print_unknown_data(ndo, tptr, "\n\t\t    ", subl))
19310f74e101Schristos 	  return(0);
19320f74e101Schristos 	break;
19330f74e101Schristos     }
19340f74e101Schristos     return(1);
19350f74e101Schristos 
1936fdccd7e4Schristos trunc:
1937c74ad251Schristos     nd_print_trunc(ndo);
19380f74e101Schristos     return(0);
19390f74e101Schristos }
19400f74e101Schristos 
19410f74e101Schristos /*
19420f74e101Schristos  * this is the common IS-REACH decoder it is called
19430f74e101Schristos  * from various EXTD-IS REACH style TLVs (22,24,222)
19440f74e101Schristos  */
19450f74e101Schristos 
19460f74e101Schristos static int
1947b3a00663Schristos isis_print_ext_is_reach(netdissect_options *ndo,
1948c74ad251Schristos                         const uint8_t *tptr, const char *ident, u_int tlv_type,
1949c74ad251Schristos                         u_int tlv_remaining)
1950ba2ff121Schristos {
19510f74e101Schristos     char ident_buffer[20];
1952c74ad251Schristos     u_int subtlv_type,subtlv_len,subtlv_sum_len;
19530f74e101Schristos     int proc_bytes = 0; /* how many bytes did we process ? */
1954c74ad251Schristos     u_int te_class,priority_level,gmpls_switch_cap;
1955c74ad251Schristos     union { /* int to float conversion buffer for several subTLVs */
1956c74ad251Schristos         float f;
1957c74ad251Schristos         uint32_t i;
1958c74ad251Schristos     } bw;
19590f74e101Schristos 
1960c74ad251Schristos     ND_TCHECK_LEN(tptr, NODE_ID_LEN);
1961c74ad251Schristos     if (tlv_remaining < NODE_ID_LEN)
19620f74e101Schristos         return(0);
19630f74e101Schristos 
1964c74ad251Schristos     ND_PRINT("%sIS Neighbor: %s", ident, isis_print_id(ndo, tptr, NODE_ID_LEN));
1965c74ad251Schristos     tptr+=NODE_ID_LEN;
1966c74ad251Schristos     tlv_remaining-=NODE_ID_LEN;
1967c74ad251Schristos     proc_bytes+=NODE_ID_LEN;
19680f74e101Schristos 
19690f74e101Schristos     if (tlv_type != ISIS_TLV_IS_ALIAS_ID) { /* the Alias TLV Metric field is implicit 0 */
1970c74ad251Schristos         ND_TCHECK_3(tptr);
1971c74ad251Schristos 	if (tlv_remaining < 3)
19720f74e101Schristos 	    return(0);
1973c74ad251Schristos 	ND_PRINT(", Metric: %u", GET_BE_U_3(tptr));
19740f74e101Schristos 	tptr+=3;
1975c74ad251Schristos 	tlv_remaining-=3;
1976c74ad251Schristos 	proc_bytes+=3;
19770f74e101Schristos     }
19780f74e101Schristos 
1979c74ad251Schristos     ND_TCHECK_1(tptr);
1980c74ad251Schristos     if (tlv_remaining < 1)
19810f74e101Schristos         return(0);
1982c74ad251Schristos     subtlv_sum_len=GET_U_1(tptr); /* read out subTLV length */
1983c74ad251Schristos     tptr++;
1984c74ad251Schristos     tlv_remaining--;
1985c74ad251Schristos     proc_bytes++;
1986c74ad251Schristos     ND_PRINT(", %ssub-TLVs present",subtlv_sum_len ? "" : "no ");
19870f74e101Schristos     if (subtlv_sum_len) {
1988c74ad251Schristos         ND_PRINT(" (%u)", subtlv_sum_len);
1989fdccd7e4Schristos         /* prepend the indent string */
19900f74e101Schristos         snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
1991c74ad251Schristos         ident = ident_buffer;
1992c74ad251Schristos         while (subtlv_sum_len != 0) {
1993c74ad251Schristos             ND_TCHECK_2(tptr);
1994c74ad251Schristos             if (tlv_remaining < 2) {
1995c74ad251Schristos                 ND_PRINT("%sRemaining data in TLV shorter than a subTLV header",ident);
1996c74ad251Schristos                 proc_bytes += tlv_remaining;
1997c74ad251Schristos                 break;
1998c74ad251Schristos             }
1999c74ad251Schristos             if (subtlv_sum_len < 2) {
2000c74ad251Schristos                 ND_PRINT("%sRemaining data in subTLVs shorter than a subTLV header",ident);
2001c74ad251Schristos                 proc_bytes += subtlv_sum_len;
2002c74ad251Schristos                 break;
2003c74ad251Schristos             }
2004c74ad251Schristos             subtlv_type=GET_U_1(tptr);
2005c74ad251Schristos             subtlv_len=GET_U_1(tptr + 1);
2006c74ad251Schristos             tptr += 2;
2007c74ad251Schristos             tlv_remaining -= 2;
2008c74ad251Schristos             subtlv_sum_len -= 2;
2009c74ad251Schristos             proc_bytes += 2;
2010c74ad251Schristos             ND_PRINT("%s%s subTLV #%u, length: %u",
2011c74ad251Schristos                       ident, tok2str(isis_ext_is_reach_subtlv_values, "unknown", subtlv_type),
2012c74ad251Schristos                       subtlv_type, subtlv_len);
2013c74ad251Schristos 
2014c74ad251Schristos             if (subtlv_sum_len < subtlv_len) {
2015c74ad251Schristos                 ND_PRINT(" (remaining data in subTLVs shorter than the current subTLV)");
2016c74ad251Schristos                 proc_bytes += subtlv_sum_len;
2017c74ad251Schristos                 break;
2018c74ad251Schristos             }
2019c74ad251Schristos 
2020c74ad251Schristos             if (tlv_remaining < subtlv_len) {
2021c74ad251Schristos                 ND_PRINT(" (> remaining tlv length)");
2022c74ad251Schristos                 proc_bytes += tlv_remaining;
2023c74ad251Schristos                 break;
2024c74ad251Schristos             }
2025c74ad251Schristos 
2026c74ad251Schristos             ND_TCHECK_LEN(tptr, subtlv_len);
2027c74ad251Schristos 
2028c74ad251Schristos             switch(subtlv_type) {
2029c74ad251Schristos             case ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP:
2030c74ad251Schristos             case ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID:
2031c74ad251Schristos             case ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID:
2032c74ad251Schristos                 if (subtlv_len >= 4) {
2033c74ad251Schristos                     ND_PRINT(", 0x%08x", GET_BE_U_4(tptr));
2034c74ad251Schristos                     if (subtlv_len == 8) /* rfc4205 */
2035c74ad251Schristos                         ND_PRINT(", 0x%08x", GET_BE_U_4(tptr + 4));
2036c74ad251Schristos                 }
2037c74ad251Schristos                 break;
2038c74ad251Schristos             case ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR:
2039c74ad251Schristos             case ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR:
2040c74ad251Schristos                 if (subtlv_len >= sizeof(nd_ipv4))
2041c74ad251Schristos                     ND_PRINT(", %s", GET_IPADDR_STRING(tptr));
2042c74ad251Schristos                 break;
2043c74ad251Schristos             case ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW :
2044c74ad251Schristos             case ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW:
2045c74ad251Schristos                 if (subtlv_len >= 4) {
2046c74ad251Schristos                     bw.i = GET_BE_U_4(tptr);
2047c74ad251Schristos                     ND_PRINT(", %.3f Mbps", bw.f * 8 / 1000000);
2048c74ad251Schristos                 }
2049c74ad251Schristos                 break;
2050c74ad251Schristos             case ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW :
2051c74ad251Schristos                 if (subtlv_len >= 32) {
2052c74ad251Schristos                     for (te_class = 0; te_class < 8; te_class++) {
2053c74ad251Schristos                         bw.i = GET_BE_U_4(tptr);
2054c74ad251Schristos                         ND_PRINT("%s  TE-Class %u: %.3f Mbps",
2055c74ad251Schristos                                   ident,
2056c74ad251Schristos                                   te_class,
2057c74ad251Schristos                                   bw.f * 8 / 1000000);
2058c74ad251Schristos                         tptr += 4;
2059c74ad251Schristos                         subtlv_len -= 4;
2060c74ad251Schristos                         subtlv_sum_len -= 4;
2061c74ad251Schristos                         proc_bytes += 4;
2062c74ad251Schristos                     }
2063c74ad251Schristos                 }
2064c74ad251Schristos                 break;
2065c74ad251Schristos             case ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS: /* fall through */
2066c74ad251Schristos             case ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS_OLD:
2067c74ad251Schristos                 if (subtlv_len == 0)
2068c74ad251Schristos                     break;
2069c74ad251Schristos                 ND_PRINT("%sBandwidth Constraints Model ID: %s (%u)",
2070c74ad251Schristos                           ident,
2071c74ad251Schristos                           tok2str(diffserv_te_bc_values, "unknown", GET_U_1(tptr)),
2072c74ad251Schristos                           GET_U_1(tptr));
2073c74ad251Schristos                 tptr++;
2074c74ad251Schristos                 subtlv_len--;
2075c74ad251Schristos                 subtlv_sum_len--;
2076c74ad251Schristos                 proc_bytes++;
2077c74ad251Schristos                 /* decode BCs until the subTLV ends */
2078c74ad251Schristos                 for (te_class = 0; subtlv_len != 0; te_class++) {
2079c74ad251Schristos                     if (subtlv_len < 4)
2080c74ad251Schristos                         break;
2081c74ad251Schristos                     bw.i = GET_BE_U_4(tptr);
2082c74ad251Schristos                     ND_PRINT("%s  Bandwidth constraint CT%u: %.3f Mbps",
2083c74ad251Schristos                               ident,
2084c74ad251Schristos                               te_class,
2085c74ad251Schristos                               bw.f * 8 / 1000000);
2086c74ad251Schristos                     tptr += 4;
2087c74ad251Schristos                     subtlv_len -= 4;
2088c74ad251Schristos                     subtlv_sum_len -= 4;
2089c74ad251Schristos                     proc_bytes += 4;
2090c74ad251Schristos                 }
2091c74ad251Schristos                 break;
2092c74ad251Schristos             case ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC:
2093c74ad251Schristos                 if (subtlv_len >= 3)
2094c74ad251Schristos                     ND_PRINT(", %u", GET_BE_U_3(tptr));
2095c74ad251Schristos                 break;
2096c74ad251Schristos             case ISIS_SUBTLV_EXT_IS_REACH_LINK_ATTRIBUTE:
2097c74ad251Schristos                 if (subtlv_len == 2) {
2098c74ad251Schristos                     ND_PRINT(", [ %s ] (0x%04x)",
2099c74ad251Schristos                               bittok2str(isis_subtlv_link_attribute_values,
2100c74ad251Schristos                                          "Unknown",
2101c74ad251Schristos                                          GET_BE_U_2(tptr)),
2102c74ad251Schristos                               GET_BE_U_2(tptr));
2103c74ad251Schristos                 }
2104c74ad251Schristos                 break;
2105c74ad251Schristos             case ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE:
2106c74ad251Schristos                 if (subtlv_len >= 2) {
2107c74ad251Schristos                     ND_PRINT(", %s, Priority %u",
2108c74ad251Schristos                               bittok2str(gmpls_link_prot_values, "none", GET_U_1(tptr)),
2109c74ad251Schristos                               GET_U_1(tptr + 1));
2110c74ad251Schristos                 }
2111c74ad251Schristos                 break;
2112c74ad251Schristos             case ISIS_SUBTLV_SPB_METRIC:
2113c74ad251Schristos                 if (subtlv_len >= 6) {
2114c74ad251Schristos                     ND_PRINT(", LM: %u", GET_BE_U_3(tptr));
2115c74ad251Schristos                     tptr += 3;
2116c74ad251Schristos                     subtlv_len -= 3;
2117c74ad251Schristos                     subtlv_sum_len -= 3;
2118c74ad251Schristos                     proc_bytes += 3;
2119c74ad251Schristos                     ND_PRINT(", P: %u", GET_U_1(tptr));
2120c74ad251Schristos                     tptr++;
2121c74ad251Schristos                     subtlv_len--;
2122c74ad251Schristos                     subtlv_sum_len--;
2123c74ad251Schristos                     proc_bytes++;
2124c74ad251Schristos                     ND_PRINT(", P-ID: %u", GET_BE_U_2(tptr));
2125c74ad251Schristos                 }
2126c74ad251Schristos                 break;
2127c74ad251Schristos             case ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR:
2128c74ad251Schristos                 if (subtlv_len >= 36) {
2129c74ad251Schristos                     gmpls_switch_cap = GET_U_1(tptr);
2130c74ad251Schristos                     ND_PRINT("%s  Interface Switching Capability:%s",
2131c74ad251Schristos                               ident,
2132c74ad251Schristos                               tok2str(gmpls_switch_cap_values, "Unknown", gmpls_switch_cap));
2133c74ad251Schristos                     ND_PRINT(", LSP Encoding: %s",
2134c74ad251Schristos                               tok2str(gmpls_encoding_values, "Unknown", GET_U_1((tptr + 1))));
2135c74ad251Schristos                     tptr += 4;
2136c74ad251Schristos                     subtlv_len -= 4;
2137c74ad251Schristos                     subtlv_sum_len -= 4;
2138c74ad251Schristos                     proc_bytes += 4;
2139c74ad251Schristos                     ND_PRINT("%s  Max LSP Bandwidth:", ident);
2140c74ad251Schristos                     for (priority_level = 0; priority_level < 8; priority_level++) {
2141c74ad251Schristos                         bw.i = GET_BE_U_4(tptr);
2142c74ad251Schristos                         ND_PRINT("%s    priority level %u: %.3f Mbps",
2143c74ad251Schristos                                   ident,
2144c74ad251Schristos                                   priority_level,
2145c74ad251Schristos                                   bw.f * 8 / 1000000);
2146c74ad251Schristos                         tptr += 4;
2147c74ad251Schristos                         subtlv_len -= 4;
2148c74ad251Schristos                         subtlv_sum_len -= 4;
2149c74ad251Schristos                         proc_bytes += 4;
2150c74ad251Schristos                     }
2151c74ad251Schristos                     switch (gmpls_switch_cap) {
2152c74ad251Schristos                     case GMPLS_PSC1:
2153c74ad251Schristos                     case GMPLS_PSC2:
2154c74ad251Schristos                     case GMPLS_PSC3:
2155c74ad251Schristos                     case GMPLS_PSC4:
2156c74ad251Schristos                         if (subtlv_len < 6)
2157c74ad251Schristos                             break;
2158c74ad251Schristos                         bw.i = GET_BE_U_4(tptr);
2159c74ad251Schristos                         ND_PRINT("%s  Min LSP Bandwidth: %.3f Mbps", ident, bw.f * 8 / 1000000);
2160c74ad251Schristos                         ND_PRINT("%s  Interface MTU: %u", ident,
2161c74ad251Schristos                                  GET_BE_U_2(tptr + 4));
2162c74ad251Schristos                         break;
2163c74ad251Schristos                     case GMPLS_TSC:
2164c74ad251Schristos                         if (subtlv_len < 8)
2165c74ad251Schristos                             break;
2166c74ad251Schristos                         bw.i = GET_BE_U_4(tptr);
2167c74ad251Schristos                         ND_PRINT("%s  Min LSP Bandwidth: %.3f Mbps", ident, bw.f * 8 / 1000000);
2168c74ad251Schristos                         ND_PRINT("%s  Indication %s", ident,
2169c74ad251Schristos                                   tok2str(gmpls_switch_cap_tsc_indication_values, "Unknown (%u)", GET_U_1((tptr + 4))));
2170c74ad251Schristos                         break;
2171c74ad251Schristos                     default:
2172c74ad251Schristos                         /* there is some optional stuff left to decode but this is as of yet
2173c74ad251Schristos                            not specified so just lets hexdump what is left */
2174c74ad251Schristos                         if (subtlv_len != 0) {
2175c74ad251Schristos                             if (!print_unknown_data(ndo, tptr, "\n\t\t    ", subtlv_len))
21760f74e101Schristos                                 return(0);
2177c74ad251Schristos                         }
2178c74ad251Schristos                     }
2179c74ad251Schristos                 }
2180c74ad251Schristos                 break;
2181c74ad251Schristos             case ISIS_SUBTLV_EXT_IS_REACH_LAN_ADJ_SEGMENT_ID:
2182c74ad251Schristos                 if (subtlv_len >= 8) {
2183c74ad251Schristos                     ND_PRINT("%s  Flags: [%s]", ident,
2184c74ad251Schristos                               bittok2str(isis_lan_adj_sid_flag_values,
2185c74ad251Schristos                                          "none",
2186c74ad251Schristos                                          GET_U_1(tptr)));
2187c74ad251Schristos                     int vflag = (GET_U_1(tptr) & 0x20) ? 1:0;
2188c74ad251Schristos                     int lflag = (GET_U_1(tptr) & 0x10) ? 1:0;
2189c74ad251Schristos                     tptr++;
2190c74ad251Schristos                     subtlv_len--;
2191c74ad251Schristos                     subtlv_sum_len--;
2192c74ad251Schristos                     proc_bytes++;
2193c74ad251Schristos                     ND_PRINT("%s  Weight: %u", ident, GET_U_1(tptr));
2194c74ad251Schristos                     tptr++;
2195c74ad251Schristos                     subtlv_len--;
2196c74ad251Schristos                     subtlv_sum_len--;
2197c74ad251Schristos                     proc_bytes++;
2198c74ad251Schristos                     if(subtlv_len>=SYSTEM_ID_LEN) {
2199c74ad251Schristos                         ND_TCHECK_LEN(tptr, SYSTEM_ID_LEN);
2200c74ad251Schristos                         ND_PRINT("%s  Neighbor System-ID: %s", ident,
2201c74ad251Schristos                             isis_print_id(ndo, tptr, SYSTEM_ID_LEN));
2202c74ad251Schristos                     }
2203c74ad251Schristos                     /* RFC 8667 section 2.2.2 */
2204c74ad251Schristos                     /* if V-flag is set to 1 and L-flag is set to 1 ==> 3 octet label */
2205c74ad251Schristos                     /* if V-flag is set to 0 and L-flag is set to 0 ==> 4 octet index */
2206c74ad251Schristos                     if (vflag && lflag) {
2207c74ad251Schristos                         ND_PRINT("%s  Label: %u",
2208c74ad251Schristos                                   ident, GET_BE_U_3(tptr+SYSTEM_ID_LEN));
2209c74ad251Schristos                     } else if ((!vflag) && (!lflag)) {
2210c74ad251Schristos                         ND_PRINT("%s  Index: %u",
2211c74ad251Schristos                                   ident, GET_BE_U_4(tptr+SYSTEM_ID_LEN));
2212c74ad251Schristos                     } else
2213c74ad251Schristos                         nd_print_invalid(ndo);
2214c74ad251Schristos                 }
2215c74ad251Schristos                 break;
2216c74ad251Schristos             default:
2217c74ad251Schristos                 if (!print_unknown_data(ndo, tptr, "\n\t\t    ", subtlv_len))
2218c74ad251Schristos                     return(0);
2219c74ad251Schristos                 break;
2220c74ad251Schristos             }
2221c74ad251Schristos 
22220f74e101Schristos             tptr += subtlv_len;
2223c74ad251Schristos             tlv_remaining -= subtlv_len;
2224c74ad251Schristos             subtlv_sum_len -= subtlv_len;
2225c74ad251Schristos             proc_bytes += subtlv_len;
22260f74e101Schristos         }
22270f74e101Schristos     }
22280f74e101Schristos     return(proc_bytes);
2229c74ad251Schristos 
2230c74ad251Schristos trunc:
2231c74ad251Schristos     return(0);
22320f74e101Schristos }
22330f74e101Schristos 
22340f74e101Schristos /*
22350f74e101Schristos  * this is the common Multi Topology ID decoder
22360f74e101Schristos  * it is called from various MT-TLVs (222,229,235,237)
22370f74e101Schristos  */
22380f74e101Schristos 
2239c74ad251Schristos static uint8_t
2240b3a00663Schristos isis_print_mtid(netdissect_options *ndo,
2241c74ad251Schristos                 const uint8_t *tptr, const char *ident, u_int tlv_remaining)
2242ba2ff121Schristos {
2243c74ad251Schristos     if (tlv_remaining < 2)
2244c74ad251Schristos         goto trunc;
22450f74e101Schristos 
2246c74ad251Schristos     ND_PRINT("%s%s",
22470f74e101Schristos            ident,
22480f74e101Schristos            tok2str(isis_mt_values,
22490f74e101Schristos                    "Reserved for IETF Consensus",
2250c74ad251Schristos                    ISIS_MASK_MTID(GET_BE_U_2(tptr))));
22510f74e101Schristos 
2252c74ad251Schristos     ND_PRINT(" Topology (0x%03x), Flags: [%s]",
2253c74ad251Schristos            ISIS_MASK_MTID(GET_BE_U_2(tptr)),
2254c74ad251Schristos            bittok2str(isis_mt_flag_values, "none",ISIS_MASK_MTFLAGS(GET_BE_U_2(tptr))));
22550f74e101Schristos 
22560f74e101Schristos     return(2);
2257c74ad251Schristos trunc:
2258c74ad251Schristos     return 0;
22590f74e101Schristos }
22600f74e101Schristos 
22610f74e101Schristos /*
22620f74e101Schristos  * this is the common extended IP reach decoder
22630f74e101Schristos  * it is called from TLVs (135,235,236,237)
22640f74e101Schristos  * we process the TLV and optional subTLVs and return
22650f74e101Schristos  * the amount of processed bytes
22660f74e101Schristos  */
22670f74e101Schristos 
2268c74ad251Schristos static u_int
2269b3a00663Schristos isis_print_extd_ip_reach(netdissect_options *ndo,
2270ba2ff121Schristos                          const uint8_t *tptr, const char *ident, uint16_t afi)
2271ba2ff121Schristos {
22720f74e101Schristos     char ident_buffer[20];
2273c74ad251Schristos     uint8_t prefix[sizeof(nd_ipv6)]; /* shared copy buffer for IPv4 and IPv6 prefixes */
22740f74e101Schristos     u_int metric, status_byte, bit_length, byte_length, sublen, processed, subtlvtype, subtlvlen;
22750f74e101Schristos 
2276c74ad251Schristos     metric = GET_BE_U_4(tptr);
22770f74e101Schristos     processed=4;
22780f74e101Schristos     tptr+=4;
22790f74e101Schristos 
22800f74e101Schristos     if (afi == AF_INET) {
2281c74ad251Schristos         status_byte=GET_U_1(tptr);
2282c74ad251Schristos         tptr++;
22830f74e101Schristos         bit_length = status_byte&0x3f;
22840f74e101Schristos         if (bit_length > 32) {
2285c74ad251Schristos             ND_PRINT("%sIPv4 prefix: bad bit length %u",
22860f74e101Schristos                    ident,
2287c74ad251Schristos                    bit_length);
22880f74e101Schristos             return (0);
22890f74e101Schristos         }
22900f74e101Schristos         processed++;
22910f74e101Schristos     } else if (afi == AF_INET6) {
2292c74ad251Schristos         status_byte=GET_U_1(tptr);
2293c74ad251Schristos         bit_length=GET_U_1(tptr + 1);
22940f74e101Schristos         if (bit_length > 128) {
2295c74ad251Schristos             ND_PRINT("%sIPv6 prefix: bad bit length %u",
22960f74e101Schristos                    ident,
2297c74ad251Schristos                    bit_length);
22980f74e101Schristos             return (0);
22990f74e101Schristos         }
2300c74ad251Schristos         tptr+=2;
23010f74e101Schristos         processed+=2;
23020f74e101Schristos     } else
23030f74e101Schristos         return (0); /* somebody is fooling us */
23040f74e101Schristos 
23050f74e101Schristos     byte_length = (bit_length + 7) / 8; /* prefix has variable length encoding */
23060f74e101Schristos 
2307c74ad251Schristos     memset(prefix, 0, sizeof(prefix));   /* clear the copy buffer */
2308c74ad251Schristos     GET_CPY_BYTES(prefix,tptr,byte_length);    /* copy as much as is stored in the TLV */
23090f74e101Schristos     tptr+=byte_length;
23100f74e101Schristos     processed+=byte_length;
23110f74e101Schristos 
23120f74e101Schristos     if (afi == AF_INET)
2313c74ad251Schristos         ND_PRINT("%sIPv4 prefix: %15s/%u",
23140f74e101Schristos                ident,
2315c74ad251Schristos                ipaddr_string(ndo, prefix), /* local buffer, not packet data; don't use GET_IPADDR_STRING() */
2316c74ad251Schristos                bit_length);
2317fdccd7e4Schristos     else if (afi == AF_INET6)
2318c74ad251Schristos         ND_PRINT("%sIPv6 prefix: %s/%u",
23190f74e101Schristos                ident,
2320c74ad251Schristos                ip6addr_string(ndo, prefix), /* local buffer, not packet data; don't use GET_IP6ADDR_STRING() */
2321c74ad251Schristos                bit_length);
23220f74e101Schristos 
2323c74ad251Schristos     ND_PRINT(", Distribution: %s, Metric: %u",
23240f74e101Schristos            ISIS_MASK_TLV_EXTD_IP_UPDOWN(status_byte) ? "down" : "up",
2325c74ad251Schristos            metric);
23260f74e101Schristos 
23270f74e101Schristos     if (afi == AF_INET && ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte))
2328c74ad251Schristos         ND_PRINT(", sub-TLVs present");
2329fdccd7e4Schristos     else if (afi == AF_INET6)
2330c74ad251Schristos         ND_PRINT(", %s%s",
23310f74e101Schristos                ISIS_MASK_TLV_EXTD_IP6_IE(status_byte) ? "External" : "Internal",
2332c74ad251Schristos                ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte) ? ", sub-TLVs present" : "");
23330f74e101Schristos 
23340f74e101Schristos     if ((afi == AF_INET  && ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte))
23350f74e101Schristos      || (afi == AF_INET6 && ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte))
23360f74e101Schristos             ) {
23370f74e101Schristos         /* assume that one prefix can hold more
23380f74e101Schristos            than one subTLV - therefore the first byte must reflect
23390f74e101Schristos            the aggregate bytecount of the subTLVs for this prefix
23400f74e101Schristos         */
2341c74ad251Schristos         sublen=GET_U_1(tptr);
2342c74ad251Schristos         tptr++;
23430f74e101Schristos         processed+=sublen+1;
2344c74ad251Schristos         ND_PRINT(" (%u)", sublen);   /* print out subTLV length */
23450f74e101Schristos 
23460f74e101Schristos         while (sublen>0) {
2347c74ad251Schristos             subtlvtype=GET_U_1(tptr);
2348c74ad251Schristos             subtlvlen=GET_U_1(tptr + 1);
2349c74ad251Schristos             tptr+=2;
2350fdccd7e4Schristos             /* prepend the indent string */
23510f74e101Schristos             snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
2352b3a00663Schristos             if (!isis_print_ip_reach_subtlv(ndo, tptr, subtlvtype, subtlvlen, ident_buffer))
23530f74e101Schristos                 return(0);
23540f74e101Schristos             tptr+=subtlvlen;
23550f74e101Schristos             sublen-=(subtlvlen+2);
23560f74e101Schristos         }
23570f74e101Schristos     }
23580f74e101Schristos     return (processed);
23590f74e101Schristos }
23600f74e101Schristos 
2361c74ad251Schristos static void
2362c74ad251Schristos isis_print_router_cap_subtlv(netdissect_options *ndo, const uint8_t *tptr, uint8_t tlen)
2363c74ad251Schristos {
2364c74ad251Schristos     uint8_t subt, subl;
2365c74ad251Schristos 
2366c74ad251Schristos     while (tlen >= 2) {
2367c74ad251Schristos 	subt = GET_U_1(tptr);
2368c74ad251Schristos 	subl = GET_U_1(tptr+1);
2369c74ad251Schristos 	tlen -= 2;
2370c74ad251Schristos 	tptr += 2;
2371c74ad251Schristos 
2372c74ad251Schristos 	/* first lets see if we know the subTLVs name*/
2373c74ad251Schristos 	ND_PRINT("\n\t\t%s subTLV #%u, length: %u",
2374c74ad251Schristos               tok2str(isis_router_capability_subtlv_values, "unknown", subt),
2375c74ad251Schristos               subt, subl);
2376c74ad251Schristos 
2377c74ad251Schristos 	/*
2378c74ad251Schristos 	 * Boundary check.
2379c74ad251Schristos 	 */
2380c74ad251Schristos 	if (subl > tlen) {
2381c74ad251Schristos 	    break;
2382c74ad251Schristos 	}
2383c74ad251Schristos 	ND_TCHECK_LEN(tptr, subl);
2384c74ad251Schristos 
2385c74ad251Schristos 	switch (subt) {
2386c74ad251Schristos 	case ISIS_SUBTLV_ROUTER_CAP_SR:
2387c74ad251Schristos 	    {
2388c74ad251Schristos 		uint8_t flags, sid_tlen, sid_type, sid_len;
2389c74ad251Schristos 		uint32_t range;
2390c74ad251Schristos 		const uint8_t *sid_ptr;
2391c74ad251Schristos 
2392c74ad251Schristos 		flags = GET_U_1(tptr);
2393c74ad251Schristos 		range = GET_BE_U_3(tptr+1);
2394c74ad251Schristos 		ND_PRINT(", Flags [%s], Range %u",
2395c74ad251Schristos 			 bittok2str(isis_router_capability_sr_flags, "None", flags),
2396c74ad251Schristos 			 range);
2397c74ad251Schristos 		sid_ptr = tptr + 4;
2398c74ad251Schristos 		sid_tlen = subl - 4;
2399c74ad251Schristos 
2400c74ad251Schristos 		while (sid_tlen >= 5) {
2401c74ad251Schristos 		    sid_type = GET_U_1(sid_ptr);
2402c74ad251Schristos 		    sid_len = GET_U_1(sid_ptr+1);
2403c74ad251Schristos 		    sid_tlen -= 2;
2404c74ad251Schristos 		    sid_ptr += 2;
2405c74ad251Schristos 
2406c74ad251Schristos 		    /*
2407c74ad251Schristos 		     * Boundary check.
2408c74ad251Schristos 		     */
2409c74ad251Schristos 		    if (sid_len > sid_tlen) {
2410c74ad251Schristos 			break;
2411c74ad251Schristos 		    }
2412c74ad251Schristos 
2413c74ad251Schristos 		    switch (sid_type) {
2414c74ad251Schristos 		    case 1:
2415c74ad251Schristos 			if (sid_len == 3) {
2416c74ad251Schristos 			    ND_PRINT(", SID value %u", GET_BE_U_3(sid_ptr));
2417c74ad251Schristos 			} else if (sid_len == 4) {
2418c74ad251Schristos 			    ND_PRINT(", SID value %u", GET_BE_U_4(sid_ptr));
2419c74ad251Schristos 			} else {
2420c74ad251Schristos 			    ND_PRINT(", Unknown SID length%u", sid_len);
2421c74ad251Schristos 			}
2422c74ad251Schristos 			break;
2423c74ad251Schristos 		    default:
2424c74ad251Schristos 			print_unknown_data(ndo, sid_ptr, "\n\t\t  ", sid_len);
2425c74ad251Schristos 		    }
2426c74ad251Schristos 
2427c74ad251Schristos 		    sid_ptr += sid_len;
2428c74ad251Schristos 		    sid_tlen -= sid_len;
2429c74ad251Schristos 		}
2430c74ad251Schristos 	    }
2431c74ad251Schristos 	    break;
2432c74ad251Schristos 	default:
2433c74ad251Schristos 	    print_unknown_data(ndo, tptr, "\n\t\t", subl);
2434c74ad251Schristos 	    break;
2435c74ad251Schristos 	}
2436c74ad251Schristos 
2437c74ad251Schristos 	tlen -= subl;
2438c74ad251Schristos 	tptr += subl;
2439c74ad251Schristos     }
2440c74ad251Schristos  trunc:
2441c74ad251Schristos     return;
2442c74ad251Schristos }
2443c74ad251Schristos 
24440f74e101Schristos /*
2445fdccd7e4Schristos  * Clear checksum and lifetime prior to signature verification.
2446fdccd7e4Schristos  */
2447fdccd7e4Schristos static void
2448fdccd7e4Schristos isis_clear_checksum_lifetime(void *header)
2449fdccd7e4Schristos {
2450fdccd7e4Schristos     struct isis_lsp_header *header_lsp = (struct isis_lsp_header *) header;
2451fdccd7e4Schristos 
2452fdccd7e4Schristos     header_lsp->checksum[0] = 0;
2453fdccd7e4Schristos     header_lsp->checksum[1] = 0;
2454fdccd7e4Schristos     header_lsp->remaining_lifetime[0] = 0;
2455fdccd7e4Schristos     header_lsp->remaining_lifetime[1] = 0;
2456fdccd7e4Schristos }
2457fdccd7e4Schristos 
2458fdccd7e4Schristos /*
24590f74e101Schristos  * isis_print
24600f74e101Schristos  * Decode IS-IS packets.  Return 0 on error.
24610f74e101Schristos  */
24620f74e101Schristos 
2463c74ad251Schristos #define INVALID_OR_DECREMENT(length,decr) \
2464c74ad251Schristos     if ((length) < (decr)) { \
2465c74ad251Schristos         ND_PRINT(" [packet length %u < %zu]", (length), (decr)); \
2466c74ad251Schristos         nd_print_invalid(ndo); \
2467c74ad251Schristos         return 1; \
2468c74ad251Schristos     } \
2469c74ad251Schristos     length -= (decr);
2470c74ad251Schristos 
2471b3a00663Schristos static int
2472b3a00663Schristos isis_print(netdissect_options *ndo,
2473b3a00663Schristos            const uint8_t *p, u_int length)
24740f74e101Schristos {
24750f74e101Schristos     const struct isis_common_header *isis_header;
24760f74e101Schristos 
24770f74e101Schristos     const struct isis_iih_lan_header *header_iih_lan;
24780f74e101Schristos     const struct isis_iih_ptp_header *header_iih_ptp;
2479fdccd7e4Schristos     const struct isis_lsp_header *header_lsp;
24800f74e101Schristos     const struct isis_csnp_header *header_csnp;
24810f74e101Schristos     const struct isis_psnp_header *header_psnp;
24820f74e101Schristos 
24830f74e101Schristos     const struct isis_tlv_lsp *tlv_lsp;
24840f74e101Schristos     const struct isis_tlv_ptp_adj *tlv_ptp_adj;
24850f74e101Schristos     const struct isis_tlv_is_reach *tlv_is_reach;
24860f74e101Schristos     const struct isis_tlv_es_reach *tlv_es_reach;
24870f74e101Schristos 
2488c74ad251Schristos     uint8_t version, pdu_version, fixed_len;
2489c74ad251Schristos     uint8_t pdu_type, pdu_max_area, max_area, pdu_id_length, id_length, tlv_type, tlv_len, tlen, alen, prefix_len;
2490c74ad251Schristos     u_int ext_is_len, ext_ip_len;
2491c74ad251Schristos     uint8_t mt_len;
2492c74ad251Schristos     uint8_t isis_subtlv_idrp;
2493b3a00663Schristos     const uint8_t *optr, *pptr, *tptr;
2494c74ad251Schristos     u_int packet_len;
2495c74ad251Schristos     u_short pdu_len, key_id;
2496c74ad251Schristos     u_int i,vendor_id, num_vals;
2497c74ad251Schristos     uint8_t auth_type;
2498c74ad251Schristos     uint8_t num_system_ids;
24990f74e101Schristos     int sigcheck;
25000f74e101Schristos 
2501c74ad251Schristos     ndo->ndo_protocol = "isis";
25020f74e101Schristos     packet_len=length;
25030f74e101Schristos     optr = p; /* initialize the _o_riginal pointer to the packet start -
25040f74e101Schristos                  need it for parsing the checksum TLV and authentication
25050f74e101Schristos                  TLV verification */
25060f74e101Schristos     isis_header = (const struct isis_common_header *)p;
2507c74ad251Schristos     ND_TCHECK_SIZE(isis_header);
250872c96ff3Schristos     if (length < ISIS_COMMON_HEADER_SIZE)
250972c96ff3Schristos         goto trunc;
25100f74e101Schristos     pptr = p+(ISIS_COMMON_HEADER_SIZE);
25110f74e101Schristos     header_iih_lan = (const struct isis_iih_lan_header *)pptr;
25120f74e101Schristos     header_iih_ptp = (const struct isis_iih_ptp_header *)pptr;
2513fdccd7e4Schristos     header_lsp = (const struct isis_lsp_header *)pptr;
25140f74e101Schristos     header_csnp = (const struct isis_csnp_header *)pptr;
25150f74e101Schristos     header_psnp = (const struct isis_psnp_header *)pptr;
25160f74e101Schristos 
2517b3a00663Schristos     if (!ndo->ndo_eflag)
2518c74ad251Schristos         ND_PRINT("IS-IS");
25190f74e101Schristos 
25200f74e101Schristos     /*
25210f74e101Schristos      * Sanity checking of the header.
25220f74e101Schristos      */
25230f74e101Schristos 
2524c74ad251Schristos     version = GET_U_1(isis_header->version);
2525c74ad251Schristos     if (version != ISIS_VERSION) {
2526c74ad251Schristos 	ND_PRINT("version %u packet not supported", version);
25270f74e101Schristos 	return (0);
25280f74e101Schristos     }
25290f74e101Schristos 
2530c74ad251Schristos     pdu_id_length = GET_U_1(isis_header->id_length);
2531c74ad251Schristos     if ((pdu_id_length != SYSTEM_ID_LEN) && (pdu_id_length != 0)) {
2532c74ad251Schristos 	ND_PRINT("system ID length of %u is not supported",
2533c74ad251Schristos 	       pdu_id_length);
25340f74e101Schristos 	return (0);
25350f74e101Schristos     }
25360f74e101Schristos 
2537c74ad251Schristos     pdu_version = GET_U_1(isis_header->pdu_version);
2538c74ad251Schristos     if (pdu_version != ISIS_VERSION) {
2539c74ad251Schristos 	ND_PRINT("version %u packet not supported", pdu_version);
25400f74e101Schristos 	return (0);
25410f74e101Schristos     }
25420f74e101Schristos 
2543c74ad251Schristos     fixed_len = GET_U_1(isis_header->fixed_len);
2544c74ad251Schristos     if (length < fixed_len) {
2545c74ad251Schristos 	ND_PRINT("fixed header length %u > packet length %u", fixed_len, length);
254672c96ff3Schristos 	return (0);
254772c96ff3Schristos     }
254872c96ff3Schristos 
2549c74ad251Schristos     if (fixed_len < ISIS_COMMON_HEADER_SIZE) {
2550c74ad251Schristos 	ND_PRINT("fixed header length %u < minimum header size %u", fixed_len, (u_int)ISIS_COMMON_HEADER_SIZE);
255172c96ff3Schristos 	return (0);
255272c96ff3Schristos     }
255372c96ff3Schristos 
2554c74ad251Schristos     pdu_max_area = GET_U_1(isis_header->max_area);
2555c74ad251Schristos     switch(pdu_max_area) {
25560f74e101Schristos     case 0:
25570f74e101Schristos 	max_area = 3;	 /* silly shit */
25580f74e101Schristos 	break;
25590f74e101Schristos     case 255:
2560c74ad251Schristos 	ND_PRINT("bad packet -- 255 areas");
25610f74e101Schristos 	return (0);
25620f74e101Schristos     default:
2563c74ad251Schristos         max_area = pdu_max_area;
25640f74e101Schristos 	break;
25650f74e101Schristos     }
25660f74e101Schristos 
2567c74ad251Schristos     switch(pdu_id_length) {
25680f74e101Schristos     case 0:
25690f74e101Schristos         id_length = 6;	 /* silly shit again */
25700f74e101Schristos 	break;
2571c74ad251Schristos     case 1:              /* 1-8 are valid sys-ID lengths */
25720f74e101Schristos     case 2:
25730f74e101Schristos     case 3:
25740f74e101Schristos     case 4:
25750f74e101Schristos     case 5:
25760f74e101Schristos     case 6:
25770f74e101Schristos     case 7:
25780f74e101Schristos     case 8:
2579c74ad251Schristos         id_length = pdu_id_length;
25800f74e101Schristos         break;
25810f74e101Schristos     case 255:
25820f74e101Schristos         id_length = 0;   /* entirely useless */
25830f74e101Schristos 	break;
25840f74e101Schristos     default:
2585c74ad251Schristos         id_length = pdu_id_length;
25860f74e101Schristos         break;
25870f74e101Schristos     }
25880f74e101Schristos 
25890f74e101Schristos     /* toss any non 6-byte sys-ID len PDUs */
25900f74e101Schristos     if (id_length != 6 ) {
2591c74ad251Schristos 	ND_PRINT("bad packet -- illegal sys-ID length (%u)", id_length);
25920f74e101Schristos 	return (0);
25930f74e101Schristos     }
25940f74e101Schristos 
2595c74ad251Schristos     pdu_type = GET_U_1(isis_header->pdu_type);
25960f74e101Schristos 
25970f74e101Schristos     /* in non-verbose mode print the basic PDU Type plus PDU specific brief information*/
259872c96ff3Schristos     if (ndo->ndo_vflag == 0) {
2599c74ad251Schristos         ND_PRINT("%s%s",
2600b3a00663Schristos                ndo->ndo_eflag ? "" : ", ",
2601c74ad251Schristos                tok2str(isis_pdu_values, "unknown PDU-Type %u", pdu_type));
260272c96ff3Schristos     } else {
26030f74e101Schristos         /* ok they seem to want to know everything - lets fully decode it */
2604c74ad251Schristos         ND_PRINT("%slength %u", ndo->ndo_eflag ? "" : ", ", length);
26050f74e101Schristos 
2606c74ad251Schristos         ND_PRINT("\n\t%s, hlen: %u, v: %u, pdu-v: %u, sys-id-len: %u (%u), max-area: %u (%u)",
26070f74e101Schristos                tok2str(isis_pdu_values,
26080f74e101Schristos                        "unknown, type %u",
26090f74e101Schristos                        pdu_type),
2610c74ad251Schristos                fixed_len,
2611c74ad251Schristos                version,
2612c74ad251Schristos                pdu_version,
26130f74e101Schristos                id_length,
2614c74ad251Schristos                pdu_id_length,
26150f74e101Schristos                max_area,
2616c74ad251Schristos                pdu_max_area);
26170f74e101Schristos 
2618b3a00663Schristos         if (ndo->ndo_vflag > 1) {
2619b3a00663Schristos             if (!print_unknown_data(ndo, optr, "\n\t", 8)) /* provide the _o_riginal pointer */
26200f74e101Schristos                 return (0);                         /* for optionally debugging the common header */
26210f74e101Schristos         }
262272c96ff3Schristos     }
26230f74e101Schristos 
26240f74e101Schristos     switch (pdu_type) {
26250f74e101Schristos 
26260f74e101Schristos     case ISIS_PDU_L1_LAN_IIH:
26270f74e101Schristos     case ISIS_PDU_L2_LAN_IIH:
2628c74ad251Schristos         if (fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE)) {
2629c74ad251Schristos             ND_PRINT(", bogus fixed header length %u should be %zu",
2630c74ad251Schristos                      fixed_len, ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
26310f74e101Schristos             return (0);
26320f74e101Schristos         }
2633c74ad251Schristos         ND_TCHECK_SIZE(header_iih_lan);
263472c96ff3Schristos         if (length < ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE)
263572c96ff3Schristos             goto trunc;
263672c96ff3Schristos         if (ndo->ndo_vflag == 0) {
2637c74ad251Schristos             ND_PRINT(", src-id %s",
2638c74ad251Schristos                       isis_print_id(ndo, header_iih_lan->source_id, SYSTEM_ID_LEN));
2639c74ad251Schristos             ND_PRINT(", lan-id %s, prio %u",
2640c74ad251Schristos                       isis_print_id(ndo, header_iih_lan->lan_id,NODE_ID_LEN),
2641c74ad251Schristos                       GET_U_1(header_iih_lan->priority));
2642c74ad251Schristos             ND_PRINT(", length %u", length);
264372c96ff3Schristos             return (1);
264472c96ff3Schristos         }
2645c74ad251Schristos         pdu_len=GET_BE_U_2(header_iih_lan->pdu_len);
26460f74e101Schristos         if (packet_len>pdu_len) {
26470f74e101Schristos            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
26480f74e101Schristos            length=pdu_len;
26490f74e101Schristos         }
26500f74e101Schristos 
2651c74ad251Schristos         ND_PRINT("\n\t  source-id: %s,  holding time: %us, Flags: [%s]",
2652c74ad251Schristos                   isis_print_id(ndo, header_iih_lan->source_id,SYSTEM_ID_LEN),
2653c74ad251Schristos                   GET_BE_U_2(header_iih_lan->holding_time),
26540f74e101Schristos                   tok2str(isis_iih_circuit_type_values,
26550f74e101Schristos                           "unknown circuit type 0x%02x",
2656c74ad251Schristos                           GET_U_1(header_iih_lan->circuit_type)));
26570f74e101Schristos 
2658c74ad251Schristos         ND_PRINT("\n\t  lan-id:    %s, Priority: %u, PDU length: %u",
2659c74ad251Schristos                   isis_print_id(ndo, header_iih_lan->lan_id, NODE_ID_LEN),
2660c74ad251Schristos                   GET_U_1(header_iih_lan->priority) & ISIS_LAN_PRIORITY_MASK,
2661c74ad251Schristos                   pdu_len);
26620f74e101Schristos 
2663b3a00663Schristos         if (ndo->ndo_vflag > 1) {
2664b3a00663Schristos             if (!print_unknown_data(ndo, pptr, "\n\t  ", ISIS_IIH_LAN_HEADER_SIZE))
26650f74e101Schristos                 return (0);
26660f74e101Schristos         }
26670f74e101Schristos 
2668c74ad251Schristos         INVALID_OR_DECREMENT(packet_len,ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
26690f74e101Schristos         pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
26700f74e101Schristos         break;
26710f74e101Schristos 
26720f74e101Schristos     case ISIS_PDU_PTP_IIH:
2673c74ad251Schristos         if (fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE)) {
2674c74ad251Schristos             ND_PRINT(", bogus fixed header length %u should be %zu",
2675c74ad251Schristos                       fixed_len, ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
26760f74e101Schristos             return (0);
26770f74e101Schristos         }
2678c74ad251Schristos         ND_TCHECK_SIZE(header_iih_ptp);
267972c96ff3Schristos         if (length < ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE)
268072c96ff3Schristos             goto trunc;
268172c96ff3Schristos         if (ndo->ndo_vflag == 0) {
2682c74ad251Schristos             ND_PRINT(", src-id %s", isis_print_id(ndo, header_iih_ptp->source_id, SYSTEM_ID_LEN));
2683c74ad251Schristos             ND_PRINT(", length %u", length);
268472c96ff3Schristos             return (1);
268572c96ff3Schristos         }
2686c74ad251Schristos         pdu_len=GET_BE_U_2(header_iih_ptp->pdu_len);
26870f74e101Schristos         if (packet_len>pdu_len) {
26880f74e101Schristos             packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
26890f74e101Schristos             length=pdu_len;
26900f74e101Schristos         }
26910f74e101Schristos 
2692c74ad251Schristos         ND_PRINT("\n\t  source-id: %s, holding time: %us, Flags: [%s]",
2693c74ad251Schristos                   isis_print_id(ndo, header_iih_ptp->source_id,SYSTEM_ID_LEN),
2694c74ad251Schristos                   GET_BE_U_2(header_iih_ptp->holding_time),
26950f74e101Schristos                   tok2str(isis_iih_circuit_type_values,
26960f74e101Schristos                           "unknown circuit type 0x%02x",
2697c74ad251Schristos                           GET_U_1(header_iih_ptp->circuit_type)));
26980f74e101Schristos 
2699c74ad251Schristos         ND_PRINT("\n\t  circuit-id: 0x%02x, PDU length: %u",
2700c74ad251Schristos                   GET_U_1(header_iih_ptp->circuit_id),
2701c74ad251Schristos                   pdu_len);
27020f74e101Schristos 
2703b3a00663Schristos         if (ndo->ndo_vflag > 1) {
2704b3a00663Schristos             if (!print_unknown_data(ndo, pptr, "\n\t  ", ISIS_IIH_PTP_HEADER_SIZE))
27050f74e101Schristos                 return (0);
27060f74e101Schristos         }
2707c74ad251Schristos         INVALID_OR_DECREMENT(packet_len,ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
27080f74e101Schristos         pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
27090f74e101Schristos         break;
27100f74e101Schristos 
27110f74e101Schristos     case ISIS_PDU_L1_LSP:
27120f74e101Schristos     case ISIS_PDU_L2_LSP:
2713c74ad251Schristos         if (fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE)) {
2714c74ad251Schristos             ND_PRINT(", bogus fixed header length %u should be %zu",
2715c74ad251Schristos                    fixed_len, ISIS_LSP_HEADER_SIZE);
27160f74e101Schristos             return (0);
27170f74e101Schristos         }
2718c74ad251Schristos         ND_TCHECK_SIZE(header_lsp);
271972c96ff3Schristos         if (length < ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE)
272072c96ff3Schristos             goto trunc;
272172c96ff3Schristos         if (ndo->ndo_vflag == 0) {
2722c74ad251Schristos             ND_PRINT(", lsp-id %s, seq 0x%08x, lifetime %5us",
2723c74ad251Schristos                       isis_print_id(ndo, header_lsp->lsp_id, LSP_ID_LEN),
2724c74ad251Schristos                       GET_BE_U_4(header_lsp->sequence_number),
2725c74ad251Schristos                       GET_BE_U_2(header_lsp->remaining_lifetime));
2726c74ad251Schristos             ND_PRINT(", length %u", length);
272772c96ff3Schristos             return (1);
272872c96ff3Schristos         }
2729c74ad251Schristos         pdu_len=GET_BE_U_2(header_lsp->pdu_len);
27300f74e101Schristos         if (packet_len>pdu_len) {
27310f74e101Schristos             packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
27320f74e101Schristos             length=pdu_len;
27330f74e101Schristos         }
27340f74e101Schristos 
2735c74ad251Schristos         ND_PRINT("\n\t  lsp-id: %s, seq: 0x%08x, lifetime: %5us\n\t  chksum: 0x%04x",
2736c74ad251Schristos                isis_print_id(ndo, header_lsp->lsp_id, LSP_ID_LEN),
2737c74ad251Schristos                GET_BE_U_4(header_lsp->sequence_number),
2738c74ad251Schristos                GET_BE_U_2(header_lsp->remaining_lifetime),
2739c74ad251Schristos                GET_BE_U_2(header_lsp->checksum));
27400f74e101Schristos 
274172c96ff3Schristos         osi_print_cksum(ndo, (const uint8_t *)header_lsp->lsp_id,
2742c74ad251Schristos                         GET_BE_U_2(header_lsp->checksum),
274372c96ff3Schristos                         12, length-12);
27440f74e101Schristos 
2745c74ad251Schristos         ND_PRINT(", PDU length: %u, Flags: [ %s",
27460f74e101Schristos                pdu_len,
2747c74ad251Schristos                ISIS_MASK_LSP_OL_BIT(header_lsp->typeblock) ? "Overload bit set, " : "");
27480f74e101Schristos 
27490f74e101Schristos         if (ISIS_MASK_LSP_ATT_BITS(header_lsp->typeblock)) {
2750c74ad251Schristos             ND_PRINT("%s", ISIS_MASK_LSP_ATT_DEFAULT_BIT(header_lsp->typeblock) ? "default " : "");
2751c74ad251Schristos             ND_PRINT("%s", ISIS_MASK_LSP_ATT_DELAY_BIT(header_lsp->typeblock) ? "delay " : "");
2752c74ad251Schristos             ND_PRINT("%s", ISIS_MASK_LSP_ATT_EXPENSE_BIT(header_lsp->typeblock) ? "expense " : "");
2753c74ad251Schristos             ND_PRINT("%s", ISIS_MASK_LSP_ATT_ERROR_BIT(header_lsp->typeblock) ? "error " : "");
2754c74ad251Schristos             ND_PRINT("ATT bit set, ");
27550f74e101Schristos         }
2756c74ad251Schristos         ND_PRINT("%s", ISIS_MASK_LSP_PARTITION_BIT(header_lsp->typeblock) ? "P bit set, " : "");
2757c74ad251Schristos         ND_PRINT("%s ]", tok2str(isis_lsp_istype_values, "Unknown(0x%x)",
2758c74ad251Schristos                   ISIS_MASK_LSP_ISTYPE_BITS(header_lsp->typeblock)));
27590f74e101Schristos 
2760b3a00663Schristos         if (ndo->ndo_vflag > 1) {
2761b3a00663Schristos             if (!print_unknown_data(ndo, pptr, "\n\t  ", ISIS_LSP_HEADER_SIZE))
27620f74e101Schristos                 return (0);
27630f74e101Schristos         }
27640f74e101Schristos 
2765c74ad251Schristos         INVALID_OR_DECREMENT(packet_len,ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
27660f74e101Schristos         pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
27670f74e101Schristos         break;
27680f74e101Schristos 
27690f74e101Schristos     case ISIS_PDU_L1_CSNP:
27700f74e101Schristos     case ISIS_PDU_L2_CSNP:
2771c74ad251Schristos         if (fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE)) {
2772c74ad251Schristos             ND_PRINT(", bogus fixed header length %u should be %zu",
2773c74ad251Schristos                       fixed_len, ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
27740f74e101Schristos             return (0);
27750f74e101Schristos         }
2776c74ad251Schristos         ND_TCHECK_SIZE(header_csnp);
277772c96ff3Schristos         if (length < ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE)
277872c96ff3Schristos             goto trunc;
277972c96ff3Schristos         if (ndo->ndo_vflag == 0) {
2780c74ad251Schristos             ND_PRINT(", src-id %s", isis_print_id(ndo, header_csnp->source_id, NODE_ID_LEN));
2781c74ad251Schristos             ND_PRINT(", length %u", length);
278272c96ff3Schristos             return (1);
278372c96ff3Schristos         }
2784c74ad251Schristos         pdu_len=GET_BE_U_2(header_csnp->pdu_len);
27850f74e101Schristos         if (packet_len>pdu_len) {
27860f74e101Schristos             packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
27870f74e101Schristos             length=pdu_len;
27880f74e101Schristos         }
27890f74e101Schristos 
2790c74ad251Schristos         ND_PRINT("\n\t  source-id:    %s, PDU length: %u",
2791c74ad251Schristos                isis_print_id(ndo, header_csnp->source_id, NODE_ID_LEN),
2792c74ad251Schristos                pdu_len);
2793c74ad251Schristos         ND_PRINT("\n\t  start lsp-id: %s",
2794c74ad251Schristos                isis_print_id(ndo, header_csnp->start_lsp_id, LSP_ID_LEN));
2795c74ad251Schristos         ND_PRINT("\n\t  end lsp-id:   %s",
2796c74ad251Schristos                isis_print_id(ndo, header_csnp->end_lsp_id, LSP_ID_LEN));
27970f74e101Schristos 
2798b3a00663Schristos         if (ndo->ndo_vflag > 1) {
2799b3a00663Schristos             if (!print_unknown_data(ndo, pptr, "\n\t  ", ISIS_CSNP_HEADER_SIZE))
28000f74e101Schristos                 return (0);
28010f74e101Schristos         }
28020f74e101Schristos 
2803c74ad251Schristos         INVALID_OR_DECREMENT(packet_len,ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
28040f74e101Schristos         pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
28050f74e101Schristos         break;
28060f74e101Schristos 
28070f74e101Schristos     case ISIS_PDU_L1_PSNP:
28080f74e101Schristos     case ISIS_PDU_L2_PSNP:
2809c74ad251Schristos         if (fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE)) {
2810c74ad251Schristos             ND_PRINT("- bogus fixed header length %u should be %zu",
2811c74ad251Schristos                    fixed_len, ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
28120f74e101Schristos             return (0);
28130f74e101Schristos         }
2814c74ad251Schristos         ND_TCHECK_SIZE(header_psnp);
281572c96ff3Schristos         if (length < ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE)
281672c96ff3Schristos             goto trunc;
281772c96ff3Schristos         if (ndo->ndo_vflag == 0) {
2818c74ad251Schristos             ND_PRINT(", src-id %s", isis_print_id(ndo, header_psnp->source_id, NODE_ID_LEN));
2819c74ad251Schristos             ND_PRINT(", length %u", length);
282072c96ff3Schristos             return (1);
282172c96ff3Schristos         }
2822c74ad251Schristos         pdu_len=GET_BE_U_2(header_psnp->pdu_len);
28230f74e101Schristos         if (packet_len>pdu_len) {
28240f74e101Schristos             packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
28250f74e101Schristos             length=pdu_len;
28260f74e101Schristos         }
28270f74e101Schristos 
2828c74ad251Schristos         ND_PRINT("\n\t  source-id:    %s, PDU length: %u",
2829c74ad251Schristos                isis_print_id(ndo, header_psnp->source_id, NODE_ID_LEN),
2830c74ad251Schristos                pdu_len);
28310f74e101Schristos 
2832b3a00663Schristos         if (ndo->ndo_vflag > 1) {
2833b3a00663Schristos             if (!print_unknown_data(ndo, pptr, "\n\t  ", ISIS_PSNP_HEADER_SIZE))
28340f74e101Schristos                 return (0);
28350f74e101Schristos         }
28360f74e101Schristos 
2837c74ad251Schristos         INVALID_OR_DECREMENT(packet_len,ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
28380f74e101Schristos         pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
28390f74e101Schristos         break;
28400f74e101Schristos 
28410f74e101Schristos     default:
284272c96ff3Schristos         if (ndo->ndo_vflag == 0) {
2843c74ad251Schristos             ND_PRINT(", length %u", length);
284472c96ff3Schristos             return (1);
284572c96ff3Schristos         }
2846ba2ff121Schristos 	(void)print_unknown_data(ndo, pptr, "\n\t  ", length);
28470f74e101Schristos 	return (0);
28480f74e101Schristos     }
28490f74e101Schristos 
28500f74e101Schristos     /*
28510f74e101Schristos      * Now print the TLV's.
28520f74e101Schristos      */
28530f74e101Schristos 
285472c96ff3Schristos     while (packet_len > 0) {
2855c74ad251Schristos 	ND_TCHECK_2(pptr);
285672c96ff3Schristos 	if (packet_len < 2)
285772c96ff3Schristos 	    goto trunc;
2858c74ad251Schristos 	tlv_type = GET_U_1(pptr);
2859c74ad251Schristos 	tlv_len = GET_U_1(pptr + 1);
2860c74ad251Schristos 	pptr += 2;
28610f74e101Schristos 	packet_len -= 2;
2862c74ad251Schristos         tlen = tlv_len; /* copy temporary len & pointer to packet data */
2863c74ad251Schristos         tptr = pptr;
28640f74e101Schristos 
28650f74e101Schristos         /* first lets see if we know the TLVs name*/
2866c74ad251Schristos 	ND_PRINT("\n\t    %s TLV #%u, length: %u",
28670f74e101Schristos                tok2str(isis_tlv_values,
28680f74e101Schristos                        "unknown",
28690f74e101Schristos                        tlv_type),
28700f74e101Schristos                tlv_type,
2871c74ad251Schristos                tlv_len);
28720f74e101Schristos 
287372c96ff3Schristos 	if (packet_len < tlv_len)
287472c96ff3Schristos 	    goto trunc;
287572c96ff3Schristos 
28760f74e101Schristos         /* now check if we have a decoder otherwise do a hexdump at the end*/
28770f74e101Schristos 	switch (tlv_type) {
28780f74e101Schristos 	case ISIS_TLV_AREA_ADDR:
2879c74ad251Schristos 	    while (tlen != 0) {
2880c74ad251Schristos 		alen = GET_U_1(tptr);
2881c74ad251Schristos 		tptr++;
2882c74ad251Schristos 		tlen--;
2883c74ad251Schristos 		if (tlen < alen)
2884c74ad251Schristos 		    goto tlv_trunc;
2885c74ad251Schristos 		ND_PRINT("\n\t      Area address (length: %u): %s",
28860f74e101Schristos                        alen,
2887c74ad251Schristos                        GET_ISONSAP_STRING(tptr, alen));
28880f74e101Schristos 		tptr += alen;
2889c74ad251Schristos 		tlen -= alen;
28900f74e101Schristos 	    }
28910f74e101Schristos 	    break;
28920f74e101Schristos 	case ISIS_TLV_ISNEIGH:
2893c74ad251Schristos 	    while (tlen != 0) {
2894c74ad251Schristos 		if (tlen < MAC_ADDR_LEN)
2895c74ad251Schristos 		    goto tlv_trunc;
2896c74ad251Schristos                 ND_TCHECK_LEN(tptr, MAC_ADDR_LEN);
2897c74ad251Schristos                 ND_PRINT("\n\t      SNPA: %s", isis_print_id(ndo, tptr, MAC_ADDR_LEN));
2898c74ad251Schristos                 tlen -= MAC_ADDR_LEN;
2899c74ad251Schristos                 tptr += MAC_ADDR_LEN;
29000f74e101Schristos 	    }
29010f74e101Schristos 	    break;
29020f74e101Schristos 
2903c74ad251Schristos         case ISIS_TLV_INSTANCE_ID:
2904c74ad251Schristos             if (tlen < 4)
2905c74ad251Schristos                 goto tlv_trunc;
2906c74ad251Schristos             num_vals = (tlen-2)/2;
2907c74ad251Schristos             ND_PRINT("\n\t      Instance ID: %u, ITIDs(%u)%s ",
2908c74ad251Schristos                      GET_BE_U_2(tptr), num_vals,
2909c74ad251Schristos                      num_vals ? ":" : "");
2910c74ad251Schristos             tptr += 2;
2911c74ad251Schristos             tlen -= 2;
2912c74ad251Schristos             for (i=0; i < num_vals; i++) {
2913c74ad251Schristos                 ND_PRINT("%u", GET_BE_U_2(tptr));
2914c74ad251Schristos                 if (i < (num_vals - 1)) {
2915c74ad251Schristos                    ND_PRINT(", ");
29160f74e101Schristos                 }
2917c74ad251Schristos                 tptr += 2;
2918c74ad251Schristos                 tlen -= 2;
29190f74e101Schristos             }
29200f74e101Schristos             break;
29210f74e101Schristos 
29220f74e101Schristos 	case ISIS_TLV_PADDING:
29230f74e101Schristos 	    break;
29240f74e101Schristos 
29250f74e101Schristos         case ISIS_TLV_MT_IS_REACH:
2926c74ad251Schristos             mt_len = isis_print_mtid(ndo, tptr, "\n\t      ", tlen);
29270f74e101Schristos             if (mt_len == 0) /* did something go wrong ? */
2928c74ad251Schristos                 goto trunc;
29290f74e101Schristos             tptr+=mt_len;
2930c74ad251Schristos             tlen-=mt_len;
2931c74ad251Schristos             while (tlen != 0) {
2932c74ad251Schristos                 ext_is_len = isis_print_ext_is_reach(ndo, tptr, "\n\t      ", tlv_type, tlen);
29330f74e101Schristos                 if (ext_is_len == 0) /* did something go wrong ? */
2934c74ad251Schristos                     goto trunc;
2935c74ad251Schristos                 if (tlen < ext_is_len) {
2936c74ad251Schristos                     ND_PRINT(" [remaining tlv length %u < %u]", tlen, ext_is_len);
2937c74ad251Schristos                     nd_print_invalid(ndo);
2938c74ad251Schristos                     break;
2939c74ad251Schristos                 }
2940c74ad251Schristos                 tlen-=(uint8_t)ext_is_len;
2941c74ad251Schristos                 tptr+=(uint8_t)ext_is_len;
29420f74e101Schristos             }
29430f74e101Schristos             break;
29440f74e101Schristos 
29450f74e101Schristos         case ISIS_TLV_IS_ALIAS_ID:
2946c74ad251Schristos 	    while (tlen != 0) {
2947c74ad251Schristos 	        ext_is_len = isis_print_ext_is_reach(ndo, tptr, "\n\t      ", tlv_type, tlen);
29480f74e101Schristos 		if (ext_is_len == 0) /* did something go wrong ? */
2949c74ad251Schristos 	            goto trunc;
2950c74ad251Schristos                 if (tlen < ext_is_len) {
2951c74ad251Schristos                     ND_PRINT(" [remaining tlv length %u < %u]", tlen, ext_is_len);
2952c74ad251Schristos                     nd_print_invalid(ndo);
2953c74ad251Schristos                     break;
2954c74ad251Schristos                 }
2955c74ad251Schristos 		tlen-=(uint8_t)ext_is_len;
2956c74ad251Schristos 		tptr+=(uint8_t)ext_is_len;
29570f74e101Schristos 	    }
29580f74e101Schristos 	    break;
29590f74e101Schristos 
29600f74e101Schristos         case ISIS_TLV_EXT_IS_REACH:
2961c74ad251Schristos             while (tlen != 0) {
2962c74ad251Schristos                 ext_is_len = isis_print_ext_is_reach(ndo, tptr, "\n\t      ", tlv_type, tlen);
29630f74e101Schristos                 if (ext_is_len == 0) /* did something go wrong ? */
2964c74ad251Schristos                     goto trunc;
2965c74ad251Schristos                 if (tlen < ext_is_len) {
2966c74ad251Schristos                     ND_PRINT(" [remaining tlv length %u < %u]", tlen, ext_is_len);
2967c74ad251Schristos                     nd_print_invalid(ndo);
2968c74ad251Schristos                     break;
2969c74ad251Schristos                 }
2970c74ad251Schristos                 tlen-=(uint8_t)ext_is_len;
2971c74ad251Schristos                 tptr+=(uint8_t)ext_is_len;
29720f74e101Schristos             }
29730f74e101Schristos             break;
29740f74e101Schristos         case ISIS_TLV_IS_REACH:
2975c74ad251Schristos             if (tlen < 1)
2976c74ad251Schristos                 goto tlv_trunc;
2977c74ad251Schristos             ND_PRINT("\n\t      %s",
29780f74e101Schristos                    tok2str(isis_is_reach_virtual_values,
29790f74e101Schristos                            "bogus virtual flag 0x%02x",
2980c74ad251Schristos                            GET_U_1(tptr)));
2981c74ad251Schristos 	    tptr++;
2982c74ad251Schristos 	    tlen--;
29830f74e101Schristos 	    tlv_is_reach = (const struct isis_tlv_is_reach *)tptr;
2984c74ad251Schristos             while (tlen != 0) {
2985c74ad251Schristos                 if (tlen < sizeof(struct isis_tlv_is_reach))
2986c74ad251Schristos                     goto tlv_trunc;
2987c74ad251Schristos 		ND_TCHECK_SIZE(tlv_is_reach);
2988c74ad251Schristos 		ND_PRINT("\n\t      IS Neighbor: %s",
2989c74ad251Schristos 		       isis_print_id(ndo, tlv_is_reach->neighbor_nodeid, NODE_ID_LEN));
2990b3a00663Schristos 		isis_print_metric_block(ndo, &tlv_is_reach->isis_metric_block);
2991c74ad251Schristos 		tlen -= sizeof(struct isis_tlv_is_reach);
29920f74e101Schristos 		tlv_is_reach++;
29930f74e101Schristos 	    }
29940f74e101Schristos             break;
29950f74e101Schristos 
29960f74e101Schristos         case ISIS_TLV_ESNEIGH:
29970f74e101Schristos 	    tlv_es_reach = (const struct isis_tlv_es_reach *)tptr;
2998c74ad251Schristos             while (tlen != 0) {
2999c74ad251Schristos                 if (tlen < sizeof(struct isis_tlv_es_reach))
3000c74ad251Schristos                     goto tlv_trunc;
3001c74ad251Schristos 		ND_TCHECK_SIZE(tlv_es_reach);
3002c74ad251Schristos 		ND_PRINT("\n\t      ES Neighbor: %s",
3003c74ad251Schristos                        isis_print_id(ndo, tlv_es_reach->neighbor_sysid, SYSTEM_ID_LEN));
3004b3a00663Schristos 		isis_print_metric_block(ndo, &tlv_es_reach->isis_metric_block);
3005c74ad251Schristos 		tlen -= sizeof(struct isis_tlv_es_reach);
30060f74e101Schristos 		tlv_es_reach++;
30070f74e101Schristos 	    }
30080f74e101Schristos             break;
30090f74e101Schristos 
30100f74e101Schristos             /* those two TLVs share the same format */
30110f74e101Schristos 	case ISIS_TLV_INT_IP_REACH:
30120f74e101Schristos 	case ISIS_TLV_EXT_IP_REACH:
3013b3a00663Schristos 		if (!isis_print_tlv_ip_reach(ndo, pptr, "\n\t      ", tlv_len))
30140f74e101Schristos 			return (1);
30150f74e101Schristos 		break;
30160f74e101Schristos 
30170f74e101Schristos 	case ISIS_TLV_EXTD_IP_REACH:
3018c74ad251Schristos 	    while (tlen != 0) {
3019b3a00663Schristos                 ext_ip_len = isis_print_extd_ip_reach(ndo, tptr, "\n\t      ", AF_INET);
30200f74e101Schristos                 if (ext_ip_len == 0) /* did something go wrong ? */
3021c74ad251Schristos                     goto trunc;
3022c74ad251Schristos                 if (tlen < ext_ip_len) {
3023c74ad251Schristos                     ND_PRINT(" [remaining tlv length %u < %u]", tlen, ext_ip_len);
3024c74ad251Schristos                     nd_print_invalid(ndo);
3025c74ad251Schristos                     break;
3026c74ad251Schristos                 }
3027c74ad251Schristos                 tlen-=(uint8_t)ext_ip_len;
3028c74ad251Schristos                 tptr+=(uint8_t)ext_ip_len;
30290f74e101Schristos             }
30300f74e101Schristos             break;
30310f74e101Schristos 
30320f74e101Schristos         case ISIS_TLV_MT_IP_REACH:
3033c74ad251Schristos             mt_len = isis_print_mtid(ndo, tptr, "\n\t      ", tlen);
30340f74e101Schristos             if (mt_len == 0) { /* did something go wrong ? */
3035c74ad251Schristos                 goto trunc;
30360f74e101Schristos             }
30370f74e101Schristos             tptr+=mt_len;
3038c74ad251Schristos             tlen-=mt_len;
30390f74e101Schristos 
3040c74ad251Schristos             while (tlen != 0) {
3041b3a00663Schristos                 ext_ip_len = isis_print_extd_ip_reach(ndo, tptr, "\n\t      ", AF_INET);
30420f74e101Schristos                 if (ext_ip_len == 0) /* did something go wrong ? */
3043c74ad251Schristos                     goto trunc;
3044c74ad251Schristos                 if (tlen < ext_ip_len) {
3045c74ad251Schristos                     ND_PRINT(" [remaining tlv length %u < %u]", tlen, ext_ip_len);
3046c74ad251Schristos                     nd_print_invalid(ndo);
3047c74ad251Schristos                     break;
3048c74ad251Schristos                 }
3049c74ad251Schristos                 tlen-=(uint8_t)ext_ip_len;
3050c74ad251Schristos                 tptr+=(uint8_t)ext_ip_len;
30510f74e101Schristos             }
30520f74e101Schristos             break;
30530f74e101Schristos 
30540f74e101Schristos 	case ISIS_TLV_IP6_REACH:
3055c74ad251Schristos             while (tlen != 0) {
3056b3a00663Schristos                 ext_ip_len = isis_print_extd_ip_reach(ndo, tptr, "\n\t      ", AF_INET6);
30570f74e101Schristos                 if (ext_ip_len == 0) /* did something go wrong ? */
3058c74ad251Schristos                     goto trunc;
3059c74ad251Schristos                 if (tlen < ext_ip_len) {
3060c74ad251Schristos                     ND_PRINT(" [remaining tlv length %u < %u]", tlen, ext_ip_len);
3061c74ad251Schristos                     nd_print_invalid(ndo);
3062c74ad251Schristos                     break;
3063c74ad251Schristos                 }
3064c74ad251Schristos                 tlen-=(uint8_t)ext_ip_len;
3065c74ad251Schristos                 tptr+=(uint8_t)ext_ip_len;
30660f74e101Schristos             }
30670f74e101Schristos             break;
30680f74e101Schristos 
30690f74e101Schristos 	case ISIS_TLV_MT_IP6_REACH:
3070c74ad251Schristos             mt_len = isis_print_mtid(ndo, tptr, "\n\t      ", tlen);
30710f74e101Schristos             if (mt_len == 0) { /* did something go wrong ? */
3072c74ad251Schristos                 goto trunc;
30730f74e101Schristos             }
30740f74e101Schristos             tptr+=mt_len;
3075c74ad251Schristos             tlen-=mt_len;
30760f74e101Schristos 
3077c74ad251Schristos             while (tlen != 0) {
3078b3a00663Schristos                 ext_ip_len = isis_print_extd_ip_reach(ndo, tptr, "\n\t      ", AF_INET6);
30790f74e101Schristos                 if (ext_ip_len == 0) /* did something go wrong ? */
3080c74ad251Schristos                     goto trunc;
3081c74ad251Schristos                 if (tlen < ext_ip_len) {
3082c74ad251Schristos                     ND_PRINT(" [remaining tlv length %u < %u]", tlen, ext_ip_len);
3083c74ad251Schristos                     nd_print_invalid(ndo);
3084c74ad251Schristos                     break;
3085c74ad251Schristos                 }
3086c74ad251Schristos                 tlen-=(uint8_t)ext_ip_len;
3087c74ad251Schristos                 tptr+=(uint8_t)ext_ip_len;
30880f74e101Schristos             }
30890f74e101Schristos             break;
30900f74e101Schristos 
30910f74e101Schristos 	case ISIS_TLV_IP6ADDR:
3092c74ad251Schristos 	    while (tlen != 0) {
3093c74ad251Schristos                 if (tlen < sizeof(nd_ipv6))
3094c74ad251Schristos                     goto tlv_trunc;
3095c74ad251Schristos                 ND_PRINT("\n\t      IPv6 interface address: %s",
3096c74ad251Schristos 		       GET_IP6ADDR_STRING(tptr));
30970f74e101Schristos 
3098c74ad251Schristos 		tptr += sizeof(nd_ipv6);
3099c74ad251Schristos 		tlen -= sizeof(nd_ipv6);
31000f74e101Schristos 	    }
31010f74e101Schristos 	    break;
31020f74e101Schristos 	case ISIS_TLV_AUTH:
3103c74ad251Schristos 	    if (tlen < 1)
3104c74ad251Schristos 	        goto tlv_trunc;
3105c74ad251Schristos 	    auth_type = GET_U_1(tptr);
3106c74ad251Schristos 	    tptr++;
3107c74ad251Schristos 	    tlen--;
31080f74e101Schristos 
3109c74ad251Schristos             ND_PRINT("\n\t      %s: ",
31100f74e101Schristos                    tok2str(isis_subtlv_auth_values,
31110f74e101Schristos                            "unknown Authentication type 0x%02x",
3112c74ad251Schristos                            auth_type));
31130f74e101Schristos 
3114c74ad251Schristos 	    switch (auth_type) {
31150f74e101Schristos 	    case ISIS_SUBTLV_AUTH_SIMPLE:
3116c74ad251Schristos 		nd_printjnp(ndo, tptr, tlen);
31170f74e101Schristos 		break;
31180f74e101Schristos 	    case ISIS_SUBTLV_AUTH_MD5:
3119c74ad251Schristos 		for(i=0;i<tlen;i++) {
3120c74ad251Schristos 		    ND_PRINT("%02x", GET_U_1(tptr + i));
31210f74e101Schristos 		}
3122c74ad251Schristos 		if (tlen != ISIS_SUBTLV_AUTH_MD5_LEN)
3123c74ad251Schristos                     ND_PRINT(", (invalid subTLV) ");
31240f74e101Schristos 
3125c74ad251Schristos                 sigcheck = signature_verify(ndo, optr, length, tptr,
3126fdccd7e4Schristos                                             isis_clear_checksum_lifetime,
3127fdccd7e4Schristos                                             header_lsp);
3128c74ad251Schristos                 ND_PRINT(" (%s)", tok2str(signature_check_values, "Unknown", sigcheck));
31290f74e101Schristos 
31300f74e101Schristos 		break;
31310e9868baSchristos             case ISIS_SUBTLV_AUTH_GENERIC:
3132c74ad251Schristos                 if (tlen < 2)
3133c74ad251Schristos                     goto tlv_trunc;
3134c74ad251Schristos                 key_id = GET_BE_U_2(tptr);
3135c74ad251Schristos                 ND_PRINT("%u, password: ", key_id);
3136c74ad251Schristos                 tptr += 2;
3137c74ad251Schristos                 tlen -= 2;
3138c74ad251Schristos                 for(i=0;i<tlen;i++) {
3139c74ad251Schristos                     ND_PRINT("%02x", GET_U_1(tptr + i));
31400e9868baSchristos                 }
31410e9868baSchristos                 break;
31420f74e101Schristos 	    case ISIS_SUBTLV_AUTH_PRIVATE:
31430f74e101Schristos 	    default:
3144c74ad251Schristos 		if (!print_unknown_data(ndo, tptr, "\n\t\t  ", tlen))
31450f74e101Schristos 		    return(0);
31460f74e101Schristos 		break;
31470f74e101Schristos 	    }
31480f74e101Schristos 	    break;
31490f74e101Schristos 
31500f74e101Schristos 	case ISIS_TLV_PTP_ADJ:
31510f74e101Schristos 	    tlv_ptp_adj = (const struct isis_tlv_ptp_adj *)tptr;
3152c74ad251Schristos 	    if(tlen>=1) {
3153c74ad251Schristos 		ND_PRINT("\n\t      Adjacency State: %s (%u)",
3154*26ba0b50Schristos 		       tok2str(isis_ptp_adjacency_values, "unknown", GET_U_1(tptr)),
3155c74ad251Schristos 		       GET_U_1(tptr));
3156c74ad251Schristos 		tlen--;
31570f74e101Schristos 	    }
3158c74ad251Schristos 	    if(tlen>sizeof(tlv_ptp_adj->extd_local_circuit_id)) {
3159c74ad251Schristos 		ND_PRINT("\n\t      Extended Local circuit-ID: 0x%08x",
3160c74ad251Schristos 		       GET_BE_U_4(tlv_ptp_adj->extd_local_circuit_id));
3161c74ad251Schristos 		tlen-=sizeof(tlv_ptp_adj->extd_local_circuit_id);
31620f74e101Schristos 	    }
3163c74ad251Schristos 	    if(tlen>=SYSTEM_ID_LEN) {
3164c74ad251Schristos 		ND_TCHECK_LEN(tlv_ptp_adj->neighbor_sysid, SYSTEM_ID_LEN);
3165c74ad251Schristos 		ND_PRINT("\n\t      Neighbor System-ID: %s",
3166c74ad251Schristos 		       isis_print_id(ndo, tlv_ptp_adj->neighbor_sysid, SYSTEM_ID_LEN));
3167c74ad251Schristos 		tlen-=SYSTEM_ID_LEN;
31680f74e101Schristos 	    }
3169c74ad251Schristos 	    if(tlen>=sizeof(tlv_ptp_adj->neighbor_extd_local_circuit_id)) {
3170c74ad251Schristos 		ND_PRINT("\n\t      Neighbor Extended Local circuit-ID: 0x%08x",
3171c74ad251Schristos 		       GET_BE_U_4(tlv_ptp_adj->neighbor_extd_local_circuit_id));
31720f74e101Schristos 	    }
31730f74e101Schristos 	    break;
31740f74e101Schristos 
31750f74e101Schristos 	case ISIS_TLV_PROTOCOLS:
3176c74ad251Schristos 	    ND_PRINT("\n\t      NLPID(s): ");
3177c74ad251Schristos 	    while (tlen != 0) {
3178c74ad251Schristos 		ND_PRINT("%s (0x%02x)",
31790f74e101Schristos                        tok2str(nlpid_values,
31800f74e101Schristos                                "unknown",
3181c74ad251Schristos                                GET_U_1(tptr)),
3182c74ad251Schristos                        GET_U_1(tptr));
3183c74ad251Schristos 		if (tlen>1) /* further NPLIDs ? - put comma */
3184c74ad251Schristos 		    ND_PRINT(", ");
31850f74e101Schristos                 tptr++;
3186c74ad251Schristos                 tlen--;
31870f74e101Schristos 	    }
31880f74e101Schristos 	    break;
31890f74e101Schristos 
3190870189d2Schristos         case ISIS_TLV_MT_PORT_CAP:
3191870189d2Schristos         {
3192c74ad251Schristos             if (tlen < 2)
3193c74ad251Schristos                 goto tlv_trunc;
3194870189d2Schristos 
3195c74ad251Schristos             ND_PRINT("\n\t       RES: %u, MTID(s): %u",
3196c74ad251Schristos                     (GET_BE_U_2(tptr) >> 12),
3197c74ad251Schristos                     (GET_BE_U_2(tptr) & 0x0fff));
3198870189d2Schristos 
3199c74ad251Schristos             tptr += 2;
3200c74ad251Schristos             tlen -= 2;
3201870189d2Schristos 
3202c74ad251Schristos             if (tlen)
3203c74ad251Schristos                 isis_print_mt_port_cap_subtlv(ndo, tptr, tlen);
3204870189d2Schristos 
3205870189d2Schristos             break;
3206870189d2Schristos         }
3207870189d2Schristos 
3208870189d2Schristos         case ISIS_TLV_MT_CAPABILITY:
3209c74ad251Schristos             if (tlen < 2)
3210c74ad251Schristos                 goto tlv_trunc;
3211870189d2Schristos 
3212c74ad251Schristos             ND_PRINT("\n\t      O: %u, RES: %u, MTID(s): %u",
3213c74ad251Schristos                       (GET_BE_U_2(tptr) >> 15) & 0x01,
3214c74ad251Schristos                       (GET_BE_U_2(tptr) >> 12) & 0x07,
3215c74ad251Schristos                       GET_BE_U_2(tptr) & 0x0fff);
3216870189d2Schristos 
3217c74ad251Schristos             tptr += 2;
3218c74ad251Schristos             tlen -= 2;
3219870189d2Schristos 
3220c74ad251Schristos             if (tlen)
3221c74ad251Schristos                 isis_print_mt_capability_subtlv(ndo, tptr, tlen);
3222870189d2Schristos 
3223870189d2Schristos             break;
3224870189d2Schristos 
32250f74e101Schristos 	case ISIS_TLV_TE_ROUTER_ID:
3226c74ad251Schristos 	    if (tlen < sizeof(nd_ipv4))
3227c74ad251Schristos 	        goto tlv_trunc;
3228c74ad251Schristos 	    ND_PRINT("\n\t      Traffic Engineering Router ID: %s", GET_IPADDR_STRING(pptr));
32290f74e101Schristos 	    break;
32300f74e101Schristos 
32310f74e101Schristos 	case ISIS_TLV_IPADDR:
3232c74ad251Schristos 	    while (tlen != 0) {
3233c74ad251Schristos                 if (tlen < sizeof(nd_ipv4))
3234c74ad251Schristos                     goto tlv_trunc;
3235c74ad251Schristos 		ND_PRINT("\n\t      IPv4 interface address: %s", GET_IPADDR_STRING(tptr));
3236c74ad251Schristos 		tptr += sizeof(nd_ipv4);
3237c74ad251Schristos 		tlen -= sizeof(nd_ipv4);
32380f74e101Schristos 	    }
32390f74e101Schristos 	    break;
32400f74e101Schristos 
32410f74e101Schristos 	case ISIS_TLV_HOSTNAME:
3242c74ad251Schristos 	    ND_PRINT("\n\t      Hostname: ");
3243c74ad251Schristos 	    nd_printjnp(ndo, tptr, tlen);
32440f74e101Schristos 	    break;
32450f74e101Schristos 
32460f74e101Schristos 	case ISIS_TLV_SHARED_RISK_GROUP:
3247c74ad251Schristos 	    if (tlen < NODE_ID_LEN)
32480f74e101Schristos 	        break;
3249c74ad251Schristos 	    ND_TCHECK_LEN(tptr, NODE_ID_LEN);
3250c74ad251Schristos 	    ND_PRINT("\n\t      IS Neighbor: %s", isis_print_id(ndo, tptr, NODE_ID_LEN));
3251c74ad251Schristos 	    tptr+=NODE_ID_LEN;
3252c74ad251Schristos 	    tlen-=NODE_ID_LEN;
32530f74e101Schristos 
3254c74ad251Schristos 	    if (tlen < 1)
32550f74e101Schristos 	        break;
3256c74ad251Schristos 	    ND_PRINT(", Flags: [%s]",
3257c74ad251Schristos                      ISIS_MASK_TLV_SHARED_RISK_GROUP(GET_U_1(tptr)) ? "numbered" : "unnumbered");
3258c74ad251Schristos 	    tptr++;
3259c74ad251Schristos 	    tlen--;
32600f74e101Schristos 
3261c74ad251Schristos 	    if (tlen < sizeof(nd_ipv4))
32620f74e101Schristos 	        break;
3263c74ad251Schristos 	    ND_PRINT("\n\t      IPv4 interface address: %s", GET_IPADDR_STRING(tptr));
3264c74ad251Schristos 	    tptr+=sizeof(nd_ipv4);
3265c74ad251Schristos 	    tlen-=sizeof(nd_ipv4);
32660f74e101Schristos 
3267c74ad251Schristos 	    if (tlen < sizeof(nd_ipv4))
32680f74e101Schristos 	        break;
3269c74ad251Schristos 	    ND_PRINT("\n\t      IPv4 neighbor address: %s", GET_IPADDR_STRING(tptr));
3270c74ad251Schristos 	    tptr+=sizeof(nd_ipv4);
3271c74ad251Schristos 	    tlen-=sizeof(nd_ipv4);
32720f74e101Schristos 
3273c74ad251Schristos 	    while (tlen != 0) {
3274c74ad251Schristos 		if (tlen < 4)
3275c74ad251Schristos 		    goto tlv_trunc;
3276c74ad251Schristos                 ND_PRINT("\n\t      Link-ID: 0x%08x", GET_BE_U_4(tptr));
32770f74e101Schristos                 tptr+=4;
3278c74ad251Schristos                 tlen-=4;
32790f74e101Schristos 	    }
32800f74e101Schristos 	    break;
32810f74e101Schristos 
32820f74e101Schristos 	case ISIS_TLV_LSP:
32830f74e101Schristos 	    tlv_lsp = (const struct isis_tlv_lsp *)tptr;
3284c74ad251Schristos 	    while (tlen != 0) {
3285c74ad251Schristos 		if (tlen < sizeof(struct isis_tlv_lsp))
3286c74ad251Schristos 		    goto tlv_trunc;
3287c74ad251Schristos 		ND_TCHECK_1(tlv_lsp->lsp_id + LSP_ID_LEN - 1);
3288c74ad251Schristos 		ND_PRINT("\n\t      lsp-id: %s",
3289c74ad251Schristos                        isis_print_id(ndo, tlv_lsp->lsp_id, LSP_ID_LEN));
3290c74ad251Schristos 		ND_PRINT(", seq: 0x%08x",
3291c74ad251Schristos                          GET_BE_U_4(tlv_lsp->sequence_number));
3292c74ad251Schristos 		ND_PRINT(", lifetime: %5ds",
3293c74ad251Schristos                          GET_BE_U_2(tlv_lsp->remaining_lifetime));
3294c74ad251Schristos 		ND_PRINT(", chksum: 0x%04x", GET_BE_U_2(tlv_lsp->checksum));
3295c74ad251Schristos 		tlen-=sizeof(struct isis_tlv_lsp);
32960f74e101Schristos 		tlv_lsp++;
32970f74e101Schristos 	    }
32980f74e101Schristos 	    break;
32990f74e101Schristos 
33000f74e101Schristos 	case ISIS_TLV_CHECKSUM:
3301c74ad251Schristos 	    if (tlen < ISIS_TLV_CHECKSUM_MINLEN)
33020f74e101Schristos 	        break;
3303c74ad251Schristos 	    ND_TCHECK_LEN(tptr, ISIS_TLV_CHECKSUM_MINLEN);
3304c74ad251Schristos 	    ND_PRINT("\n\t      checksum: 0x%04x ", GET_BE_U_2(tptr));
33050f74e101Schristos             /* do not attempt to verify the checksum if it is zero
33060f74e101Schristos              * most likely a HMAC-MD5 TLV is also present and
33070f74e101Schristos              * to avoid conflicts the checksum TLV is zeroed.
33080f74e101Schristos              * see rfc3358 for details
33090f74e101Schristos              */
3310c74ad251Schristos             osi_print_cksum(ndo, optr, GET_BE_U_2(tptr), (int)(tptr-optr),
331172c96ff3Schristos                             length);
3312fdccd7e4Schristos 	    break;
3313fdccd7e4Schristos 
3314fdccd7e4Schristos 	case ISIS_TLV_POI:
3315c74ad251Schristos 	    if (tlen < 1)
3316c74ad251Schristos 	        goto tlv_trunc;
3317c74ad251Schristos 	    num_system_ids = GET_U_1(tptr);
3318c74ad251Schristos 	    tptr++;
3319c74ad251Schristos 	    tlen--;
3320c74ad251Schristos 	    if (num_system_ids == 0) {
3321c74ad251Schristos 		/* Not valid */
3322c74ad251Schristos 		ND_PRINT(" No system IDs supplied");
3323c74ad251Schristos 	    } else {
3324c74ad251Schristos 		if (tlen < SYSTEM_ID_LEN)
3325c74ad251Schristos 		    goto tlv_trunc;
3326c74ad251Schristos 		ND_TCHECK_LEN(tptr, SYSTEM_ID_LEN);
3327c74ad251Schristos 		ND_PRINT("\n\t      Purge Originator System-ID: %s",
3328c74ad251Schristos 		       isis_print_id(ndo, tptr, SYSTEM_ID_LEN));
3329c74ad251Schristos 		tptr += SYSTEM_ID_LEN;
3330c74ad251Schristos 		tlen -= SYSTEM_ID_LEN;
3331fdccd7e4Schristos 
3332c74ad251Schristos 		if (num_system_ids > 1) {
3333c74ad251Schristos 		    if (tlen < SYSTEM_ID_LEN)
3334c74ad251Schristos 			goto tlv_trunc;
3335c74ad251Schristos 		    ND_TCHECK_LEN(tptr, SYSTEM_ID_LEN);
3336c74ad251Schristos 		    ND_TCHECK_LEN(tptr, 2 * SYSTEM_ID_LEN + 1);
3337c74ad251Schristos 		    ND_PRINT("\n\t      Received from System-ID: %s",
3338c74ad251Schristos 			   isis_print_id(ndo, tptr, SYSTEM_ID_LEN));
3339c74ad251Schristos 		}
3340fdccd7e4Schristos 	    }
33410f74e101Schristos 	    break;
33420f74e101Schristos 
33430f74e101Schristos 	case ISIS_TLV_MT_SUPPORTED:
3344c74ad251Schristos 	    while (tlen != 0) {
33450f74e101Schristos 		/* length can only be a multiple of 2, otherwise there is
33460f74e101Schristos 		   something broken -> so decode down until length is 1 */
3347c74ad251Schristos 		if (tlen!=1) {
3348c74ad251Schristos                     mt_len = isis_print_mtid(ndo, tptr, "\n\t      ", tlen);
33490f74e101Schristos                     if (mt_len == 0) /* did something go wrong ? */
3350c74ad251Schristos                         goto trunc;
33510f74e101Schristos                     tptr+=mt_len;
3352c74ad251Schristos                     tlen-=mt_len;
33530f74e101Schristos 		} else {
3354c74ad251Schristos 		    ND_PRINT("\n\t      invalid MT-ID");
33550f74e101Schristos 		    break;
33560f74e101Schristos 		}
33570f74e101Schristos 	    }
33580f74e101Schristos 	    break;
33590f74e101Schristos 
33600f74e101Schristos 	case ISIS_TLV_RESTART_SIGNALING:
33610f74e101Schristos             /* first attempt to decode the flags */
3362c74ad251Schristos             if (tlen < ISIS_TLV_RESTART_SIGNALING_FLAGLEN)
33630f74e101Schristos                 break;
3364c74ad251Schristos             ND_TCHECK_LEN(tptr, ISIS_TLV_RESTART_SIGNALING_FLAGLEN);
3365c74ad251Schristos             ND_PRINT("\n\t      Flags [%s]",
3366c74ad251Schristos                    bittok2str(isis_restart_flag_values, "none", GET_U_1(tptr)));
33670f74e101Schristos             tptr+=ISIS_TLV_RESTART_SIGNALING_FLAGLEN;
3368c74ad251Schristos             tlen-=ISIS_TLV_RESTART_SIGNALING_FLAGLEN;
33690f74e101Schristos 
33700f74e101Schristos             /* is there anything other than the flags field? */
3371c74ad251Schristos             if (tlen == 0)
33720f74e101Schristos                 break;
33730f74e101Schristos 
3374c74ad251Schristos             if (tlen < ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN)
33750f74e101Schristos                 break;
3376c74ad251Schristos             ND_TCHECK_LEN(tptr, ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN);
33770f74e101Schristos 
3378c74ad251Schristos             ND_PRINT(", Remaining holding time %us", GET_BE_U_2(tptr));
33790f74e101Schristos             tptr+=ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN;
3380c74ad251Schristos             tlen-=ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN;
33810f74e101Schristos 
33820f74e101Schristos             /* is there an additional sysid field present ?*/
3383c74ad251Schristos             if (tlen == SYSTEM_ID_LEN) {
3384c74ad251Schristos                     ND_TCHECK_LEN(tptr, SYSTEM_ID_LEN);
3385c74ad251Schristos                     ND_PRINT(", for %s", isis_print_id(ndo, tptr,SYSTEM_ID_LEN));
33860f74e101Schristos             }
33870f74e101Schristos 	    break;
33880f74e101Schristos 
33890f74e101Schristos         case ISIS_TLV_IDRP_INFO:
3390c74ad251Schristos 	    if (tlen < 1)
33910f74e101Schristos 	        break;
3392c74ad251Schristos             isis_subtlv_idrp = GET_U_1(tptr);
3393c74ad251Schristos             ND_PRINT("\n\t      Inter-Domain Information Type: %s",
33940f74e101Schristos                    tok2str(isis_subtlv_idrp_values,
33950f74e101Schristos                            "Unknown (0x%02x)",
3396c74ad251Schristos                            isis_subtlv_idrp));
3397c74ad251Schristos             tptr++;
3398c74ad251Schristos             tlen--;
3399c74ad251Schristos             switch (isis_subtlv_idrp) {
34000f74e101Schristos             case ISIS_SUBTLV_IDRP_ASN:
3401c74ad251Schristos                 if (tlen < 2)
3402c74ad251Schristos                     goto tlv_trunc;
3403c74ad251Schristos                 ND_PRINT("AS Number: %u", GET_BE_U_2(tptr));
34040f74e101Schristos                 break;
34050f74e101Schristos             case ISIS_SUBTLV_IDRP_LOCAL:
34060f74e101Schristos             case ISIS_SUBTLV_IDRP_RES:
34070f74e101Schristos             default:
3408c74ad251Schristos                 if (!print_unknown_data(ndo, tptr, "\n\t      ", tlen))
34090f74e101Schristos                     return(0);
34100f74e101Schristos                 break;
34110f74e101Schristos             }
34120f74e101Schristos             break;
34130f74e101Schristos 
34140f74e101Schristos         case ISIS_TLV_LSP_BUFFERSIZE:
3415c74ad251Schristos 	    if (tlen < 2)
34160f74e101Schristos 	        break;
3417c74ad251Schristos             ND_PRINT("\n\t      LSP Buffersize: %u", GET_BE_U_2(tptr));
34180f74e101Schristos             break;
34190f74e101Schristos 
34200f74e101Schristos         case ISIS_TLV_PART_DIS:
3421c74ad251Schristos             while (tlen != 0) {
3422c74ad251Schristos                 if (tlen < SYSTEM_ID_LEN)
3423c74ad251Schristos                     goto tlv_trunc;
3424c74ad251Schristos                 ND_TCHECK_LEN(tptr, SYSTEM_ID_LEN);
3425c74ad251Schristos                 ND_PRINT("\n\t      %s", isis_print_id(ndo, tptr, SYSTEM_ID_LEN));
34260f74e101Schristos                 tptr+=SYSTEM_ID_LEN;
3427c74ad251Schristos                 tlen-=SYSTEM_ID_LEN;
34280f74e101Schristos             }
34290f74e101Schristos             break;
34300f74e101Schristos 
34310f74e101Schristos         case ISIS_TLV_PREFIX_NEIGH:
3432c74ad251Schristos 	    if (tlen < sizeof(struct isis_metric_block))
34330f74e101Schristos 	        break;
3434c74ad251Schristos             ND_TCHECK_LEN(tptr, sizeof(struct isis_metric_block));
3435c74ad251Schristos             ND_PRINT("\n\t      Metric Block");
3436b3a00663Schristos             isis_print_metric_block(ndo, (const struct isis_metric_block *)tptr);
34370f74e101Schristos             tptr+=sizeof(struct isis_metric_block);
3438c74ad251Schristos             tlen-=sizeof(struct isis_metric_block);
34390f74e101Schristos 
3440c74ad251Schristos             while (tlen != 0) {
3441c74ad251Schristos                 prefix_len=GET_U_1(tptr); /* read out prefix length in semioctets*/
3442c74ad251Schristos                 tptr++;
3443c74ad251Schristos                 tlen--;
34440f74e101Schristos                 if (prefix_len < 2) {
3445c74ad251Schristos                     ND_PRINT("\n\t\tAddress: prefix length %u < 2", prefix_len);
34460f74e101Schristos                     break;
34470f74e101Schristos                 }
3448c74ad251Schristos                 if (tlen < prefix_len/2)
34490f74e101Schristos                     break;
3450c74ad251Schristos                 ND_PRINT("\n\t\tAddress: %s/%u",
3451c74ad251Schristos                        GET_ISONSAP_STRING(tptr, prefix_len / 2), prefix_len * 4);
34520f74e101Schristos                 tptr+=prefix_len/2;
3453c74ad251Schristos                 tlen-=prefix_len/2;
34540f74e101Schristos             }
34550f74e101Schristos             break;
34560f74e101Schristos 
34570f74e101Schristos         case ISIS_TLV_IIH_SEQNR:
3458c74ad251Schristos 	    if (tlen < 4)
34590f74e101Schristos 	        break;
3460c74ad251Schristos             ND_PRINT("\n\t      Sequence number: %u", GET_BE_U_4(tptr));
3461c74ad251Schristos             break;
3462c74ad251Schristos 
3463c74ad251Schristos         case ISIS_TLV_ROUTER_CAPABILITY:
3464c74ad251Schristos             if (tlen < 5) {
3465c74ad251Schristos                 ND_PRINT(" [object length %u < 5]", tlen);
3466c74ad251Schristos                 nd_print_invalid(ndo);
3467c74ad251Schristos                 break;
3468c74ad251Schristos             }
3469c74ad251Schristos             ND_PRINT("\n\t      Router-ID %s", GET_IPADDR_STRING(tptr));
3470c74ad251Schristos             ND_PRINT(", Flags [%s]",
3471c74ad251Schristos 		     bittok2str(isis_tlv_router_capability_flags, "none", GET_U_1(tptr+4)));
3472c74ad251Schristos 
3473c74ad251Schristos 	    /* Optional set of sub-TLV */
3474c74ad251Schristos 	    if (tlen > 5) {
3475c74ad251Schristos 		isis_print_router_cap_subtlv(ndo, tptr+5, tlen-5);
3476c74ad251Schristos 	    }
34770f74e101Schristos             break;
34780f74e101Schristos 
34790f74e101Schristos         case ISIS_TLV_VENDOR_PRIVATE:
3480c74ad251Schristos 	    if (tlen < 3)
34810f74e101Schristos 	        break;
3482c74ad251Schristos             vendor_id = GET_BE_U_3(tptr);
3483c74ad251Schristos             ND_PRINT("\n\t      Vendor: %s (%u)",
34840f74e101Schristos                    tok2str(oui_values, "Unknown", vendor_id),
3485c74ad251Schristos                    vendor_id);
34860f74e101Schristos             tptr+=3;
3487c74ad251Schristos             tlen-=3;
3488c74ad251Schristos             if (tlen != 0) /* hexdump the rest */
3489c74ad251Schristos                 if (!print_unknown_data(ndo, tptr, "\n\t\t", tlen))
34900f74e101Schristos                     return(0);
34910f74e101Schristos             break;
34920f74e101Schristos             /*
34930f74e101Schristos              * FIXME those are the defined TLVs that lack a decoder
34940f74e101Schristos              * you are welcome to contribute code ;-)
34950f74e101Schristos              */
34960f74e101Schristos 
34970f74e101Schristos         case ISIS_TLV_DECNET_PHASE4:
34980f74e101Schristos         case ISIS_TLV_LUCENT_PRIVATE:
34990f74e101Schristos         case ISIS_TLV_IPAUTH:
35000f74e101Schristos         case ISIS_TLV_NORTEL_PRIVATE1:
35010f74e101Schristos         case ISIS_TLV_NORTEL_PRIVATE2:
35020f74e101Schristos 
35030f74e101Schristos 	default:
3504b3a00663Schristos 		if (ndo->ndo_vflag <= 1) {
3505b3a00663Schristos 			if (!print_unknown_data(ndo, pptr, "\n\t\t", tlv_len))
35060f74e101Schristos 				return(0);
35070f74e101Schristos 		}
35080f74e101Schristos 		break;
35090f74e101Schristos 	}
3510c74ad251Schristos tlv_trunc:
35110f74e101Schristos         /* do we want to see an additionally hexdump ? */
3512b3a00663Schristos 	if (ndo->ndo_vflag> 1) {
3513b3a00663Schristos 		if (!print_unknown_data(ndo, pptr, "\n\t      ", tlv_len))
35140f74e101Schristos 			return(0);
35150f74e101Schristos 	}
35160f74e101Schristos 
35170f74e101Schristos 	pptr += tlv_len;
35180f74e101Schristos 	packet_len -= tlv_len;
35190f74e101Schristos     }
35200f74e101Schristos 
35210f74e101Schristos     if (packet_len != 0) {
3522c74ad251Schristos 	ND_PRINT("\n\t      %u straggler bytes", packet_len);
35230f74e101Schristos     }
35240f74e101Schristos     return (1);
35250f74e101Schristos 
35260f74e101Schristos trunc:
3527c74ad251Schristos     nd_print_trunc(ndo);
35280f74e101Schristos     return (1);
35290f74e101Schristos }
35300f74e101Schristos 
353172c96ff3Schristos static void
3532fdccd7e4Schristos osi_print_cksum(netdissect_options *ndo, const uint8_t *pptr,
353372c96ff3Schristos 	        uint16_t checksum, int checksum_offset, u_int length)
35340f74e101Schristos {
3535b3a00663Schristos         uint16_t calculated_checksum;
35360f74e101Schristos 
3537ba2ff121Schristos         /* do not attempt to verify the checksum if it is zero,
3538ba2ff121Schristos          * if the offset is nonsense,
3539ba2ff121Schristos          * or the base pointer is not sane
3540ba2ff121Schristos          */
3541ba2ff121Schristos         if (!checksum
3542fdccd7e4Schristos             || checksum_offset < 0
3543c74ad251Schristos             || !ND_TTEST_2(pptr + checksum_offset)
354472c96ff3Schristos             || (u_int)checksum_offset > length
3545c74ad251Schristos             || !ND_TTEST_LEN(pptr, length)) {
3546c74ad251Schristos                 ND_PRINT(" (unverified)");
35470f74e101Schristos         } else {
3548fdccd7e4Schristos #if 0
3549c74ad251Schristos                 ND_PRINT("\nosi_print_cksum: %p %d %u\n", pptr, checksum_offset, length);
3550fdccd7e4Schristos #endif
35510f74e101Schristos                 calculated_checksum = create_osi_cksum(pptr, checksum_offset, length);
35520f74e101Schristos                 if (checksum == calculated_checksum) {
3553c74ad251Schristos                         ND_PRINT(" (correct)");
35540f74e101Schristos                 } else {
3555c74ad251Schristos                         ND_PRINT(" (incorrect should be 0x%04x)", calculated_checksum);
35560f74e101Schristos                 }
35570f74e101Schristos         }
35580f74e101Schristos }
3559