138032Speter/*
290792Sgshapiro * Copyright (c) 1992, 1993, 1994, 1995, 1996
364562Sgshapiro *	The Regents of the University of California.  All rights reserved.
438032Speter *
538032Speter * Redistribution and use in source and binary forms, with or without
638032Speter * modification, are permitted provided that: (1) source code distributions
738032Speter * retain the above copyright notice and this paragraph in its entirety, (2)
838032Speter * distributions including binary code include the above copyright notice and
938032Speter * this paragraph in its entirety in the documentation or other materials
1038032Speter * provided with the distribution, and (3) all advertising materials mentioning
1138032Speter * features or use of this software display the following acknowledgement:
1238032Speter * ``This product includes software developed by the University of California,
1338032Speter * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1464562Sgshapiro * the University nor the names of its contributors may be used to endorse
1590792Sgshapiro * or promote products derived from this software without specific prior
1638032Speter * written permission.
17110560Sgshapiro * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1864562Sgshapiro * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1938032Speter * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2038032Speter *
2164562Sgshapiro * Original code by Matt Thomas, Digital Equipment Corporation
2238032Speter *
2394334Sgshapiro * Extensively modified by Hannes Gredler (hannes@gredler.at) for more
2494334Sgshapiro * complete IS-IS & CLNP support.
2594334Sgshapiro */
2694334Sgshapiro
2790792Sgshapiro/* \summary: ISO CLNS, ESIS, and ISIS printer */
2864562Sgshapiro
2990792Sgshapiro/*
3064562Sgshapiro * specification:
3190792Sgshapiro *
3264562Sgshapiro * CLNP: ISO 8473 (respective ITU version is at https://www.itu.int/rec/T-REC-X.233/en/)
3364562Sgshapiro * ES-IS: ISO 9542
3464562Sgshapiro * IS-IS: ISO 10589
3564562Sgshapiro */
3664562Sgshapiro
3790792Sgshapiro#ifdef HAVE_CONFIG_H
3890792Sgshapiro#include <config.h>
3964562Sgshapiro#endif
4090792Sgshapiro
4164562Sgshapiro#include "netdissect-stdinc.h"
4290792Sgshapiro
4390792Sgshapiro#include <string.h>
4490792Sgshapiro
4590792Sgshapiro#include "netdissect.h"
4690792Sgshapiro#include "addrtoname.h"
4738032Speter#include "nlpid.h"
4838032Speter#include "extract.h"
4938032Speter#include "gmpls.h"
5038032Speter#include "oui.h"
5138032Speter#include "signature.h"
5238032Speter
5338032Speter
5438032Speter/*
5538032Speter * IS-IS is defined in ISO 10589.  Look there for protocol definitions.
5638032Speter */
5738032Speter
5838032Speter#define SYSTEM_ID_LEN	MAC_ADDR_LEN
5938032Speter#define NODE_ID_LEN     (SYSTEM_ID_LEN+1)
6038032Speter#define LSP_ID_LEN      (SYSTEM_ID_LEN+2)
6138032Speter
6238032Speter#define ISIS_VERSION	1
6338032Speter#define ESIS_VERSION	1
6438032Speter#define CLNP_VERSION	1
6538032Speter
6638032Speter#define ISIS_PDU_TYPE_MASK      0x1F
6738032Speter#define ESIS_PDU_TYPE_MASK      0x1F
6838032Speter#define CLNP_PDU_TYPE_MASK      0x1F
6938032Speter#define CLNP_FLAG_MASK          0xE0
7038032Speter#define ISIS_LAN_PRIORITY_MASK  0x7F
7138032Speter
7238032Speter#define ISIS_PDU_L1_LAN_IIH	15
7338032Speter#define ISIS_PDU_L2_LAN_IIH	16
7464562Sgshapiro#define ISIS_PDU_PTP_IIH	17
7538032Speter#define ISIS_PDU_L1_LSP		18
7638032Speter#define ISIS_PDU_L2_LSP		20
7738032Speter#define ISIS_PDU_L1_CSNP	24
7890792Sgshapiro#define ISIS_PDU_L2_CSNP	25
7938032Speter#define ISIS_PDU_L1_PSNP        26
8038032Speter#define ISIS_PDU_L2_PSNP        27
8138032Speter
8238032Speterstatic const struct tok isis_pdu_values[] = {
8338032Speter    { ISIS_PDU_L1_LAN_IIH,       "L1 Lan IIH"},
8438032Speter    { ISIS_PDU_L2_LAN_IIH,       "L2 Lan IIH"},
8538032Speter    { ISIS_PDU_PTP_IIH,          "p2p IIH"},
8638032Speter    { ISIS_PDU_L1_LSP,           "L1 LSP"},
8738032Speter    { ISIS_PDU_L2_LSP,           "L2 LSP"},
8838032Speter    { ISIS_PDU_L1_CSNP,          "L1 CSNP"},
8990792Sgshapiro    { ISIS_PDU_L2_CSNP,          "L2 CSNP"},
9038032Speter    { ISIS_PDU_L1_PSNP,          "L1 PSNP"},
9190792Sgshapiro    { ISIS_PDU_L2_PSNP,          "L2 PSNP"},
9290792Sgshapiro    { 0, NULL}
9390792Sgshapiro};
9438032Speter
9590792Sgshapiro/*
9638032Speter * A TLV is a tuple of a type, length and a value and is normally used for
9738032Speter * encoding information in all sorts of places.  This is an enumeration of
9838032Speter * the well known types.
9938032Speter *
10038032Speter * list taken from rfc3359 plus some memory from veterans ;-)
10138032Speter */
10238032Speter
10338032Speter#define ISIS_TLV_AREA_ADDR           1   /* iso10589 */
10438032Speter#define ISIS_TLV_IS_REACH            2   /* iso10589 */
10538032Speter#define ISIS_TLV_ESNEIGH             3   /* iso10589 */
10638032Speter#define ISIS_TLV_PART_DIS            4   /* iso10589 */
10738032Speter#define ISIS_TLV_PREFIX_NEIGH        5   /* iso10589 */
10838032Speter#define ISIS_TLV_ISNEIGH             6   /* iso10589 */
10938032Speter#define ISIS_TLV_INSTANCE_ID         7   /* rfc8202 */
11038032Speter#define ISIS_TLV_PADDING             8   /* iso10589 */
11138032Speter#define ISIS_TLV_LSP                 9   /* iso10589 */
11238032Speter#define ISIS_TLV_AUTH                10  /* iso10589, rfc3567 */
11338032Speter#define ISIS_TLV_CHECKSUM            12  /* rfc3358 */
11438032Speter#define ISIS_TLV_CHECKSUM_MINLEN 2
11538032Speter#define ISIS_TLV_POI                 13  /* rfc6232 */
11638032Speter#define ISIS_TLV_LSP_BUFFERSIZE      14  /* iso10589 rev2 */
11738032Speter#define ISIS_TLV_EXT_IS_REACH        22  /* rfc5305 */
11838032Speter#define ISIS_TLV_IS_ALIAS_ID         24  /* rfc5311 */
11938032Speter#define ISIS_TLV_DECNET_PHASE4       42
12038032Speter#define ISIS_TLV_LUCENT_PRIVATE      66
12138032Speter#define ISIS_TLV_INT_IP_REACH        128 /* rfc1195, rfc2966 */
12238032Speter#define ISIS_TLV_PROTOCOLS           129 /* rfc1195 */
12338032Speter#define ISIS_TLV_EXT_IP_REACH        130 /* rfc1195, rfc2966 */
12490792Sgshapiro#define ISIS_TLV_IDRP_INFO           131 /* rfc1195 */
12538032Speter#define ISIS_TLV_IPADDR              132 /* rfc1195 */
12690792Sgshapiro#define ISIS_TLV_IPAUTH              133 /* rfc1195 */
12790792Sgshapiro#define ISIS_TLV_TE_ROUTER_ID        134 /* rfc5305 */
12838032Speter#define ISIS_TLV_EXTD_IP_REACH       135 /* rfc5305 */
12990792Sgshapiro#define ISIS_TLV_HOSTNAME            137 /* rfc2763 */
13090792Sgshapiro#define ISIS_TLV_SHARED_RISK_GROUP   138 /* draft-ietf-isis-gmpls-extensions */
13138032Speter#define ISIS_TLV_MT_PORT_CAP         143 /* rfc6165 */
13238032Speter#define ISIS_TLV_MT_CAPABILITY       144 /* rfc6329 */
13338032Speter#define ISIS_TLV_NORTEL_PRIVATE1     176
13438032Speter#define ISIS_TLV_NORTEL_PRIVATE2     177
13538032Speter#define ISIS_TLV_RESTART_SIGNALING   211 /* rfc3847 */
13638032Speter#define ISIS_TLV_RESTART_SIGNALING_FLAGLEN 1
13738032Speter#define ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN 2
13838032Speter#define ISIS_TLV_MT_IS_REACH         222 /* draft-ietf-isis-wg-multi-topology-05 */
13938032Speter#define ISIS_TLV_MT_SUPPORTED        229 /* draft-ietf-isis-wg-multi-topology-05 */
14038032Speter#define ISIS_TLV_IP6ADDR             232 /* draft-ietf-isis-ipv6-02 */
14138032Speter#define ISIS_TLV_MT_IP_REACH         235 /* draft-ietf-isis-wg-multi-topology-05 */
14238032Speter#define ISIS_TLV_IP6_REACH           236 /* draft-ietf-isis-ipv6-02 */
14338032Speter#define ISIS_TLV_MT_IP6_REACH        237 /* draft-ietf-isis-wg-multi-topology-05 */
14438032Speter#define ISIS_TLV_PTP_ADJ             240 /* rfc3373 */
14577349Sgshapiro#define ISIS_TLV_IIH_SEQNR           241 /* draft-shen-isis-iih-sequence-00 */
14677349Sgshapiro#define ISIS_TLV_ROUTER_CAPABILITY   242 /* rfc7981 */
14777349Sgshapiro#define ISIS_TLV_VENDOR_PRIVATE      250 /* draft-ietf-isis-experimental-tlv-01 */
14877349Sgshapiro#define ISIS_TLV_VENDOR_PRIVATE_MINLEN 3
14977349Sgshapiro
15077349Sgshapirostatic const struct tok isis_tlv_values[] = {
15177349Sgshapiro    { ISIS_TLV_AREA_ADDR,	   "Area address(es)"},
15277349Sgshapiro    { ISIS_TLV_IS_REACH,           "IS Reachability"},
15338032Speter    { ISIS_TLV_ESNEIGH,            "ES Neighbor(s)"},
15490792Sgshapiro    { ISIS_TLV_PART_DIS,           "Partition DIS"},
15538032Speter    { ISIS_TLV_PREFIX_NEIGH,       "Prefix Neighbors"},
15664562Sgshapiro    { ISIS_TLV_ISNEIGH,            "IS Neighbor(s)"},
15777349Sgshapiro    { ISIS_TLV_INSTANCE_ID,        "Instance Identifier"},
15877349Sgshapiro    { ISIS_TLV_PADDING,            "Padding"},
15977349Sgshapiro    { ISIS_TLV_LSP,                "LSP entries"},
16077349Sgshapiro    { ISIS_TLV_AUTH,               "Authentication"},
16164562Sgshapiro    { ISIS_TLV_CHECKSUM,           "Checksum"},
16264562Sgshapiro    { ISIS_TLV_POI,                "Purge Originator Identifier"},
16364562Sgshapiro    { ISIS_TLV_LSP_BUFFERSIZE,     "LSP Buffersize"},
16464562Sgshapiro    { ISIS_TLV_EXT_IS_REACH,       "Extended IS Reachability"},
16564562Sgshapiro    { ISIS_TLV_IS_ALIAS_ID,        "IS Alias ID"},
16664562Sgshapiro    { ISIS_TLV_DECNET_PHASE4,      "DECnet Phase IV"},
16777349Sgshapiro    { ISIS_TLV_LUCENT_PRIVATE,     "Lucent Proprietary"},
16864562Sgshapiro    { ISIS_TLV_INT_IP_REACH,       "IPv4 Internal Reachability"},
16938032Speter    { ISIS_TLV_PROTOCOLS,          "Protocols supported"},
17038032Speter    { ISIS_TLV_EXT_IP_REACH,       "IPv4 External Reachability"},
17138032Speter    { ISIS_TLV_IDRP_INFO,          "Inter-Domain Information Type"},
17238032Speter    { ISIS_TLV_IPADDR,             "IPv4 Interface address(es)"},
17338032Speter    { ISIS_TLV_IPAUTH,             "IPv4 authentication (deprecated)"},
17438032Speter    { ISIS_TLV_TE_ROUTER_ID,       "Traffic Engineering Router ID"},
17564562Sgshapiro    { ISIS_TLV_EXTD_IP_REACH,      "Extended IPv4 Reachability"},
17638032Speter    { ISIS_TLV_SHARED_RISK_GROUP,  "Shared Risk Link Group"},
17738032Speter    { ISIS_TLV_MT_PORT_CAP,        "Multi-Topology-Aware Port Capability"},
17838032Speter    { ISIS_TLV_MT_CAPABILITY,      "Multi-Topology Capability"},
17938032Speter    { ISIS_TLV_NORTEL_PRIVATE1,    "Nortel Proprietary"},
18038032Speter    { ISIS_TLV_NORTEL_PRIVATE2,    "Nortel Proprietary"},
18138032Speter    { ISIS_TLV_HOSTNAME,           "Hostname"},
18264562Sgshapiro    { ISIS_TLV_RESTART_SIGNALING,  "Restart Signaling"},
18338032Speter    { ISIS_TLV_MT_IS_REACH,        "Multi Topology IS Reachability"},
18438032Speter    { ISIS_TLV_MT_SUPPORTED,       "Multi Topology"},
18538032Speter    { ISIS_TLV_IP6ADDR,            "IPv6 Interface address(es)"},
18690792Sgshapiro    { ISIS_TLV_MT_IP_REACH,        "Multi-Topology IPv4 Reachability"},
18790792Sgshapiro    { ISIS_TLV_IP6_REACH,          "IPv6 reachability"},
18838032Speter    { ISIS_TLV_MT_IP6_REACH,       "Multi-Topology IP6 Reachability"},
18964562Sgshapiro    { ISIS_TLV_PTP_ADJ,            "Point-to-point Adjacency State"},
19038032Speter    { ISIS_TLV_IIH_SEQNR,          "Hello PDU Sequence Number"},
19138032Speter    { ISIS_TLV_ROUTER_CAPABILITY,  "IS-IS Router Capability"},
19238032Speter    { ISIS_TLV_VENDOR_PRIVATE,     "Vendor Private"},
19338032Speter    { 0, NULL }
19438032Speter};
19538032Speter
19638032Speter#define ESIS_OPTION_PROTOCOLS        129
19738032Speter#define ESIS_OPTION_QOS_MAINTENANCE  195 /* iso9542 */
19838032Speter#define ESIS_OPTION_SECURITY         197 /* iso9542 */
19938032Speter#define ESIS_OPTION_ES_CONF_TIME     198 /* iso9542 */
20038032Speter#define ESIS_OPTION_PRIORITY         205 /* iso9542 */
20138032Speter#define ESIS_OPTION_ADDRESS_MASK     225 /* iso9542 */
20238032Speter#define ESIS_OPTION_SNPA_MASK        226 /* iso9542 */
20338032Speter
20438032Speterstatic const struct tok esis_option_values[] = {
20538032Speter    { ESIS_OPTION_PROTOCOLS,       "Protocols supported"},
20638032Speter    { ESIS_OPTION_QOS_MAINTENANCE, "QoS Maintenance" },
20738032Speter    { ESIS_OPTION_SECURITY,        "Security" },
20838032Speter    { ESIS_OPTION_ES_CONF_TIME,    "ES Configuration Time" },
20938032Speter    { ESIS_OPTION_PRIORITY,        "Priority" },
21064562Sgshapiro    { ESIS_OPTION_ADDRESS_MASK,    "Addressk Mask" },
21138032Speter    { ESIS_OPTION_SNPA_MASK,       "SNPA Mask" },
21238032Speter    { 0, NULL }
21338032Speter};
21438032Speter
21538032Speter#define CLNP_OPTION_DISCARD_REASON   193
21638032Speter#define CLNP_OPTION_QOS_MAINTENANCE  195 /* iso8473 */
21790792Sgshapiro#define CLNP_OPTION_SECURITY         197 /* iso8473 */
21890792Sgshapiro#define CLNP_OPTION_SOURCE_ROUTING   200 /* iso8473 */
21938032Speter#define CLNP_OPTION_ROUTE_RECORDING  203 /* iso8473 */
22038032Speter#define CLNP_OPTION_PADDING          204 /* iso8473 */
22138032Speter#define CLNP_OPTION_PRIORITY         205 /* iso8473 */
22238032Speter
22338032Speterstatic const struct tok clnp_option_values[] = {
22438032Speter    { CLNP_OPTION_DISCARD_REASON,  "Discard Reason"},
22538032Speter    { CLNP_OPTION_PRIORITY,        "Priority"},
22690792Sgshapiro    { CLNP_OPTION_QOS_MAINTENANCE, "QoS Maintenance"},
22790792Sgshapiro    { CLNP_OPTION_SECURITY, "Security"},
22838032Speter    { CLNP_OPTION_SOURCE_ROUTING, "Source Routing"},
22938032Speter    { CLNP_OPTION_ROUTE_RECORDING, "Route Recording"},
23038032Speter    { CLNP_OPTION_PADDING, "Padding"},
23138032Speter    { 0, NULL }
23238032Speter};
23338032Speter
23438032Speterstatic const struct tok clnp_option_rfd_class_values[] = {
23590792Sgshapiro    { 0x0, "General"},
23690792Sgshapiro    { 0x8, "Address"},
23738032Speter    { 0x9, "Source Routeing"},
23864562Sgshapiro    { 0xa, "Lifetime"},
23938032Speter    { 0xb, "PDU Discarded"},
24038032Speter    { 0xc, "Reassembly"},
24190792Sgshapiro    { 0, NULL }
24238032Speter};
24338032Speter
24438032Speterstatic const struct tok clnp_option_rfd_general_values[] = {
24538032Speter    { 0x0, "Reason not specified"},
24690792Sgshapiro    { 0x1, "Protocol procedure error"},
24790792Sgshapiro    { 0x2, "Incorrect checksum"},
24838032Speter    { 0x3, "PDU discarded due to congestion"},
24938032Speter    { 0x4, "Header syntax error (cannot be parsed)"},
25038032Speter    { 0x5, "Segmentation needed but not permitted"},
25138032Speter    { 0x6, "Incomplete PDU received"},
25238032Speter    { 0x7, "Duplicate option"},
25338032Speter    { 0, NULL }
25438032Speter};
25590792Sgshapiro
25690792Sgshapirostatic const struct tok clnp_option_rfd_address_values[] = {
25738032Speter    { 0x0, "Destination address unreachable"},
25838032Speter    { 0x1, "Destination address unknown"},
25938032Speter    { 0, NULL }
26038032Speter};
26138032Speter
26238032Speterstatic const struct tok clnp_option_rfd_source_routeing_values[] = {
26338032Speter    { 0x0, "Unspecified source routeing error"},
26490792Sgshapiro    { 0x1, "Syntax error in source routeing field"},
26590792Sgshapiro    { 0x2, "Unknown address in source routeing field"},
26638032Speter    { 0x3, "Path not acceptable"},
26738032Speter    { 0, NULL }
26838032Speter};
26938032Speter
27038032Speterstatic const struct tok clnp_option_rfd_lifetime_values[] = {
27138032Speter    { 0x0, "Lifetime expired while data unit in transit"},
27238032Speter    { 0x1, "Lifetime expired during reassembly"},
27390792Sgshapiro    { 0, NULL }
27490792Sgshapiro};
27538032Speter
27638032Speterstatic const struct tok clnp_option_rfd_pdu_discard_values[] = {
27738032Speter    { 0x0, "Unsupported option not specified"},
27838032Speter    { 0x1, "Unsupported protocol version"},
27938032Speter    { 0x2, "Unsupported security option"},
28090792Sgshapiro    { 0x3, "Unsupported source routeing option"},
28190792Sgshapiro    { 0x4, "Unsupported recording of route option"},
28238032Speter    { 0, NULL }
28338032Speter};
28438032Speter
28538032Speterstatic const struct tok clnp_option_rfd_reassembly_values[] = {
28690792Sgshapiro    { 0x0, "Reassembly interference"},
28738032Speter    { 0, NULL }
28838032Speter};
28938032Speter
29064562Sgshapiro/* array of 16 error-classes */
29164562Sgshapirostatic const struct tok *clnp_option_rfd_error_class[] = {
29264562Sgshapiro    clnp_option_rfd_general_values,
29390792Sgshapiro    NULL,
29464562Sgshapiro    NULL,
29564562Sgshapiro    NULL,
29664562Sgshapiro    NULL,
29764562Sgshapiro    NULL,
29864562Sgshapiro    NULL,
29964562Sgshapiro    NULL,
30064562Sgshapiro    clnp_option_rfd_address_values,
30164562Sgshapiro    clnp_option_rfd_source_routeing_values,
30264562Sgshapiro    clnp_option_rfd_lifetime_values,
30364562Sgshapiro    clnp_option_rfd_pdu_discard_values,
30464562Sgshapiro    clnp_option_rfd_reassembly_values,
30564562Sgshapiro    NULL,
30664562Sgshapiro    NULL,
30764562Sgshapiro    NULL
30864562Sgshapiro};
30964562Sgshapiro
31090792Sgshapiro#define CLNP_OPTION_OPTION_QOS_MASK 0x3f
31190792Sgshapiro#define CLNP_OPTION_SCOPE_MASK      0xc0
31264562Sgshapiro#define CLNP_OPTION_SCOPE_SA_SPEC   0x40
31390792Sgshapiro#define CLNP_OPTION_SCOPE_DA_SPEC   0x80
31464562Sgshapiro#define CLNP_OPTION_SCOPE_GLOBAL    0xc0
31564562Sgshapiro
31664562Sgshapirostatic const struct tok clnp_option_scope_values[] = {
31764562Sgshapiro    { CLNP_OPTION_SCOPE_SA_SPEC, "Source Address Specific"},
31864562Sgshapiro    { CLNP_OPTION_SCOPE_DA_SPEC, "Destination Address Specific"},
31990792Sgshapiro    { CLNP_OPTION_SCOPE_GLOBAL, "Globally unique"},
32064562Sgshapiro    { 0, NULL }
32190792Sgshapiro};
32290792Sgshapiro
32390792Sgshapirostatic const struct tok clnp_option_sr_rr_values[] = {
32464562Sgshapiro    { 0x0, "partial"},
32564562Sgshapiro    { 0x1, "complete"},
32664562Sgshapiro    { 0, NULL }
32764562Sgshapiro};
32864562Sgshapiro
32964562Sgshapirostatic const struct tok clnp_option_sr_rr_string_values[] = {
33090792Sgshapiro    { CLNP_OPTION_SOURCE_ROUTING, "source routing"},
33164562Sgshapiro    { CLNP_OPTION_ROUTE_RECORDING, "recording of route in progress"},
33264562Sgshapiro    { 0, NULL }
33364562Sgshapiro};
33464562Sgshapiro
33538032Speterstatic const struct tok clnp_option_qos_global_values[] = {
33638032Speter    { 0x20, "reserved"},
33738032Speter    { 0x10, "sequencing vs. delay"},
33838032Speter    { 0x08, "congested"},
33938032Speter    { 0x04, "delay vs. cost"},
34038032Speter    { 0x02, "error vs. delay"},
34138032Speter    { 0x01, "error vs. cost"},
34238032Speter    { 0, NULL }
34338032Speter};
34464562Sgshapiro
34564562Sgshapirostatic const struct tok isis_tlv_router_capability_flags[] = {
34638032Speter    { 0x01, "S bit"},
34738032Speter    { 0x02, "D bit"},
34890792Sgshapiro    { 0, NULL }
34964562Sgshapiro};
35090792Sgshapiro
35138032Speter#define ISIS_SUBTLV_ROUTER_CAP_SR 2 /* rfc 8667 */
35264562Sgshapiro
35364562Sgshapirostatic const struct tok isis_router_capability_subtlv_values[] = {
35464562Sgshapiro    { ISIS_SUBTLV_ROUTER_CAP_SR, "SR-Capabilities"},
35564562Sgshapiro    { 0, NULL }
35638032Speter};
35738032Speter
35890792Sgshapirostatic const struct tok isis_router_capability_sr_flags[] = {
35964562Sgshapiro    { 0x80, "ipv4"},
36090792Sgshapiro    { 0x40, "ipv6"},
36138032Speter    { 0, NULL }
36290792Sgshapiro};
36390792Sgshapiro
36490792Sgshapiro#define ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP           3 /* rfc5305 */
36590792Sgshapiro#define ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID  4 /* rfc4205 */
36690792Sgshapiro#define ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID        5 /* rfc5305 */
36790792Sgshapiro#define ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR        6 /* rfc5305 */
36890792Sgshapiro#define ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR    8 /* rfc5305 */
36990792Sgshapiro#define ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW           9 /* rfc5305 */
37090792Sgshapiro#define ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW        10 /* rfc5305 */
37190792Sgshapiro#define ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW        11 /* rfc4124 */
37290792Sgshapiro#define ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS_OLD   12 /* draft-ietf-tewg-diff-te-proto-06 */
37338032Speter#define ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC            18 /* rfc5305 */
37438032Speter#define ISIS_SUBTLV_EXT_IS_REACH_LINK_ATTRIBUTE       19 /* draft-ietf-isis-link-attr-01 */
37538032Speter#define ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE 20 /* rfc4205 */
37690792Sgshapiro#define ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR    21 /* rfc4205 */
37790792Sgshapiro#define ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS       22 /* rfc4124 */
37838032Speter#define ISIS_SUBTLV_EXT_IS_REACH_LAN_ADJ_SEGMENT_ID   32 /* rfc8667 */
37938032Speter
38038032Speter#define ISIS_SUBTLV_SPB_METRIC                        29 /* rfc6329 */
38138032Speter
38238032Speterstatic const struct tok isis_ext_is_reach_subtlv_values[] = {
38338032Speter    { ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP,            "Administrative groups" },
38438032Speter    { ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID,   "Link Local/Remote Identifier" },
38538032Speter    { ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID,         "Link Remote Identifier" },
38638032Speter    { ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR,         "IPv4 interface address" },
38790792Sgshapiro    { ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR,     "IPv4 neighbor address" },
38890792Sgshapiro    { ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW,            "Maximum link bandwidth" },
38990792Sgshapiro    { ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW,          "Reservable link bandwidth" },
39064562Sgshapiro    { ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW,          "Unreserved bandwidth" },
39138032Speter    { ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC,              "Traffic Engineering Metric" },
39264562Sgshapiro    { ISIS_SUBTLV_EXT_IS_REACH_LINK_ATTRIBUTE,         "Link Attribute" },
39338032Speter    { ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE,   "Link Protection Type" },
39438032Speter    { ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR,      "Interface Switching Capability" },
39590792Sgshapiro    { ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS_OLD,     "Bandwidth Constraints (old)" },
39690792Sgshapiro    { ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS,         "Bandwidth Constraints" },
39790792Sgshapiro    { ISIS_SUBTLV_EXT_IS_REACH_LAN_ADJ_SEGMENT_ID,     "LAN Adjacency Segment Identifier" },
39838032Speter    { ISIS_SUBTLV_SPB_METRIC,                          "SPB Metric" },
39990792Sgshapiro    { 250,                                             "Reserved for cisco specific extensions" },
40090792Sgshapiro    { 251,                                             "Reserved for cisco specific extensions" },
40190792Sgshapiro    { 252,                                             "Reserved for cisco specific extensions" },
40290792Sgshapiro    { 253,                                             "Reserved for cisco specific extensions" },
40390792Sgshapiro    { 254,                                             "Reserved for cisco specific extensions" },
40438032Speter    { 255,                                             "Reserved for future expansion" },
40538032Speter    { 0, NULL }
40690792Sgshapiro};
40738032Speter
40838032Speter#define ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32          1 /* draft-ietf-isis-admin-tags-01 */
40990792Sgshapiro#define ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64          2 /* draft-ietf-isis-admin-tags-01 */
41090792Sgshapiro#define ISIS_SUBTLV_EXTD_IP_REACH_PREFIX_SID           3 /* rfc8667 */
41138032Speter#define ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR  117 /* draft-ietf-isis-wg-multi-topology-05 */
41264562Sgshapiro
41338032Speterstatic const struct tok isis_ext_ip_reach_subtlv_values[] = {
41464562Sgshapiro    { ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32,           "32-Bit Administrative tag" },
41538032Speter    { ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64,           "64-Bit Administrative tag" },
41690792Sgshapiro    { ISIS_SUBTLV_EXTD_IP_REACH_PREFIX_SID,            "Prefix SID" },
41790792Sgshapiro    { ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR,     "Management Prefix Color" },
41838032Speter    { 0, NULL }
41938032Speter};
42064562Sgshapiro
42190792Sgshapiro#define ISIS_PREFIX_SID_FLAG_R 0x80 /* rfc 8667 */
42290792Sgshapiro#define ISIS_PREFIX_SID_FLAG_N 0x40 /* rfc 8667 */
42390792Sgshapiro#define ISIS_PREFIX_SID_FLAG_P 0x20 /* rfc 8667 */
42490792Sgshapiro#define ISIS_PREFIX_SID_FLAG_E 0x10 /* rfc 8667 */
42590792Sgshapiro#define ISIS_PREFIX_SID_FLAG_V 0x08 /* rfc 8667 */
42638032Speter#define ISIS_PREFIX_SID_FLAG_L 0x04 /* rfc 8667 */
42738032Speter
42838032Speterstatic const struct tok prefix_sid_flag_values[] = {
42938032Speter    { ISIS_PREFIX_SID_FLAG_R, "Readvertisement"},
43038032Speter    { ISIS_PREFIX_SID_FLAG_N, "Node"},
43138032Speter    { ISIS_PREFIX_SID_FLAG_P, "No-PHP"},
43264562Sgshapiro    { ISIS_PREFIX_SID_FLAG_E, "Explicit NULL"},
43338032Speter    { ISIS_PREFIX_SID_FLAG_V, "Value"},
43490792Sgshapiro    { ISIS_PREFIX_SID_FLAG_L, "Local"},
43590792Sgshapiro    { 0, NULL}
43638032Speter};
43738032Speter
43838032Speter
43938032Speter/* rfc 8667 */
44038032Speterstatic const struct tok prefix_sid_algo_values[] = {
44138032Speter    { 0, "SPF"},
44264562Sgshapiro    { 1, "strict-SPF"},
44338032Speter    { 0, NULL}
44490792Sgshapiro};
44590792Sgshapiro
44638032Speterstatic const struct tok isis_subtlv_link_attribute_values[] = {
44738032Speter    { 0x01, "Local Protection Available" },
44838032Speter    { 0x02, "Link excluded from local protection path" },
44938032Speter    { 0x04, "Local maintenance required"},
45038032Speter    { 0, NULL }
45138032Speter};
45238032Speter
45390792Sgshapirostatic const struct tok isis_lan_adj_sid_flag_values[] = {
45490792Sgshapiro    { 0x80, "Address family IPv6" },
45538032Speter    { 0x40, "Backup" },
45638032Speter    { 0x20, "Value" },
45738032Speter    { 0x10, "Local significance" },
45838032Speter    { 0x08, "Set of adjacencies" },
45990792Sgshapiro    { 0x04, "Persistent" },
46064562Sgshapiro    { 0, NULL }
46164562Sgshapiro};
46264562Sgshapiro
46364562Sgshapiro#define ISIS_SUBTLV_AUTH_SIMPLE        1
46464562Sgshapiro#define ISIS_SUBTLV_AUTH_GENERIC       3 /* rfc 5310 */
46564562Sgshapiro#define ISIS_SUBTLV_AUTH_MD5          54
46664562Sgshapiro#define ISIS_SUBTLV_AUTH_MD5_LEN      16
46764562Sgshapiro#define ISIS_SUBTLV_AUTH_PRIVATE     255
46864562Sgshapiro
46990792Sgshapirostatic const struct tok isis_subtlv_auth_values[] = {
47064562Sgshapiro    { ISIS_SUBTLV_AUTH_SIMPLE,	"simple text password"},
47164562Sgshapiro    { ISIS_SUBTLV_AUTH_GENERIC, "Generic Crypto key-id"},
47264562Sgshapiro    { ISIS_SUBTLV_AUTH_MD5,	"HMAC-MD5 password"},
47364562Sgshapiro    { ISIS_SUBTLV_AUTH_PRIVATE,	"Routing Domain private password"},
47464562Sgshapiro    { 0, NULL }
47542575Speter};
47690792Sgshapiro
47790792Sgshapiro#define ISIS_SUBTLV_IDRP_RES           0
47890792Sgshapiro#define ISIS_SUBTLV_IDRP_LOCAL         1
47938032Speter#define ISIS_SUBTLV_IDRP_ASN           2
48038032Speter
48138032Speterstatic const struct tok isis_subtlv_idrp_values[] = {
48238032Speter    { ISIS_SUBTLV_IDRP_RES,         "Reserved"},
48338032Speter    { ISIS_SUBTLV_IDRP_LOCAL,       "Routing-Domain Specific"},
48490792Sgshapiro    { ISIS_SUBTLV_IDRP_ASN,         "AS Number Tag"},
48538032Speter    { 0, NULL}
48638032Speter};
48790792Sgshapiro
48890792Sgshapiro#define ISIS_SUBTLV_SPB_MCID          4
48938032Speter#define ISIS_SUBTLV_SPB_DIGEST        5
49064562Sgshapiro#define ISIS_SUBTLV_SPB_BVID          6
49138032Speter
49238032Speter#define ISIS_SUBTLV_SPB_INSTANCE      1
49338032Speter#define ISIS_SUBTLV_SPBM_SI           3
49438032Speter
49538032Speter#define ISIS_SPB_MCID_LEN                         51
49638032Speter#define ISIS_SUBTLV_SPB_MCID_MIN_LEN              102
49790792Sgshapiro#define ISIS_SUBTLV_SPB_DIGEST_MIN_LEN            33
49838032Speter#define ISIS_SUBTLV_SPB_BVID_MIN_LEN              6
49938032Speter#define ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN          19
50090792Sgshapiro#define ISIS_SUBTLV_SPB_INSTANCE_VLAN_TUPLE_LEN   8
50171345Sgshapiro
50238032Speterstatic const struct tok isis_mt_port_cap_subtlv_values[] = {
50390792Sgshapiro    { ISIS_SUBTLV_SPB_MCID,           "SPB MCID" },
50438032Speter    { ISIS_SUBTLV_SPB_DIGEST,         "SPB Digest" },
50590792Sgshapiro    { ISIS_SUBTLV_SPB_BVID,           "SPB BVID" },
50638032Speter    { 0, NULL }
50738032Speter};
50871345Sgshapiro
50938032Speterstatic const struct tok isis_mt_capability_subtlv_values[] = {
51038032Speter    { ISIS_SUBTLV_SPB_INSTANCE,      "SPB Instance" },
51138032Speter    { ISIS_SUBTLV_SPBM_SI,      "SPBM Service Identifier and Unicast Address" },
51238032Speter    { 0, NULL }
51371345Sgshapiro};
51438032Speter
51538032Speterstruct isis_spb_mcid {
51638032Speter  nd_uint8_t  format_id;
51738032Speter  nd_byte     name[32];
51838032Speter  nd_uint16_t revision_lvl;
51990792Sgshapiro  nd_byte     digest[16];
52090792Sgshapiro};
52138032Speter
52238032Speterstruct isis_subtlv_spb_mcid {
52390792Sgshapiro  struct isis_spb_mcid mcid;
52490792Sgshapiro  struct isis_spb_mcid aux_mcid;
52566494Sgshapiro};
52666494Sgshapiro
52766494Sgshapirostruct isis_subtlv_spb_instance {
52866494Sgshapiro  nd_byte     cist_root_id[8];
52966494Sgshapiro  nd_uint32_t cist_external_root_path_cost;
53066494Sgshapiro  nd_uint16_t bridge_priority;
53166494Sgshapiro  nd_uint32_t spsourceid;
53290792Sgshapiro  nd_uint8_t  no_of_trees;
53390792Sgshapiro};
53490792Sgshapiro
53590792Sgshapiro#define CLNP_SEGMENT_PART  0x80
53690792Sgshapiro#define CLNP_MORE_SEGMENTS 0x40
53790792Sgshapiro#define CLNP_REQUEST_ER    0x20
53838032Speter
53990792Sgshapirostatic const struct tok clnp_flag_values[] = {
54090792Sgshapiro    { CLNP_SEGMENT_PART, "Segmentation permitted"},
54138032Speter    { CLNP_MORE_SEGMENTS, "more Segments"},
54238032Speter    { CLNP_REQUEST_ER, "request Error Report"},
54338032Speter    { 0, NULL}
54438032Speter};
54538032Speter
54638032Speter#define ISIS_MASK_LSP_OL_BIT(x)            (GET_U_1(x)&0x4)
54738032Speter#define ISIS_MASK_LSP_ISTYPE_BITS(x)       (GET_U_1(x)&0x3)
54838032Speter#define ISIS_MASK_LSP_PARTITION_BIT(x)     (GET_U_1(x)&0x80)
54938032Speter#define ISIS_MASK_LSP_ATT_BITS(x)          (GET_U_1(x)&0x78)
55038032Speter#define ISIS_MASK_LSP_ATT_ERROR_BIT(x)     (GET_U_1(x)&0x40)
55138032Speter#define ISIS_MASK_LSP_ATT_EXPENSE_BIT(x)   (GET_U_1(x)&0x20)
55290792Sgshapiro#define ISIS_MASK_LSP_ATT_DELAY_BIT(x)     (GET_U_1(x)&0x10)
55338032Speter#define ISIS_MASK_LSP_ATT_DEFAULT_BIT(x)   (GET_U_1(x)&0x8)
55438032Speter
55590792Sgshapiro#define ISIS_MASK_MTID(x)                  ((x)&0x0fff)
55690792Sgshapiro#define ISIS_MASK_MTFLAGS(x)               ((x)&0xf000)
55790792Sgshapiro
55890792Sgshapirostatic const struct tok isis_mt_flag_values[] = {
55938032Speter    { 0x4000,                  "ATT bit set"},
56038032Speter    { 0x8000,                  "Overload bit set"},
56190792Sgshapiro    { 0, NULL}
56290792Sgshapiro};
56390792Sgshapiro
56438032Speter#define ISIS_MASK_TLV_EXTD_IP_UPDOWN(x)     ((x)&0x80)
56590792Sgshapiro#define ISIS_MASK_TLV_EXTD_IP_SUBTLV(x)     ((x)&0x40)
56638032Speter
56738032Speter#define ISIS_MASK_TLV_EXTD_IP6_IE(x)        ((x)&0x40)
56838032Speter#define ISIS_MASK_TLV_EXTD_IP6_SUBTLV(x)    ((x)&0x20)
56938032Speter
57038032Speter#define ISIS_LSP_TLV_METRIC_SUPPORTED(x)   (GET_U_1(x)&0x80)
57138032Speter#define ISIS_LSP_TLV_METRIC_IE(x)          (GET_U_1(x)&0x40)
57238032Speter#define ISIS_LSP_TLV_METRIC_UPDOWN(x)      (GET_U_1(x)&0x80)
57338032Speter#define ISIS_LSP_TLV_METRIC_VALUE(x)	   (GET_U_1(x)&0x3f)
57438032Speter
57538032Speter#define ISIS_MASK_TLV_SHARED_RISK_GROUP(x) ((x)&0x1)
57664562Sgshapiro
57738032Speterstatic const struct tok isis_mt_values[] = {
57864562Sgshapiro    { 0,    "IPv4 unicast"},
57938032Speter    { 1,    "In-Band Management"},
58038032Speter    { 2,    "IPv6 unicast"},
58190792Sgshapiro    { 3,    "Multicast"},
58238032Speter    { 4095, "Development, Experimental or Proprietary"},
58338032Speter    { 0, NULL }
58438032Speter};
58538032Speter
58690792Sgshapirostatic const struct tok isis_iih_circuit_type_values[] = {
58738032Speter    { 1,    "Level 1 only"},
58838032Speter    { 2,    "Level 2 only"},
58938032Speter    { 3,    "Level 1, Level 2"},
59038032Speter    { 0, NULL}
59138032Speter};
59290792Sgshapiro
59338032Speter#define ISIS_LSP_TYPE_UNUSED0   0
59464562Sgshapiro#define ISIS_LSP_TYPE_LEVEL_1   1
59538032Speter#define ISIS_LSP_TYPE_UNUSED2   2
59638032Speter#define ISIS_LSP_TYPE_LEVEL_2   3
59738032Speter
59838032Speterstatic const struct tok isis_lsp_istype_values[] = {
59938032Speter    { ISIS_LSP_TYPE_UNUSED0,	"Unused 0x0 (invalid)"},
60038032Speter    { ISIS_LSP_TYPE_LEVEL_1,	"L1 IS"},
60138032Speter    { ISIS_LSP_TYPE_UNUSED2,	"Unused 0x2 (invalid)"},
60238032Speter    { ISIS_LSP_TYPE_LEVEL_2,	"L2 IS"},
60338032Speter    { 0, NULL }
60438032Speter};
60538032Speter
60638032Speter/*
60738032Speter * Katz's point to point adjacency TLV uses codes to tell us the state of
60890792Sgshapiro * the remote adjacency.  Enumerate them.
60938032Speter */
61038032Speter
61138032Speter#define ISIS_PTP_ADJ_UP   0
61238032Speter#define ISIS_PTP_ADJ_INIT 1
61338032Speter#define ISIS_PTP_ADJ_DOWN 2
61438032Speter
61538032Speterstatic const struct tok isis_ptp_adjancey_values[] = {
61638032Speter    { ISIS_PTP_ADJ_UP,    "Up" },
61738032Speter    { ISIS_PTP_ADJ_INIT,  "Initializing" },
61838032Speter    { ISIS_PTP_ADJ_DOWN,  "Down" },
61938032Speter    { 0, NULL}
62038032Speter};
62190792Sgshapiro
62238032Speterstruct isis_tlv_ptp_adj {
62338032Speter    nd_uint8_t  adjacency_state;
62438032Speter    nd_uint32_t extd_local_circuit_id;
62538032Speter    nd_byte     neighbor_sysid[SYSTEM_ID_LEN];
62664562Sgshapiro    nd_uint32_t neighbor_extd_local_circuit_id;
62738032Speter};
62864562Sgshapiro
62964562Sgshapirostatic void osi_print_cksum(netdissect_options *, const uint8_t *pptr,
63064562Sgshapiro			    uint16_t checksum, int checksum_offset, u_int length);
63164562Sgshapirostatic int clnp_print(netdissect_options *, const uint8_t *, u_int);
63264562Sgshapirostatic void esis_print(netdissect_options *, const uint8_t *, u_int);
63364562Sgshapirostatic int isis_print(netdissect_options *, const uint8_t *, u_int);
63464562Sgshapiro
63564562Sgshapirostruct isis_metric_block {
63690792Sgshapiro    nd_uint8_t metric_default;
63764562Sgshapiro    nd_uint8_t metric_delay;
63838032Speter    nd_uint8_t metric_expense;
63938032Speter    nd_uint8_t metric_error;
64038032Speter};
64164562Sgshapiro
64264562Sgshapirostruct isis_tlv_is_reach {
64338032Speter    struct isis_metric_block isis_metric_block;
64464562Sgshapiro    nd_byte neighbor_nodeid[NODE_ID_LEN];
64538032Speter};
64638032Speter
64738032Speterstruct isis_tlv_es_reach {
64838032Speter    struct isis_metric_block isis_metric_block;
64964562Sgshapiro    nd_byte neighbor_sysid[SYSTEM_ID_LEN];
65038032Speter};
65138032Speter
65238032Speterstruct isis_tlv_ip_reach {
65364562Sgshapiro    struct isis_metric_block isis_metric_block;
65438032Speter    nd_ipv4 prefix;
65538032Speter    nd_ipv4 mask;
65638032Speter};
65738032Speter
65890792Sgshapirostatic const struct tok isis_is_reach_virtual_values[] = {
65938032Speter    { 0,    "IsNotVirtual"},
66038032Speter    { 1,    "IsVirtual"},
66138032Speter    { 0, NULL }
66238032Speter};
66338032Speter
66490792Sgshapirostatic const struct tok isis_restart_flag_values[] = {
66564562Sgshapiro    { 0x1,  "Restart Request"},
66664562Sgshapiro    { 0x2,  "Restart Acknowledgement"},
66738032Speter    { 0x4,  "Suppress adjacency advertisement"},
66864562Sgshapiro    { 0, NULL }
66938032Speter};
67038032Speter
67138032Speterstruct isis_common_header {
67238032Speter    nd_uint8_t nlpid;
67390792Sgshapiro    nd_uint8_t fixed_len;
67438032Speter    nd_uint8_t version;			/* Protocol version */
67538032Speter    nd_uint8_t id_length;
67690792Sgshapiro    nd_uint8_t pdu_type;		/* 3 MSbits are reserved */
67738032Speter    nd_uint8_t pdu_version;		/* Packet format version */
67838032Speter    nd_byte reserved;
67938032Speter    nd_uint8_t max_area;
68077349Sgshapiro};
68177349Sgshapiro
68290792Sgshapirostruct isis_iih_lan_header {
68377349Sgshapiro    nd_uint8_t  circuit_type;
68477349Sgshapiro    nd_byte     source_id[SYSTEM_ID_LEN];
68577349Sgshapiro    nd_uint16_t holding_time;
68666494Sgshapiro    nd_uint16_t pdu_len;
68790792Sgshapiro    nd_uint8_t  priority;
68890792Sgshapiro    nd_byte     lan_id[NODE_ID_LEN];
68990792Sgshapiro};
69090792Sgshapiro
69190792Sgshapirostruct isis_iih_ptp_header {
69290792Sgshapiro    nd_uint8_t  circuit_type;
69390792Sgshapiro    nd_byte     source_id[SYSTEM_ID_LEN];
69466494Sgshapiro    nd_uint16_t holding_time;
69566494Sgshapiro    nd_uint16_t pdu_len;
69666494Sgshapiro    nd_uint8_t  circuit_id;
69766494Sgshapiro};
69866494Sgshapiro
69966494Sgshapirostruct isis_lsp_header {
70090792Sgshapiro    nd_uint16_t pdu_len;
70166494Sgshapiro    nd_uint16_t remaining_lifetime;
70290792Sgshapiro    nd_byte     lsp_id[LSP_ID_LEN];
70338032Speter    nd_uint32_t sequence_number;
70438032Speter    nd_uint16_t checksum;
70538032Speter    nd_uint8_t  typeblock;
70638032Speter};
70764562Sgshapiro
70890792Sgshapirostruct isis_csnp_header {
70938032Speter    nd_uint16_t pdu_len;
71090792Sgshapiro    nd_byte     source_id[NODE_ID_LEN];
71190792Sgshapiro    nd_byte     start_lsp_id[LSP_ID_LEN];
71238032Speter    nd_byte     end_lsp_id[LSP_ID_LEN];
71338032Speter};
71464562Sgshapiro
71538032Speterstruct isis_psnp_header {
71638032Speter    nd_uint16_t pdu_len;
71738032Speter    nd_byte     source_id[NODE_ID_LEN];
71838032Speter};
71964562Sgshapiro
72064562Sgshapirostruct isis_tlv_lsp {
72164562Sgshapiro    nd_uint16_t remaining_lifetime;
72238032Speter    nd_byte     lsp_id[LSP_ID_LEN];
72364562Sgshapiro    nd_uint32_t sequence_number;
72438032Speter    nd_uint16_t checksum;
72564562Sgshapiro};
72690792Sgshapiro
72738032Speter#define ISIS_COMMON_HEADER_SIZE (sizeof(struct isis_common_header))
72838032Speter#define ISIS_IIH_LAN_HEADER_SIZE (sizeof(struct isis_iih_lan_header))
72938032Speter#define ISIS_IIH_PTP_HEADER_SIZE (sizeof(struct isis_iih_ptp_header))
73090792Sgshapiro#define ISIS_LSP_HEADER_SIZE (sizeof(struct isis_lsp_header))
73138032Speter#define ISIS_CSNP_HEADER_SIZE (sizeof(struct isis_csnp_header))
73238032Speter#define ISIS_PSNP_HEADER_SIZE (sizeof(struct isis_psnp_header))
73338032Speter
73438032Spetervoid
73538032Speterisoclns_print(netdissect_options *ndo, const u_char *p, u_int length)
73638032Speter{
73738032Speter	ndo->ndo_protocol = "isoclns";
73838032Speter
73938032Speter	if (ndo->ndo_eflag)
74038032Speter		ND_PRINT("OSI NLPID %s (0x%02x): ",
74138032Speter			 tok2str(nlpid_values, "Unknown", GET_U_1(p)),
74290792Sgshapiro			 GET_U_1(p));
74338032Speter
74464562Sgshapiro	switch (GET_U_1(p)) {
74538032Speter
74664562Sgshapiro	case NLPID_CLNP:
74738032Speter		if (!clnp_print(ndo, p, length))
74838032Speter			print_unknown_data(ndo, p, "\n\t", length);
74938032Speter		break;
75038032Speter
75138032Speter	case NLPID_ESIS:
75238032Speter		esis_print(ndo, p, length);
75338032Speter		return;
75438032Speter
75538032Speter	case NLPID_ISIS:
75690792Sgshapiro		if (!isis_print(ndo, p, length))
75790792Sgshapiro			print_unknown_data(ndo, p, "\n\t", length);
75838032Speter		break;
75938032Speter
76090792Sgshapiro	case NLPID_NULLNS:
76190792Sgshapiro		ND_PRINT("%slength: %u", ndo->ndo_eflag ? "" : ", ", length);
76290792Sgshapiro		break;
76364562Sgshapiro
76438032Speter	case NLPID_Q933:
76538032Speter		q933_print(ndo, p + 1, length - 1);
76638032Speter		break;
76790792Sgshapiro
76838032Speter	case NLPID_IP:
76938032Speter		ip_print(ndo, p + 1, length - 1);
77038032Speter		break;
77138032Speter
77238032Speter	case NLPID_IP6:
77338032Speter		ip6_print(ndo, p + 1, length - 1);
77490792Sgshapiro		break;
77538032Speter
77638032Speter	case NLPID_PPP:
77738032Speter		ppp_print(ndo, p + 1, length - 1);
77838032Speter		break;
77938032Speter
78090792Sgshapiro	default:
78138032Speter		if (!ndo->ndo_eflag)
78238032Speter			ND_PRINT("OSI NLPID 0x%02x unknown", GET_U_1(p));
78364562Sgshapiro		ND_PRINT("%slength: %u", ndo->ndo_eflag ? "" : ", ", length);
78438032Speter		if (length > 1)
78538032Speter			print_unknown_data(ndo, p, "\n\t", length);
78638032Speter		break;
78738032Speter	}
78838032Speter}
78938032Speter
79038032Speter#define	CLNP_PDU_ER	 1
79138032Speter#define	CLNP_PDU_DT	28
79290792Sgshapiro#define	CLNP_PDU_MD	29
79390792Sgshapiro#define	CLNP_PDU_ERQ	30
79490792Sgshapiro#define	CLNP_PDU_ERP	31
79538032Speter
79638032Speterstatic const struct tok clnp_pdu_values[] = {
79764562Sgshapiro    { CLNP_PDU_ER,  "Error Report"},
79864562Sgshapiro    { CLNP_PDU_MD,  "MD"},
79938032Speter    { CLNP_PDU_DT,  "Data"},
80038032Speter    { CLNP_PDU_ERQ, "Echo Request"},
80138032Speter    { CLNP_PDU_ERP, "Echo Response"},
80238032Speter    { 0, NULL }
80338032Speter};
80438032Speter
80538032Speterstruct clnp_header_t {
80638032Speter    nd_uint8_t  nlpid;
80738032Speter    nd_uint8_t  length_indicator;
80838032Speter    nd_uint8_t  version;
80938032Speter    nd_uint8_t  lifetime; /* units of 500ms */
81038032Speter    nd_uint8_t  type;
81138032Speter    nd_uint16_t segment_length;
81238032Speter    nd_uint16_t cksum;
81338032Speter};
81490792Sgshapiro
81590792Sgshapirostruct clnp_segment_header_t {
81690792Sgshapiro    nd_uint16_t data_unit_id;
81790792Sgshapiro    nd_uint16_t segment_offset;
81890792Sgshapiro    nd_uint16_t total_length;
81964562Sgshapiro};
82090792Sgshapiro
82190792Sgshapiro/*
82290792Sgshapiro * clnp_print
82364562Sgshapiro * Decode CLNP packets.  Return 0 on error.
82464562Sgshapiro */
82538032Speter
82638032Speterstatic int
82738032Speterclnp_print(netdissect_options *ndo,
82838032Speter           const uint8_t *pptr, u_int length)
82938032Speter{
83038032Speter	const uint8_t *optr,*source_address,*dest_address;
83138032Speter        u_int li,li_remaining,tlen,nsap_offset,source_address_length,dest_address_length, clnp_pdu_type, clnp_flags;
83238032Speter	const struct clnp_header_t *clnp_header;
83338032Speter	const struct clnp_segment_header_t *clnp_segment_header;
83464562Sgshapiro        uint8_t rfd_error,rfd_error_major,rfd_error_minor;
83590792Sgshapiro
83690792Sgshapiro	ndo->ndo_protocol = "clnp";
83790792Sgshapiro	clnp_header = (const struct clnp_header_t *) pptr;
83838032Speter        ND_TCHECK_SIZE(clnp_header);
83990792Sgshapiro
84090792Sgshapiro        li = GET_U_1(clnp_header->length_indicator);
84190792Sgshapiro        li_remaining = li;
84290792Sgshapiro        optr = pptr;
84390792Sgshapiro
84490792Sgshapiro        if (!ndo->ndo_eflag)
84590792Sgshapiro            nd_print_protocol_caps(ndo);
84690792Sgshapiro
84790792Sgshapiro        /*
84890792Sgshapiro         * Sanity checking of the header.
84990792Sgshapiro         */
85090792Sgshapiro
85190792Sgshapiro        if (GET_U_1(clnp_header->version) != CLNP_VERSION) {
85290792Sgshapiro            ND_PRINT("version %u packet not supported",
85390792Sgshapiro                     GET_U_1(clnp_header->version));
85490792Sgshapiro            return (0);
85590792Sgshapiro        }
85690792Sgshapiro
85790792Sgshapiro	if (li > length) {
85890792Sgshapiro            ND_PRINT(" length indicator(%u) > PDU size (%u)!", li, length);
85990792Sgshapiro            return (0);
86090792Sgshapiro	}
86190792Sgshapiro
86290792Sgshapiro        if (li < sizeof(struct clnp_header_t)) {
86390792Sgshapiro            ND_PRINT(" length indicator %u < min PDU size:", li);
86490792Sgshapiro            while (pptr < ndo->ndo_snapend) {
86590792Sgshapiro                ND_PRINT("%02X", GET_U_1(pptr));
86690792Sgshapiro                pptr++;
86790792Sgshapiro            }
86890792Sgshapiro            return (0);
86990792Sgshapiro        }
87090792Sgshapiro
87190792Sgshapiro        /* FIXME further header sanity checking */
87290792Sgshapiro
87390792Sgshapiro        clnp_pdu_type = GET_U_1(clnp_header->type) & CLNP_PDU_TYPE_MASK;
87490792Sgshapiro        clnp_flags = GET_U_1(clnp_header->type) & CLNP_FLAG_MASK;
87590792Sgshapiro
87690792Sgshapiro        pptr += sizeof(struct clnp_header_t);
87790792Sgshapiro        li_remaining -= sizeof(struct clnp_header_t);
87890792Sgshapiro
87990792Sgshapiro        if (li_remaining < 1) {
88090792Sgshapiro            ND_PRINT("li < size of fixed part of CLNP header and addresses");
88190792Sgshapiro            return (0);
88238032Speter        }
88338032Speter        dest_address_length = GET_U_1(pptr);
88438032Speter        pptr += 1;
88538032Speter        li_remaining -= 1;
88638032Speter        if (li_remaining < dest_address_length) {
88738032Speter            ND_PRINT("li < size of fixed part of CLNP header and addresses");
88890792Sgshapiro            return (0);
88990792Sgshapiro        }
89038032Speter        ND_TCHECK_LEN(pptr, dest_address_length);
89164562Sgshapiro        dest_address = pptr;
89238032Speter        pptr += dest_address_length;
89338032Speter        li_remaining -= dest_address_length;
89438032Speter
89564562Sgshapiro        if (li_remaining < 1) {
89638032Speter            ND_PRINT("li < size of fixed part of CLNP header and addresses");
89738032Speter            return (0);
89838032Speter        }
89938032Speter        source_address_length = GET_U_1(pptr);
90038032Speter        pptr += 1;
90138032Speter        li_remaining -= 1;
90238032Speter        if (li_remaining < source_address_length) {
90338032Speter            ND_PRINT("li < size of fixed part of CLNP header and addresses");
90438032Speter            return (0);
90538032Speter        }
90638032Speter        ND_TCHECK_LEN(pptr, source_address_length);
90738032Speter        source_address = pptr;
90864562Sgshapiro        pptr += source_address_length;
90938032Speter        li_remaining -= source_address_length;
91038032Speter
91138032Speter        if (ndo->ndo_vflag < 1) {
91238032Speter            ND_PRINT("%s%s > %s, %s, length %u",
91338032Speter                   ndo->ndo_eflag ? "" : ", ",
91466494Sgshapiro                   GET_ISONSAP_STRING(source_address, source_address_length),
91566494Sgshapiro                   GET_ISONSAP_STRING(dest_address, dest_address_length),
91638032Speter                   tok2str(clnp_pdu_values,"unknown (%u)",clnp_pdu_type),
91790792Sgshapiro                   length);
91838032Speter            return (1);
91938032Speter        }
92038032Speter        ND_PRINT("%slength %u", ndo->ndo_eflag ? "" : ", ", length);
92190792Sgshapiro
92238032Speter        ND_PRINT("\n\t%s PDU, hlen: %u, v: %u, lifetime: %u.%us, Segment PDU length: %u, checksum: 0x%04x",
92338032Speter               tok2str(clnp_pdu_values, "unknown (%u)",clnp_pdu_type),
92438032Speter               GET_U_1(clnp_header->length_indicator),
92538032Speter               GET_U_1(clnp_header->version),
92638032Speter               GET_U_1(clnp_header->lifetime)/2,
92738032Speter               (GET_U_1(clnp_header->lifetime)%2)*5,
92838032Speter               GET_BE_U_2(clnp_header->segment_length),
92938032Speter               GET_BE_U_2(clnp_header->cksum));
93038032Speter
93138032Speter        osi_print_cksum(ndo, optr, GET_BE_U_2(clnp_header->cksum), 7,
93264562Sgshapiro                        GET_U_1(clnp_header->length_indicator));
93338032Speter
93490792Sgshapiro        ND_PRINT("\n\tFlags [%s]",
93590792Sgshapiro               bittok2str(clnp_flag_values, "none", clnp_flags));
93690792Sgshapiro
93790792Sgshapiro        ND_PRINT("\n\tsource address (length %u): %s\n\tdest   address (length %u): %s",
93890792Sgshapiro               source_address_length,
93990792Sgshapiro               GET_ISONSAP_STRING(source_address, source_address_length),
94090792Sgshapiro               dest_address_length,
94190792Sgshapiro               GET_ISONSAP_STRING(dest_address, dest_address_length));
94290792Sgshapiro
94390792Sgshapiro        if (clnp_flags & CLNP_SEGMENT_PART) {
94490792Sgshapiro                if (li_remaining < sizeof(struct clnp_segment_header_t)) {
94590792Sgshapiro                    ND_PRINT("li < size of fixed part of CLNP header, addresses, and segment part");
94690792Sgshapiro                    return (0);
94790792Sgshapiro                }
94890792Sgshapiro		clnp_segment_header = (const struct clnp_segment_header_t *) pptr;
94990792Sgshapiro                ND_TCHECK_SIZE(clnp_segment_header);
95090792Sgshapiro                ND_PRINT("\n\tData Unit ID: 0x%04x, Segment Offset: %u, Total PDU Length: %u",
95190792Sgshapiro                       GET_BE_U_2(clnp_segment_header->data_unit_id),
95290792Sgshapiro                       GET_BE_U_2(clnp_segment_header->segment_offset),
95390792Sgshapiro                       GET_BE_U_2(clnp_segment_header->total_length));
95490792Sgshapiro                pptr+=sizeof(struct clnp_segment_header_t);
95590792Sgshapiro                li_remaining-=sizeof(struct clnp_segment_header_t);
956110560Sgshapiro        }
957110560Sgshapiro
958110560Sgshapiro        /* now walk the options */
959110560Sgshapiro        while (li_remaining != 0) {
960110560Sgshapiro            u_int op, opli;
96190792Sgshapiro            const uint8_t *tptr;
96290792Sgshapiro
96390792Sgshapiro            if (li_remaining < 2) {
96490792Sgshapiro                ND_PRINT(", bad opts/li");
96590792Sgshapiro                return (0);
96690792Sgshapiro            }
96790792Sgshapiro            op = GET_U_1(pptr);
96890792Sgshapiro            opli = GET_U_1(pptr + 1);
96990792Sgshapiro            pptr += 2;
97090792Sgshapiro            li_remaining -= 2;
97190792Sgshapiro            if (opli > li_remaining) {
97290792Sgshapiro                ND_PRINT(", opt (%u) too long", op);
97390792Sgshapiro                return (0);
97490792Sgshapiro            }
97590792Sgshapiro            ND_TCHECK_LEN(pptr, opli);
97690792Sgshapiro            li_remaining -= opli;
97790792Sgshapiro            tptr = pptr;
97890792Sgshapiro            tlen = opli;
97990792Sgshapiro
98090792Sgshapiro            ND_PRINT("\n\t  %s Option #%u, length %u, value: ",
98190792Sgshapiro                   tok2str(clnp_option_values,"Unknown",op),
98290792Sgshapiro                   op,
98390792Sgshapiro                   opli);
98490792Sgshapiro
98590792Sgshapiro            /*
98690792Sgshapiro             * We've already checked that the entire option is present
98790792Sgshapiro             * in the captured packet with the ND_TCHECK_LEN() call.
98890792Sgshapiro             * Therefore, we don't need to do ND_TCHECK()/ND_TCHECK_LEN()
98990792Sgshapiro             * checks.
99090792Sgshapiro             * We do, however, need to check tlen, to make sure we
99190792Sgshapiro             * don't run past the end of the option.
99290792Sgshapiro	     */
99338032Speter            switch (op) {
99438032Speter
99538032Speter
99638032Speter            case CLNP_OPTION_ROUTE_RECORDING: /* those two options share the format */
99738032Speter            case CLNP_OPTION_SOURCE_ROUTING:
99890792Sgshapiro                    if (tlen < 2) {
99938032Speter                            ND_PRINT(", bad opt len");
100038032Speter                            return (0);
100138032Speter                    }
100238032Speter                    ND_PRINT("%s %s",
100338032Speter                           tok2str(clnp_option_sr_rr_values,"Unknown",GET_U_1(tptr)),
100464562Sgshapiro                           tok2str(clnp_option_sr_rr_string_values, "Unknown Option %u", op));
100538032Speter                    nsap_offset=GET_U_1(tptr + 1);
100690792Sgshapiro                    if (nsap_offset == 0) {
100738032Speter                            ND_PRINT(" Bad NSAP offset (0)");
100838032Speter                            break;
100964562Sgshapiro                    }
101038032Speter                    nsap_offset-=1; /* offset to nsap list */
101138032Speter                    if (nsap_offset > tlen) {
101238032Speter                            ND_PRINT(" Bad NSAP offset (past end of option)");
101364562Sgshapiro                            break;
101464562Sgshapiro                    }
101564562Sgshapiro                    tptr+=nsap_offset;
101664562Sgshapiro                    tlen-=nsap_offset;
101764562Sgshapiro                    while (tlen > 0) {
101890792Sgshapiro                            source_address_length=GET_U_1(tptr);
101990792Sgshapiro                            if (tlen < source_address_length+1) {
1020102528Sgshapiro                                    ND_PRINT("\n\t    NSAP address goes past end of option");
1021102528Sgshapiro                                    break;
1022102528Sgshapiro                            }
1023102528Sgshapiro                            if (source_address_length > 0) {
1024102528Sgshapiro                                    source_address=(tptr+1);
1025102528Sgshapiro                                    ND_PRINT("\n\t    NSAP address (length %u): %s",
1026102528Sgshapiro                                           source_address_length,
1027102528Sgshapiro                                           GET_ISONSAP_STRING(source_address, source_address_length));
1028102528Sgshapiro                            }
1029102528Sgshapiro                            tlen-=source_address_length+1;
103038032Speter                    }
103138032Speter                    break;
103264562Sgshapiro
103338032Speter            case CLNP_OPTION_PRIORITY:
103438032Speter                    if (tlen < 1) {
103564562Sgshapiro                            ND_PRINT(", bad opt len");
103638032Speter                            return (0);
103738032Speter                    }
103838032Speter                    ND_PRINT("0x%1x", GET_U_1(tptr)&0x0f);
103938032Speter                    break;
104090792Sgshapiro
104164562Sgshapiro            case CLNP_OPTION_QOS_MAINTENANCE:
104238032Speter                    if (tlen < 1) {
104338032Speter                            ND_PRINT(", bad opt len");
104438032Speter                            return (0);
104538032Speter                    }
104690792Sgshapiro                    ND_PRINT("\n\t    Format Code: %s",
104764562Sgshapiro                           tok2str(clnp_option_scope_values, "Reserved", GET_U_1(tptr) & CLNP_OPTION_SCOPE_MASK));
104838032Speter
104938032Speter                    if ((GET_U_1(tptr)&CLNP_OPTION_SCOPE_MASK) == CLNP_OPTION_SCOPE_GLOBAL)
105038032Speter                            ND_PRINT("\n\t    QoS Flags [%s]",
105190792Sgshapiro                                   bittok2str(clnp_option_qos_global_values,
105238032Speter                                              "none",
105390792Sgshapiro                                              GET_U_1(tptr)&CLNP_OPTION_OPTION_QOS_MASK));
105438032Speter                    break;
105538032Speter
105638032Speter            case CLNP_OPTION_SECURITY:
105738032Speter                    if (tlen < 2) {
105838032Speter                            ND_PRINT(", bad opt len");
105938032Speter                            return (0);
106038032Speter                    }
106138032Speter                    ND_PRINT("\n\t    Format Code: %s, Security-Level %u",
106238032Speter                           tok2str(clnp_option_scope_values,"Reserved",GET_U_1(tptr)&CLNP_OPTION_SCOPE_MASK),
106338032Speter                           GET_U_1(tptr + 1));
106438032Speter                    break;
106538032Speter
106638032Speter            case CLNP_OPTION_DISCARD_REASON:
106738032Speter                if (tlen < 1) {
106838032Speter                        ND_PRINT(", bad opt len");
106938032Speter                        return (0);
107038032Speter                }
107138032Speter                rfd_error = GET_U_1(tptr);
107238032Speter                rfd_error_major = (rfd_error&0xf0) >> 4;
107338032Speter                rfd_error_minor = rfd_error&0x0f;
107438032Speter                ND_PRINT("\n\t    Class: %s Error (0x%01x), %s (0x%01x)",
107564562Sgshapiro                       tok2str(clnp_option_rfd_class_values,"Unknown",rfd_error_major),
107638032Speter                       rfd_error_major,
107764562Sgshapiro                       tok2str(clnp_option_rfd_error_class[rfd_error_major],"Unknown",rfd_error_minor),
107838032Speter                       rfd_error_minor);
107964562Sgshapiro                break;
108038032Speter
108164562Sgshapiro            case CLNP_OPTION_PADDING:
108238032Speter                    ND_PRINT("padding data");
108338032Speter                break;
108438032Speter
108538032Speter                /*
108638032Speter                 * FIXME those are the defined Options that lack a decoder
108738032Speter                 * you are welcome to contribute code ;-)
108838032Speter                 */
108938032Speter
109038032Speter            default:
109164562Sgshapiro                print_unknown_data(ndo, tptr, "\n\t  ", opli);
109238032Speter                break;
109338032Speter            }
109490792Sgshapiro            if (ndo->ndo_vflag > 1)
109538032Speter                print_unknown_data(ndo, pptr, "\n\t  ", opli);
109638032Speter            pptr += opli;
109738032Speter        }
109838032Speter
109938032Speter        switch (clnp_pdu_type) {
110038032Speter
110138032Speter        case    CLNP_PDU_ER: /* fall through */
110238032Speter        case	CLNP_PDU_ERP:
110338032Speter            if (GET_U_1(pptr) == NLPID_CLNP) {
110438032Speter                ND_PRINT("\n\t-----original packet-----\n\t");
110538032Speter                /* FIXME recursion protection */
110638032Speter                clnp_print(ndo, pptr, length - li);
110738032Speter                break;
110838032Speter            }
110977349Sgshapiro
111038032Speter        /* The cases above break from the switch block if they see and print
111138032Speter         * a CLNP header in the Data part. For an Error Report PDU this is
111238032Speter         * described in Section 7.9.6 of ITU X.233 (1997 E), also known as
111338032Speter         * ISO/IEC 8473-1:1998(E). It is not clear why in this code the same
111438032Speter         * applies to an Echo Response PDU, as the standard does not specify
111564562Sgshapiro         * the contents -- could be a proprietary extension or a bug. In either
111638032Speter         * case, if the Data part does not contain a CLNP header, its structure
111790792Sgshapiro         * is considered unknown and the decoding falls through to print the
111890792Sgshapiro         * contents as-is.
111990792Sgshapiro         */
112090792Sgshapiro        ND_FALL_THROUGH;
112190792Sgshapiro
112290792Sgshapiro        case	CLNP_PDU_DT:
112390792Sgshapiro        case	CLNP_PDU_MD:
112490792Sgshapiro        case	CLNP_PDU_ERQ:
112590792Sgshapiro
112690792Sgshapiro        default:
112790792Sgshapiro            /* dump the PDU specific data */
112890792Sgshapiro            if (length > ND_BYTES_BETWEEN(pptr, optr)) {
112990792Sgshapiro                ND_PRINT("\n\t  undecoded non-header data, length %u", length-li);
113090792Sgshapiro                print_unknown_data(ndo, pptr, "\n\t  ", length - ND_BYTES_BETWEEN(pptr, optr));
113190792Sgshapiro            }
113290792Sgshapiro        }
113390792Sgshapiro
113490792Sgshapiro        return (1);
113590792Sgshapiro
113690792Sgshapiro trunc:
113790792Sgshapiro    nd_print_trunc(ndo);
113890792Sgshapiro    return (1);
113990792Sgshapiro
114090792Sgshapiro}
114190792Sgshapiro
114290792Sgshapiro
114390792Sgshapiro#define	ESIS_PDU_REDIRECT	6
114490792Sgshapiro#define	ESIS_PDU_ESH	        2
114590792Sgshapiro#define	ESIS_PDU_ISH	        4
114690792Sgshapiro
114790792Sgshapirostatic const struct tok esis_pdu_values[] = {
114890792Sgshapiro    { ESIS_PDU_REDIRECT, "redirect"},
114990792Sgshapiro    { ESIS_PDU_ESH,      "ESH"},
115090792Sgshapiro    { ESIS_PDU_ISH,      "ISH"},
115190792Sgshapiro    { 0, NULL }
115290792Sgshapiro};
115390792Sgshapiro
115490792Sgshapirostruct esis_header_t {
115590792Sgshapiro	nd_uint8_t  nlpid;
115690792Sgshapiro	nd_uint8_t  length_indicator;
115790792Sgshapiro	nd_uint8_t  version;
115890792Sgshapiro	nd_byte     reserved;
115990792Sgshapiro	nd_uint8_t  type;
116090792Sgshapiro	nd_uint16_t holdtime;
116190792Sgshapiro	nd_uint16_t cksum;
116290792Sgshapiro};
116390792Sgshapiro
116490792Sgshapirostatic void
116590792Sgshapiroesis_print(netdissect_options *ndo,
116690792Sgshapiro           const uint8_t *pptr, u_int length)
116790792Sgshapiro{
116890792Sgshapiro	const uint8_t *optr;
116990792Sgshapiro	u_int li, version, esis_pdu_type, source_address_length, source_address_number;
117090792Sgshapiro	const struct esis_header_t *esis_header;
117190792Sgshapiro
117290792Sgshapiro	ndo->ndo_protocol = "esis";
117390792Sgshapiro	if (!ndo->ndo_eflag)
117490792Sgshapiro		ND_PRINT("ES-IS");
117590792Sgshapiro
117690792Sgshapiro	if (length <= 2) {
117790792Sgshapiro		ND_PRINT(ndo->ndo_qflag ? "bad pkt!" : "no header at all!");
117890792Sgshapiro		return;
117990792Sgshapiro	}
118090792Sgshapiro
118190792Sgshapiro	esis_header = (const struct esis_header_t *) pptr;
118290792Sgshapiro        ND_TCHECK_SIZE(esis_header);
118390792Sgshapiro        li = GET_U_1(esis_header->length_indicator);
118438032Speter        optr = pptr;
118538032Speter
118638032Speter        /*
118738032Speter         * Sanity checking of the header.
118838032Speter         */
118938032Speter
119038032Speter        if (GET_U_1(esis_header->nlpid) != NLPID_ESIS) {
119138032Speter            ND_PRINT(" nlpid 0x%02x packet not supported",
119290792Sgshapiro		     GET_U_1(esis_header->nlpid));
119390792Sgshapiro            return;
119490792Sgshapiro        }
119590792Sgshapiro
119690792Sgshapiro        version = GET_U_1(esis_header->version);
119790792Sgshapiro        if (version != ESIS_VERSION) {
119890792Sgshapiro            ND_PRINT(" version %u packet not supported", version);
119990792Sgshapiro            return;
120090792Sgshapiro        }
120190792Sgshapiro
120290792Sgshapiro	if (li > length) {
120390792Sgshapiro            ND_PRINT(" length indicator(%u) > PDU size (%u)!", li, length);
120490792Sgshapiro            return;
120590792Sgshapiro	}
120690792Sgshapiro
120790792Sgshapiro	if (li < sizeof(struct esis_header_t) + 2) {
120890792Sgshapiro            ND_PRINT(" length indicator %u < min PDU size:", li);
120990792Sgshapiro            while (pptr < ndo->ndo_snapend) {
121090792Sgshapiro                ND_PRINT("%02X", GET_U_1(pptr));
121190792Sgshapiro                pptr++;
121290792Sgshapiro            }
121390792Sgshapiro            return;
121490792Sgshapiro	}
121590792Sgshapiro
121690792Sgshapiro        esis_pdu_type = GET_U_1(esis_header->type) & ESIS_PDU_TYPE_MASK;
121790792Sgshapiro
121890792Sgshapiro        if (ndo->ndo_vflag < 1) {
121990792Sgshapiro            ND_PRINT("%s%s, length %u",
122090792Sgshapiro                   ndo->ndo_eflag ? "" : ", ",
122190792Sgshapiro                   tok2str(esis_pdu_values,"unknown type (%u)",esis_pdu_type),
122290792Sgshapiro                   length);
122390792Sgshapiro            return;
122490792Sgshapiro        } else
122590792Sgshapiro            ND_PRINT("%slength %u\n\t%s (%u)",
122690792Sgshapiro                   ndo->ndo_eflag ? "" : ", ",
122790792Sgshapiro                   length,
122890792Sgshapiro                   tok2str(esis_pdu_values,"unknown type: %u", esis_pdu_type),
122990792Sgshapiro                   esis_pdu_type);
123090792Sgshapiro
123138032Speter        ND_PRINT(", v: %u%s", version, version == ESIS_VERSION ? "" : "unsupported" );
123238032Speter        ND_PRINT(", checksum: 0x%04x", GET_BE_U_2(esis_header->cksum));
123338032Speter
123438032Speter        osi_print_cksum(ndo, pptr, GET_BE_U_2(esis_header->cksum), 7,
123538032Speter                        li);
123638032Speter
123738032Speter        ND_PRINT(", holding time: %us, length indicator: %u",
123838032Speter                  GET_BE_U_2(esis_header->holdtime), li);
123938032Speter
124038032Speter        if (ndo->ndo_vflag > 1)
124138032Speter            print_unknown_data(ndo, optr, "\n\t", sizeof(struct esis_header_t));
124238032Speter
124338032Speter	pptr += sizeof(struct esis_header_t);
124438032Speter	li -= sizeof(struct esis_header_t);
124538032Speter
124664562Sgshapiro	switch (esis_pdu_type) {
124738032Speter	case ESIS_PDU_REDIRECT: {
124838032Speter		const uint8_t *dst, *snpa, *neta;
124964562Sgshapiro		u_int dstl, snpal, netal;
125038032Speter
125164562Sgshapiro		ND_TCHECK_1(pptr);
125238032Speter		if (li < 1) {
125338032Speter			ND_PRINT(", bad redirect/li");
125438032Speter			return;
125538032Speter		}
125638032Speter		dstl = GET_U_1(pptr);
125738032Speter		pptr++;
125838032Speter		li--;
125938032Speter		ND_TCHECK_LEN(pptr, dstl);
126038032Speter		if (li < dstl) {
126138032Speter			ND_PRINT(", bad redirect/li");
126238032Speter			return;
126390792Sgshapiro		}
126438032Speter		dst = pptr;
126590792Sgshapiro		pptr += dstl;
126638032Speter                li -= dstl;
126790792Sgshapiro		ND_PRINT("\n\t  %s", GET_ISONSAP_STRING(dst, dstl));
126890792Sgshapiro
126938032Speter		ND_TCHECK_1(pptr);
127038032Speter		if (li < 1) {
127190792Sgshapiro			ND_PRINT(", bad redirect/li");
127290792Sgshapiro			return;
127390792Sgshapiro		}
127438032Speter		snpal = GET_U_1(pptr);
127590792Sgshapiro		pptr++;
127638032Speter		li--;
127790792Sgshapiro		ND_TCHECK_LEN(pptr, snpal);
127890792Sgshapiro		if (li < snpal) {
127964562Sgshapiro			ND_PRINT(", bad redirect/li");
128090792Sgshapiro			return;
128164562Sgshapiro		}
128238032Speter		snpa = pptr;
128338032Speter		pptr += snpal;
128438032Speter                li -= snpal;
128590792Sgshapiro		ND_TCHECK_1(pptr);
128664562Sgshapiro		if (li < 1) {
128790792Sgshapiro			ND_PRINT(", bad redirect/li");
128890792Sgshapiro			return;
128990792Sgshapiro		}
129064562Sgshapiro		netal = GET_U_1(pptr);
129164562Sgshapiro		pptr++;
129290792Sgshapiro		ND_TCHECK_LEN(pptr, netal);
129364562Sgshapiro		if (li < netal) {
129464562Sgshapiro			ND_PRINT(", bad redirect/li");
129590792Sgshapiro			return;
129638032Speter		}
129738032Speter		neta = pptr;
129864562Sgshapiro		pptr += netal;
129964562Sgshapiro                li -= netal;
130038032Speter
130198121Sgshapiro		if (snpal == MAC_ADDR_LEN)
130238032Speter			ND_PRINT("\n\t  SNPA (length: %u): %s",
130338032Speter			       snpal,
130464562Sgshapiro			       GET_ETHERADDR_STRING(snpa));
130564562Sgshapiro		else
130638032Speter			ND_PRINT("\n\t  SNPA (length: %u): %s",
130738032Speter			       snpal,
130838032Speter			       GET_LINKADDR_STRING(snpa, LINKADDR_OTHER, snpal));
130938032Speter		if (netal != 0)
131038032Speter			ND_PRINT("\n\t  NET (length: %u) %s",
131138032Speter			       netal,
131238032Speter			       GET_ISONSAP_STRING(neta, netal));
131338032Speter		break;
131438032Speter	}
131538032Speter
131638032Speter	case ESIS_PDU_ESH:
131790792Sgshapiro            ND_TCHECK_1(pptr);
131838032Speter            if (li < 1) {
131938032Speter                ND_PRINT(", bad esh/li");
132090792Sgshapiro                return;
132138032Speter            }
132238032Speter            source_address_number = GET_U_1(pptr);
132390792Sgshapiro            pptr++;
132438032Speter            li--;
132538032Speter
132664562Sgshapiro            ND_PRINT("\n\t  Number of Source Addresses: %u", source_address_number);
132738032Speter
132838032Speter            while (source_address_number > 0) {
132990792Sgshapiro                ND_TCHECK_1(pptr);
133090792Sgshapiro		if (li < 1) {
133190792Sgshapiro                    ND_PRINT(", bad esh/li");
133290792Sgshapiro		    return;
133338032Speter		}
133464562Sgshapiro                source_address_length = GET_U_1(pptr);
133590792Sgshapiro                pptr++;
133690792Sgshapiro		li--;
133790792Sgshapiro
133890792Sgshapiro                ND_TCHECK_LEN(pptr, source_address_length);
133938032Speter		if (li < source_address_length) {
134038032Speter                    ND_PRINT(", bad esh/li");
134138032Speter		    return;
134238032Speter		}
134338032Speter                ND_PRINT("\n\t  NET (length: %u): %s",
134438032Speter                       source_address_length,
134538032Speter                       GET_ISONSAP_STRING(pptr, source_address_length));
134638032Speter                pptr += source_address_length;
134738032Speter                li -= source_address_length;
134838032Speter                source_address_number--;
134938032Speter            }
135038032Speter
135138032Speter            break;
135238032Speter
135338032Speter	case ESIS_PDU_ISH: {
135438032Speter            ND_TCHECK_1(pptr);
135538032Speter            if (li < 1) {
135690792Sgshapiro                ND_PRINT(", bad ish/li");
135790792Sgshapiro                return;
135838032Speter            }
135990792Sgshapiro            source_address_length = GET_U_1(pptr);
136090792Sgshapiro            pptr++;
136190792Sgshapiro            li--;
136290792Sgshapiro            ND_TCHECK_LEN(pptr, source_address_length);
136390792Sgshapiro            if (li < source_address_length) {
136438032Speter                ND_PRINT(", bad ish/li");
136590792Sgshapiro                return;
136690792Sgshapiro            }
136790792Sgshapiro            ND_PRINT("\n\t  NET (length: %u): %s", source_address_length, GET_ISONSAP_STRING(pptr, source_address_length));
136838032Speter            pptr += source_address_length;
136938032Speter            li -= source_address_length;
137038032Speter            break;
137138032Speter	}
137238032Speter
137364562Sgshapiro	default:
137464562Sgshapiro		if (ndo->ndo_vflag <= 1) {
137564562Sgshapiro			/*
137638032Speter			 * If there's at least one byte to print, print
137738032Speter			 * it/them.
137838032Speter			 */
137938032Speter			if (ND_TTEST_LEN(pptr, 1))
138038032Speter				print_unknown_data(ndo, pptr, "\n\t  ", ND_BYTES_AVAILABLE_AFTER(pptr));
138190792Sgshapiro		}
138238032Speter		return;
138338032Speter	}
138438032Speter
138538032Speter        /* now walk the options */
138638032Speter        while (li != 0) {
138738032Speter            u_int op, opli;
138838032Speter            const uint8_t *tptr;
138938032Speter
139038032Speter            if (li < 2) {
139138032Speter                ND_PRINT(", bad opts/li");
139238032Speter                return;
139338032Speter            }
139438032Speter            op = GET_U_1(pptr);
139538032Speter            opli = GET_U_1(pptr + 1);
139638032Speter            pptr += 2;
139738032Speter            li -= 2;
139838032Speter            if (opli > li) {
139938032Speter                ND_PRINT(", opt (%u) too long", op);
140038032Speter                return;
140138032Speter            }
140238032Speter            li -= opli;
140338032Speter            tptr = pptr;
140438032Speter
140538032Speter            ND_PRINT("\n\t  %s Option #%u, length %u, value: ",
140638032Speter                   tok2str(esis_option_values,"Unknown",op),
140738032Speter                   op,
140890792Sgshapiro                   opli);
140938032Speter
141038032Speter            switch (op) {
141164562Sgshapiro
141264562Sgshapiro            case ESIS_OPTION_ES_CONF_TIME:
141390792Sgshapiro                if (opli == 2) {
141490792Sgshapiro                    ND_TCHECK_2(pptr);
141538032Speter                    ND_PRINT("%us", GET_BE_U_2(tptr));
141638032Speter                } else
141738032Speter                    ND_PRINT("(bad length)");
141838032Speter                break;
141938032Speter
142038032Speter            case ESIS_OPTION_PROTOCOLS:
142138032Speter                while (opli>0) {
142238032Speter                    ND_PRINT("%s (0x%02x)",
142338032Speter                           tok2str(nlpid_values,
142438032Speter                                   "unknown",
142538032Speter                                   GET_U_1(tptr)),
142673188Sgshapiro                           GET_U_1(tptr));
142790792Sgshapiro                    if (opli>1) /* further NPLIDs ? - put comma */
142838032Speter                        ND_PRINT(", ");
142938032Speter                    tptr++;
143073188Sgshapiro                    opli--;
143173188Sgshapiro                }
143273188Sgshapiro                break;
143373188Sgshapiro
143473188Sgshapiro                /*
143573188Sgshapiro                 * FIXME those are the defined Options that lack a decoder
143673188Sgshapiro                 * you are welcome to contribute code ;-)
143773188Sgshapiro                 */
143838032Speter
143938032Speter            case ESIS_OPTION_QOS_MAINTENANCE:
144038032Speter            case ESIS_OPTION_SECURITY:
144138032Speter            case ESIS_OPTION_PRIORITY:
144238032Speter            case ESIS_OPTION_ADDRESS_MASK:
144338032Speter            case ESIS_OPTION_SNPA_MASK:
144438032Speter
144538032Speter            default:
144664562Sgshapiro                print_unknown_data(ndo, tptr, "\n\t  ", opli);
144764562Sgshapiro                break;
144864562Sgshapiro            }
144990792Sgshapiro            if (ndo->ndo_vflag > 1)
145090792Sgshapiro                print_unknown_data(ndo, pptr, "\n\t  ", opli);
145190792Sgshapiro            pptr += opli;
145290792Sgshapiro        }
145390792Sgshapiro        return;
145464562Sgshapiro
145538032Spetertrunc:
145638032Speter	nd_print_trunc(ndo);
145738032Speter}
145864562Sgshapiro
145964562Sgshapirostatic void
146038032Speterisis_print_mcid(netdissect_options *ndo,
146138032Speter                const struct isis_spb_mcid *mcid)
146290792Sgshapiro{
146338032Speter  int i;
146438032Speter
146590792Sgshapiro  ND_TCHECK_SIZE(mcid);
146690792Sgshapiro  ND_PRINT("ID: %u, Name: ", GET_U_1(mcid->format_id));
146790792Sgshapiro
146890792Sgshapiro  nd_printjnp(ndo, mcid->name, sizeof(mcid->name));
146990792Sgshapiro
147090792Sgshapiro  ND_PRINT("\n\t              Lvl: %u", GET_BE_U_2(mcid->revision_lvl));
147190792Sgshapiro
147290792Sgshapiro  ND_PRINT(", Digest: ");
147390792Sgshapiro
147490792Sgshapiro  for(i=0;i<16;i++)
147590792Sgshapiro    ND_PRINT("%.2x ", mcid->digest[i]);
147690792Sgshapiro  return;
147790792Sgshapiro
147890792Sgshapirotrunc:
147990792Sgshapiro  nd_print_trunc(ndo);
148090792Sgshapiro}
148190792Sgshapiro
148290792Sgshapirostatic int
148390792Sgshapiroisis_print_mt_port_cap_subtlv(netdissect_options *ndo,
148490792Sgshapiro                              const uint8_t *tptr, u_int len)
148590792Sgshapiro{
148690792Sgshapiro  u_int stlv_type, stlv_len;
148790792Sgshapiro  const struct isis_subtlv_spb_mcid *subtlv_spb_mcid;
148890792Sgshapiro  int i;
148990792Sgshapiro
149090792Sgshapiro  while (len > 2)
149190792Sgshapiro  {
149290792Sgshapiro    stlv_type = GET_U_1(tptr);
149390792Sgshapiro    stlv_len  = GET_U_1(tptr + 1);
149464562Sgshapiro
149564562Sgshapiro    /* first lets see if we know the subTLVs name*/
149690792Sgshapiro    ND_PRINT("\n\t       %s subTLV #%u, length: %u",
149790792Sgshapiro               tok2str(isis_mt_port_cap_subtlv_values, "unknown", stlv_type),
149890792Sgshapiro               stlv_type,
149990792Sgshapiro               stlv_len);
150090792Sgshapiro
150190792Sgshapiro    tptr += 2;
150290792Sgshapiro    /*len -= TLV_TYPE_LEN_OFFSET;*/
150390792Sgshapiro    len -= 2;
150464562Sgshapiro
150564562Sgshapiro    /* Make sure the subTLV fits within the space left */
150638032Speter    if (len < stlv_len)
150738032Speter      goto subtlv_too_long;
150838032Speter    /* Make sure the entire subTLV is in the captured data */
150990792Sgshapiro    ND_TCHECK_LEN(tptr, stlv_len);
151090792Sgshapiro
151138032Speter    switch (stlv_type)
151238032Speter    {
151338032Speter      case ISIS_SUBTLV_SPB_MCID:
151438032Speter      {
151590792Sgshapiro	if (stlv_len < ISIS_SUBTLV_SPB_MCID_MIN_LEN)
151638032Speter          goto subtlv_too_short;
151790792Sgshapiro
151890792Sgshapiro        subtlv_spb_mcid = (const struct isis_subtlv_spb_mcid *)tptr;
151990792Sgshapiro
152038032Speter        ND_PRINT("\n\t         MCID: ");
152138032Speter        isis_print_mcid(ndo, &(subtlv_spb_mcid->mcid));
152238032Speter
152390792Sgshapiro          /*tptr += SPB_MCID_MIN_LEN;
152490792Sgshapiro            len -= SPB_MCID_MIN_LEN; */
152538032Speter
152638032Speter        ND_PRINT("\n\t         AUX-MCID: ");
152738032Speter        isis_print_mcid(ndo, &(subtlv_spb_mcid->aux_mcid));
152838032Speter
152938032Speter          /*tptr += SPB_MCID_MIN_LEN;
153038032Speter            len -= SPB_MCID_MIN_LEN; */
153138032Speter        tptr += ISIS_SUBTLV_SPB_MCID_MIN_LEN;
153238032Speter        len -= ISIS_SUBTLV_SPB_MCID_MIN_LEN;
153366494Sgshapiro        stlv_len -= ISIS_SUBTLV_SPB_MCID_MIN_LEN;
153438032Speter
153538032Speter        break;
153666494Sgshapiro      }
153766494Sgshapiro
153838032Speter      case ISIS_SUBTLV_SPB_DIGEST:
153938032Speter      {
154038032Speter        if (stlv_len < ISIS_SUBTLV_SPB_DIGEST_MIN_LEN)
154138032Speter          goto subtlv_too_short;
154238032Speter
154338032Speter        ND_PRINT("\n\t        RES: %u V: %u A: %u D: %u",
154490792Sgshapiro                        (GET_U_1(tptr) >> 5),
154564562Sgshapiro                        ((GET_U_1(tptr) >> 4) & 0x01),
154664562Sgshapiro                        ((GET_U_1(tptr) >> 2) & 0x03),
154764562Sgshapiro                        (GET_U_1(tptr) & 0x03));
154864562Sgshapiro
154990792Sgshapiro        tptr++;
155064562Sgshapiro
155190792Sgshapiro        ND_PRINT("\n\t         Digest: ");
155238032Speter
155338032Speter        for(i=1;i<=8; i++)
155473188Sgshapiro        {
155590792Sgshapiro            ND_PRINT("%08x ", GET_BE_U_4(tptr));
155638032Speter            if (i%4 == 0 && i != 8)
155738032Speter              ND_PRINT("\n\t                 ");
155890792Sgshapiro            tptr += 4;
155990792Sgshapiro        }
156090792Sgshapiro
156164562Sgshapiro        len -= ISIS_SUBTLV_SPB_DIGEST_MIN_LEN;
1562102528Sgshapiro        stlv_len -= ISIS_SUBTLV_SPB_DIGEST_MIN_LEN;
1563102528Sgshapiro
156438032Speter        break;
156538032Speter      }
156642575Speter
156742575Speter      case ISIS_SUBTLV_SPB_BVID:
156864562Sgshapiro      {
156942575Speter        while (stlv_len != 0)
157090792Sgshapiro        {
157164562Sgshapiro          if (stlv_len < 4)
157238032Speter            goto subtlv_too_short;
157338032Speter          ND_PRINT("\n\t           ECT: %08x",
157438032Speter                      GET_BE_U_4(tptr));
157564562Sgshapiro
157664562Sgshapiro          tptr += 4;
157790792Sgshapiro          len -= 4;
157838032Speter          stlv_len -= 4;
157938032Speter
158090792Sgshapiro          if (stlv_len < 2)
158190792Sgshapiro            goto subtlv_too_short;
158290792Sgshapiro          ND_PRINT(" BVID: %u, U:%01x M:%01x ",
158390792Sgshapiro                     (GET_BE_U_2(tptr) >> 4) ,
158490792Sgshapiro                     (GET_BE_U_2(tptr) >> 3) & 0x01,
158590792Sgshapiro                     (GET_BE_U_2(tptr) >> 2) & 0x01);
158690792Sgshapiro
158790792Sgshapiro          tptr += 2;
158890792Sgshapiro          len -= 2;
158990792Sgshapiro          stlv_len -= 2;
159090792Sgshapiro        }
159190792Sgshapiro
159290792Sgshapiro        break;
159390792Sgshapiro      }
159442575Speter
159542575Speter      default:
159642575Speter        break;
159742575Speter    }
159890792Sgshapiro    tptr += stlv_len;
159990792Sgshapiro    len -= stlv_len;
160042575Speter  }
160138032Speter  return (0);
160264562Sgshapiro
160364562Sgshapirotrunc:
160464562Sgshapiro  nd_print_trunc(ndo);
160564562Sgshapiro  return (1);
160642575Speter
160742575Spetersubtlv_too_long:
160864562Sgshapiro  ND_PRINT(" (> containing TLV length)");
160964562Sgshapiro  return (1);
161064562Sgshapiro
161142575Spetersubtlv_too_short:
161264562Sgshapiro  ND_PRINT(" (too short)");
161342575Speter  return (1);
161442575Speter}
161542575Speter
161642575Speterstatic int
161738032Speterisis_print_mt_capability_subtlv(netdissect_options *ndo,
161838032Speter                                const uint8_t *tptr, u_int len)
161938032Speter{
162038032Speter  u_int stlv_type, stlv_len, treecount;
162138032Speter
162238032Speter  while (len > 2)
162338032Speter  {
162438032Speter    stlv_type = GET_U_1(tptr);
162538032Speter    stlv_len  = GET_U_1(tptr + 1);
162638032Speter    tptr += 2;
1627110560Sgshapiro    len -= 2;
1628110560Sgshapiro
1629110560Sgshapiro    /* first lets see if we know the subTLVs name*/
1630110560Sgshapiro    ND_PRINT("\n\t      %s subTLV #%u, length: %u",
1631110560Sgshapiro               tok2str(isis_mt_capability_subtlv_values, "unknown", stlv_type),
1632110560Sgshapiro               stlv_type,
163338032Speter               stlv_len);
1634110560Sgshapiro
1635110560Sgshapiro    /* Make sure the subTLV fits within the space left */
1636110560Sgshapiro    if (len < stlv_len)
1637110560Sgshapiro      goto subtlv_too_long;
163838032Speter    /* Make sure the entire subTLV is in the captured data */
163938032Speter    ND_TCHECK_LEN(tptr, stlv_len);
164038032Speter
164138032Speter    switch (stlv_type)
164238032Speter    {
164338032Speter      case ISIS_SUBTLV_SPB_INSTANCE:
164438032Speter          if (stlv_len < ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN)
164538032Speter            goto subtlv_too_short;
164638032Speter
164738032Speter          ND_PRINT("\n\t        CIST Root-ID: %08x", GET_BE_U_4(tptr));
164838032Speter          tptr += 4;
164938032Speter          ND_PRINT(" %08x", GET_BE_U_4(tptr));
165038032Speter          tptr += 4;
165164562Sgshapiro          ND_PRINT(", Path Cost: %08x", GET_BE_U_4(tptr));
165238032Speter          tptr += 4;
165338032Speter          ND_PRINT(", Prio: %u", GET_BE_U_2(tptr));
165438032Speter          tptr += 2;
165538032Speter          ND_PRINT("\n\t        RES: %u",
165638032Speter                    GET_BE_U_2(tptr) >> 5);
165738032Speter          ND_PRINT(", V: %u",
165838032Speter                    (GET_BE_U_2(tptr) >> 4) & 0x0001);
165938032Speter          ND_PRINT(", SPSource-ID: %u",
166038032Speter                    (GET_BE_U_4(tptr) & 0x000fffff));
166138032Speter          tptr += 4;
166238032Speter          ND_PRINT(", No of Trees: %x", GET_U_1(tptr));
166338032Speter
166490792Sgshapiro          treecount = GET_U_1(tptr);
166538032Speter          tptr++;
166638032Speter
166738032Speter          len -= ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN;
166890792Sgshapiro          stlv_len -= ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN;
166938032Speter
167038032Speter          while (treecount)
167138032Speter          {
167238032Speter            if (stlv_len < ISIS_SUBTLV_SPB_INSTANCE_VLAN_TUPLE_LEN)
167338032Speter              goto trunc;
167438032Speter
167538032Speter            ND_PRINT("\n\t         U:%u, M:%u, A:%u, RES:%u",
167638032Speter                      GET_U_1(tptr) >> 7,
167738032Speter                      (GET_U_1(tptr) >> 6) & 0x01,
167864562Sgshapiro                      (GET_U_1(tptr) >> 5) & 0x01,
167990792Sgshapiro                      (GET_U_1(tptr) & 0x1f));
168090792Sgshapiro
168138032Speter            tptr++;
168238032Speter
168338032Speter            ND_PRINT(", ECT: %08x", GET_BE_U_4(tptr));
168464562Sgshapiro
168538032Speter            tptr += 4;
168638032Speter
168738032Speter            ND_PRINT(", BVID: %u, SPVID: %u",
168838032Speter                      (GET_BE_U_3(tptr) >> 12) & 0x000fff,
168938032Speter                      GET_BE_U_3(tptr) & 0x000fff);
169090792Sgshapiro
169190792Sgshapiro            tptr += 3;
169290792Sgshapiro            len -= ISIS_SUBTLV_SPB_INSTANCE_VLAN_TUPLE_LEN;
169390792Sgshapiro            stlv_len -= ISIS_SUBTLV_SPB_INSTANCE_VLAN_TUPLE_LEN;
169438032Speter            treecount--;
169538032Speter          }
169638032Speter
169790792Sgshapiro          break;
169838032Speter
169938032Speter      case ISIS_SUBTLV_SPBM_SI:
170038032Speter          if (stlv_len < 8)
170138032Speter            goto trunc;
170238032Speter
170338032Speter          ND_PRINT("\n\t        BMAC: %08x", GET_BE_U_4(tptr));
170438032Speter          tptr += 4;
170538032Speter          ND_PRINT("%04x", GET_BE_U_2(tptr));
170638032Speter          tptr += 2;
170738032Speter
170838032Speter          ND_PRINT(", RES: %u, VID: %u", GET_BE_U_2(tptr) >> 12,
170964562Sgshapiro                    (GET_BE_U_2(tptr)) & 0x0fff);
171064562Sgshapiro
171190792Sgshapiro          tptr += 2;
171238032Speter          len -= 8;
171338032Speter          stlv_len -= 8;
171438032Speter
171590792Sgshapiro          while (stlv_len >= 4) {
171638032Speter            ND_PRINT("\n\t        T: %u, R: %u, RES: %u, ISID: %u",
171764562Sgshapiro                    (GET_BE_U_4(tptr) >> 31),
171864562Sgshapiro                    (GET_BE_U_4(tptr) >> 30) & 0x01,
171964562Sgshapiro                    (GET_BE_U_4(tptr) >> 24) & 0x03f,
172064562Sgshapiro                    (GET_BE_U_4(tptr)) & 0x0ffffff);
172164562Sgshapiro
172264562Sgshapiro            tptr += 4;
172364562Sgshapiro            len -= 4;
172490792Sgshapiro            stlv_len -= 4;
172590792Sgshapiro          }
172664562Sgshapiro
172790792Sgshapiro        break;
172890792Sgshapiro
172964562Sgshapiro      default:
173090792Sgshapiro        break;
173190792Sgshapiro    }
173264562Sgshapiro    tptr += stlv_len;
173364562Sgshapiro    len -= stlv_len;
173464562Sgshapiro  }
173590792Sgshapiro  return (0);
173690792Sgshapiro
173764562Sgshapirotrunc:
173864562Sgshapiro  nd_print_trunc(ndo);
173964562Sgshapiro  return (1);
174090792Sgshapiro
174190792Sgshapirosubtlv_too_long:
174264562Sgshapiro  ND_PRINT(" (> containing TLV length)");
174364562Sgshapiro  return (1);
174490792Sgshapiro
174590792Sgshapirosubtlv_too_short:
174664562Sgshapiro  ND_PRINT(" (too short)");
174738032Speter  return (1);
174838032Speter}
174938032Speter
175038032Speter/* shared routine for printing system, node and lsp-ids */
175138032Speterstatic char *
175238032Speterisis_print_id(netdissect_options *ndo, const uint8_t *cp, u_int id_len)
175338032Speter{
175490792Sgshapiro    u_int i;
175538032Speter    static char id[sizeof("xxxx.xxxx.xxxx.yy-zz")];
175638032Speter    char *pos = id;
175738032Speter    u_int sysid_len;
175838032Speter
175938032Speter    sysid_len = SYSTEM_ID_LEN;
176038032Speter    if (sysid_len > id_len)
176138032Speter        sysid_len = id_len;
176238032Speter    for (i = 1; i <= sysid_len; i++) {
176338032Speter        snprintf(pos, sizeof(id) - (pos - id), "%02x", GET_U_1(cp));
176464562Sgshapiro	cp++;
176538032Speter	pos += strlen(pos);
176690792Sgshapiro	if (i == 2 || i == 4)
176790792Sgshapiro	    *pos++ = '.';
176838032Speter	}
176938032Speter    if (id_len >= NODE_ID_LEN) {
177038032Speter        snprintf(pos, sizeof(id) - (pos - id), ".%02x", GET_U_1(cp));
177190792Sgshapiro	cp++;
177290792Sgshapiro	pos += strlen(pos);
177390792Sgshapiro    }
177490792Sgshapiro    if (id_len == LSP_ID_LEN)
177590792Sgshapiro        snprintf(pos, sizeof(id) - (pos - id), "-%02x", GET_U_1(cp));
177690792Sgshapiro    return (id);
177764562Sgshapiro}
177890792Sgshapiro
177990792Sgshapiro/* print the 4-byte metric block which is common found in the old-style TLVs */
178090792Sgshapirostatic int
178164562Sgshapiroisis_print_metric_block(netdissect_options *ndo,
178290792Sgshapiro                        const struct isis_metric_block *isis_metric_block)
178390792Sgshapiro{
178490792Sgshapiro    ND_PRINT(", Default Metric: %u, %s",
178590792Sgshapiro           ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_default),
178690792Sgshapiro           ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_default) ? "External" : "Internal");
178790792Sgshapiro    if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_delay))
178890792Sgshapiro        ND_PRINT("\n\t\t  Delay Metric: %u, %s",
178990792Sgshapiro               ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_delay),
179038032Speter               ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_delay) ? "External" : "Internal");
179138032Speter    if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_expense))
179238032Speter        ND_PRINT("\n\t\t  Expense Metric: %u, %s",
179338032Speter               ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_expense),
179438032Speter               ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_expense) ? "External" : "Internal");
179538032Speter    if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_error))
179690792Sgshapiro        ND_PRINT("\n\t\t  Error Metric: %u, %s",
179738032Speter               ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_error),
179890792Sgshapiro               ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_error) ? "External" : "Internal");
179990792Sgshapiro
180090792Sgshapiro    return(1); /* everything is ok */
180190792Sgshapiro}
180290792Sgshapiro
180390792Sgshapirostatic int
180490792Sgshapiroisis_print_tlv_ip_reach(netdissect_options *ndo,
180590792Sgshapiro                        const uint8_t *cp, const char *ident, u_int length)
180638032Speter{
180738032Speter	int prefix_len;
180838032Speter	const struct isis_tlv_ip_reach *tlv_ip_reach;
180938032Speter
181038032Speter	tlv_ip_reach = (const struct isis_tlv_ip_reach *)cp;
181138032Speter
181238032Speter	while (length > 0) {
181338032Speter		if ((size_t)length < sizeof(*tlv_ip_reach)) {
181438032Speter			ND_PRINT("short IPv4 Reachability (%u vs %zu)",
181538032Speter                               length,
181638032Speter                               sizeof(*tlv_ip_reach));
181764562Sgshapiro			return (0);
181838032Speter		}
181938032Speter
182038032Speter		ND_TCHECK_SIZE(tlv_ip_reach);
182138032Speter
182238032Speter		prefix_len = mask2plen(GET_IPV4_TO_HOST_ORDER(tlv_ip_reach->mask));
182338032Speter
182438032Speter		if (prefix_len == -1)
182564562Sgshapiro			ND_PRINT("%sIPv4 prefix: %s mask %s",
182638032Speter                               ident,
182738032Speter			       GET_IPADDR_STRING(tlv_ip_reach->prefix),
182838032Speter			       GET_IPADDR_STRING(tlv_ip_reach->mask));
182990792Sgshapiro		else
183038032Speter			ND_PRINT("%sIPv4 prefix: %15s/%u",
183138032Speter                               ident,
183238032Speter			       GET_IPADDR_STRING(tlv_ip_reach->prefix),
183373188Sgshapiro			       prefix_len);
183438032Speter
183538032Speter		ND_PRINT(", Distribution: %s, Metric: %u, %s",
183638032Speter                       ISIS_LSP_TLV_METRIC_UPDOWN(tlv_ip_reach->isis_metric_block.metric_default) ? "down" : "up",
183738032Speter                       ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_default),
183838032Speter                       ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_default) ? "External" : "Internal");
183938032Speter
184038032Speter		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_delay))
184138032Speter                    ND_PRINT("%s  Delay Metric: %u, %s",
184238032Speter                           ident,
184338032Speter                           ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_delay),
184438032Speter                           ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_delay) ? "External" : "Internal");
184538032Speter
184638032Speter		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_expense))
184738032Speter                    ND_PRINT("%s  Expense Metric: %u, %s",
184838032Speter                           ident,
184938032Speter                           ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_expense),
185038032Speter                           ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_expense) ? "External" : "Internal");
185138032Speter
185238032Speter		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_error))
185338032Speter                    ND_PRINT("%s  Error Metric: %u, %s",
185490792Sgshapiro                           ident,
185590792Sgshapiro                           ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_error),
185690792Sgshapiro                           ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_error) ? "External" : "Internal");
185738032Speter
185838032Speter		length -= sizeof(struct isis_tlv_ip_reach);
185964562Sgshapiro		tlv_ip_reach++;
186038032Speter	}
186138032Speter	return (1);
186238032Spetertrunc:
186338032Speter	return 0;
186438032Speter}
186538032Speter
186638032Speter/*
186764562Sgshapiro * this is the common IP-REACH subTLV decoder it is called
186838032Speter * from various EXTD-IP REACH TLVs (135,235,236,237)
186964562Sgshapiro */
187064562Sgshapiro
187190792Sgshapirostatic int
187238032Speterisis_print_ip_reach_subtlv(netdissect_options *ndo,
187338032Speter                           const uint8_t *tptr, u_int subt, u_int subl,
187438032Speter                           const char *ident)
187538032Speter{
187638032Speter    /* first lets see if we know the subTLVs name*/
187738032Speter    ND_PRINT("%s%s subTLV #%u, length: %u",
187838032Speter              ident, tok2str(isis_ext_ip_reach_subtlv_values, "unknown", subt),
187938032Speter              subt, subl);
188038032Speter
188138032Speter    ND_TCHECK_LEN(tptr, subl);
188290792Sgshapiro
188390792Sgshapiro    switch(subt) {
188490792Sgshapiro    case ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR: /* fall through */
188590792Sgshapiro    case ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32:
188690792Sgshapiro        while (subl >= 4) {
188790792Sgshapiro	    ND_PRINT(", 0x%08x (=%u)",
188890792Sgshapiro		   GET_BE_U_4(tptr),
188990792Sgshapiro		   GET_BE_U_4(tptr));
189090792Sgshapiro	    tptr+=4;
189190792Sgshapiro	    subl-=4;
189290792Sgshapiro	}
189390792Sgshapiro	break;
189490792Sgshapiro    case ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64:
189590792Sgshapiro        while (subl >= 8) {
189690792Sgshapiro	    ND_PRINT(", 0x%08x%08x",
189790792Sgshapiro		   GET_BE_U_4(tptr),
189890792Sgshapiro		   GET_BE_U_4(tptr + 4));
189990792Sgshapiro	    tptr+=8;
190090792Sgshapiro	    subl-=8;
190190792Sgshapiro	}
190290792Sgshapiro	break;
190390792Sgshapiro    case ISIS_SUBTLV_EXTD_IP_REACH_PREFIX_SID:
190490792Sgshapiro	{
190590792Sgshapiro	    uint8_t algo, flags;
190690792Sgshapiro	    uint32_t sid;
190790792Sgshapiro
190890792Sgshapiro	    flags = GET_U_1(tptr);
190990792Sgshapiro	    algo = GET_U_1(tptr+1);
191090792Sgshapiro
191190792Sgshapiro	    if (flags & ISIS_PREFIX_SID_FLAG_V) {
191290792Sgshapiro	        if (subl < 5)
191390792Sgshapiro	            goto trunc;
191490792Sgshapiro		sid = GET_BE_U_3(tptr+2);
191590792Sgshapiro		tptr+=5;
191690792Sgshapiro		subl-=5;
191790792Sgshapiro	    } else {
191890792Sgshapiro	        if (subl < 6)
191990792Sgshapiro	            goto trunc;
192038032Speter		sid = GET_BE_U_4(tptr+2);
192138032Speter		tptr+=6;
192290792Sgshapiro		subl-=6;
192338032Speter	    }
192490792Sgshapiro
192538032Speter	    ND_PRINT(", Flags [%s], Algo %s (%u), %s %u",
192638032Speter		     bittok2str(prefix_sid_flag_values, "None", flags),
192738032Speter		     tok2str(prefix_sid_algo_values, "Unknown", algo), algo,
192838032Speter		     flags & ISIS_PREFIX_SID_FLAG_V ? "label" : "index",
192938032Speter		     sid);
193064562Sgshapiro	}
193138032Speter	break;
193238032Speter    default:
193338032Speter	if (!print_unknown_data(ndo, tptr, "\n\t\t    ", subl))
193438032Speter	  return(0);
193564562Sgshapiro	break;
193664562Sgshapiro    }
193764562Sgshapiro    return(1);
193864562Sgshapiro
193964562Sgshapirotrunc:
194064562Sgshapiro    nd_print_trunc(ndo);
194164562Sgshapiro    return(0);
194264562Sgshapiro}
194364562Sgshapiro
194464562Sgshapiro/*
194564562Sgshapiro * this is the common IS-REACH decoder it is called
194664562Sgshapiro * from various EXTD-IS REACH style TLVs (22,24,222)
194738032Speter */
194838032Speter
194938032Speterstatic int
195038032Speterisis_print_ext_is_reach(netdissect_options *ndo,
195138032Speter                        const uint8_t *tptr, const char *ident, u_int tlv_type,
195238032Speter                        u_int tlv_remaining)
195338032Speter{
195438032Speter    char ident_buffer[20];
195538032Speter    u_int subtlv_type,subtlv_len,subtlv_sum_len;
195638032Speter    int proc_bytes = 0; /* how many bytes did we process ? */
195764562Sgshapiro    u_int te_class,priority_level,gmpls_switch_cap;
195838032Speter    union { /* int to float conversion buffer for several subTLVs */
195938032Speter        float f;
196038032Speter        uint32_t i;
196164562Sgshapiro    } bw;
196264562Sgshapiro
196364562Sgshapiro    ND_TCHECK_LEN(tptr, NODE_ID_LEN);
196464562Sgshapiro    if (tlv_remaining < NODE_ID_LEN)
196564562Sgshapiro        return(0);
196638032Speter
196790792Sgshapiro    ND_PRINT("%sIS Neighbor: %s", ident, isis_print_id(ndo, tptr, NODE_ID_LEN));
196838032Speter    tptr+=NODE_ID_LEN;
196938032Speter    tlv_remaining-=NODE_ID_LEN;
197064562Sgshapiro    proc_bytes+=NODE_ID_LEN;
197164562Sgshapiro
197264562Sgshapiro    if (tlv_type != ISIS_TLV_IS_ALIAS_ID) { /* the Alias TLV Metric field is implicit 0 */
197338032Speter        ND_TCHECK_3(tptr);
197438032Speter	if (tlv_remaining < 3)
197538032Speter	    return(0);
197638032Speter	ND_PRINT(", Metric: %u", GET_BE_U_3(tptr));
197738032Speter	tptr+=3;
197838032Speter	tlv_remaining-=3;
197964562Sgshapiro	proc_bytes+=3;
198038032Speter    }
198138032Speter
198264562Sgshapiro    ND_TCHECK_1(tptr);
198364562Sgshapiro    if (tlv_remaining < 1)
198490792Sgshapiro        return(0);
198590792Sgshapiro    subtlv_sum_len=GET_U_1(tptr); /* read out subTLV length */
198638032Speter    tptr++;
198764562Sgshapiro    tlv_remaining--;
198838032Speter    proc_bytes++;
198964562Sgshapiro    ND_PRINT(", %ssub-TLVs present",subtlv_sum_len ? "" : "no ");
199064562Sgshapiro    if (subtlv_sum_len) {
199138032Speter        ND_PRINT(" (%u)", subtlv_sum_len);
199238032Speter        /* prepend the indent string */
199364562Sgshapiro        snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
199464562Sgshapiro        ident = ident_buffer;
199538032Speter        while (subtlv_sum_len != 0) {
199664562Sgshapiro            ND_TCHECK_2(tptr);
199764562Sgshapiro            if (tlv_remaining < 2) {
199864562Sgshapiro                ND_PRINT("%sRemaining data in TLV shorter than a subTLV header",ident);
199964562Sgshapiro                proc_bytes += tlv_remaining;
200064562Sgshapiro                break;
200164562Sgshapiro            }
200264562Sgshapiro            if (subtlv_sum_len < 2) {
200364562Sgshapiro                ND_PRINT("%sRemaining data in subTLVs shorter than a subTLV header",ident);
200464562Sgshapiro                proc_bytes += subtlv_sum_len;
200564562Sgshapiro                break;
200664562Sgshapiro            }
200764562Sgshapiro            subtlv_type=GET_U_1(tptr);
200864562Sgshapiro            subtlv_len=GET_U_1(tptr + 1);
200964562Sgshapiro            tptr += 2;
201064562Sgshapiro            tlv_remaining -= 2;
201190792Sgshapiro            subtlv_sum_len -= 2;
201290792Sgshapiro            proc_bytes += 2;
201390792Sgshapiro            ND_PRINT("%s%s subTLV #%u, length: %u",
201490792Sgshapiro                      ident, tok2str(isis_ext_is_reach_subtlv_values, "unknown", subtlv_type),
201590792Sgshapiro                      subtlv_type, subtlv_len);
201690792Sgshapiro
201790792Sgshapiro            if (subtlv_sum_len < subtlv_len) {
201890792Sgshapiro                ND_PRINT(" (remaining data in subTLVs shorter than the current subTLV)");
201990792Sgshapiro                proc_bytes += subtlv_sum_len;
202090792Sgshapiro                break;
202190792Sgshapiro            }
202290792Sgshapiro
202390792Sgshapiro            if (tlv_remaining < subtlv_len) {
202490792Sgshapiro                ND_PRINT(" (> remaining tlv length)");
202590792Sgshapiro                proc_bytes += tlv_remaining;
202690792Sgshapiro                break;
202790792Sgshapiro            }
202890792Sgshapiro
202964562Sgshapiro            ND_TCHECK_LEN(tptr, subtlv_len);
203064562Sgshapiro
203138032Speter            switch(subtlv_type) {
203264562Sgshapiro            case ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP:
203364562Sgshapiro            case ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID:
203464562Sgshapiro            case ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID:
203538032Speter                if (subtlv_len >= 4) {
203638032Speter                    ND_PRINT(", 0x%08x", GET_BE_U_4(tptr));
203790792Sgshapiro                    if (subtlv_len == 8) /* rfc4205 */
203890792Sgshapiro                        ND_PRINT(", 0x%08x", GET_BE_U_4(tptr + 4));
203964562Sgshapiro                }
204064562Sgshapiro                break;
204164562Sgshapiro            case ISIS_SUBTLV_EXT_IS_REACH_IPV4_INTF_ADDR:
204238032Speter            case ISIS_SUBTLV_EXT_IS_REACH_IPV4_NEIGHBOR_ADDR:
204338032Speter                if (subtlv_len >= sizeof(nd_ipv4))
204438032Speter                    ND_PRINT(", %s", GET_IPADDR_STRING(tptr));
204538032Speter                break;
204638032Speter            case ISIS_SUBTLV_EXT_IS_REACH_MAX_LINK_BW :
204738032Speter            case ISIS_SUBTLV_EXT_IS_REACH_RESERVABLE_BW:
204890792Sgshapiro                if (subtlv_len >= 4) {
204990792Sgshapiro                    bw.i = GET_BE_U_4(tptr);
205038032Speter                    ND_PRINT(", %.3f Mbps", bw.f * 8 / 1000000);
205138032Speter                }
205290792Sgshapiro                break;
205390792Sgshapiro            case ISIS_SUBTLV_EXT_IS_REACH_UNRESERVED_BW :
205438032Speter                if (subtlv_len >= 32) {
205538032Speter                    for (te_class = 0; te_class < 8; te_class++) {
205690792Sgshapiro                        bw.i = GET_BE_U_4(tptr);
205790792Sgshapiro                        ND_PRINT("%s  TE-Class %u: %.3f Mbps",
205890792Sgshapiro                                  ident,
205990792Sgshapiro                                  te_class,
206090792Sgshapiro                                  bw.f * 8 / 1000000);
206190792Sgshapiro                        tptr += 4;
206290792Sgshapiro                        subtlv_len -= 4;
206390792Sgshapiro                        subtlv_sum_len -= 4;
206464562Sgshapiro                        proc_bytes += 4;
206538032Speter                    }
206638032Speter                }
206738032Speter                break;
206838032Speter            case ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS: /* fall through */
206938032Speter            case ISIS_SUBTLV_EXT_IS_REACH_BW_CONSTRAINTS_OLD:
207038032Speter                if (subtlv_len == 0)
207190792Sgshapiro                    break;
207238032Speter                ND_PRINT("%sBandwidth Constraints Model ID: %s (%u)",
207338032Speter                          ident,
207438032Speter                          tok2str(diffserv_te_bc_values, "unknown", GET_U_1(tptr)),
207538032Speter                          GET_U_1(tptr));
207638032Speter                tptr++;
207738032Speter                subtlv_len--;
207890792Sgshapiro                subtlv_sum_len--;
207938032Speter                proc_bytes++;
208038032Speter                /* decode BCs until the subTLV ends */
208138032Speter                for (te_class = 0; subtlv_len != 0; te_class++) {
208238032Speter                    if (subtlv_len < 4)
208390792Sgshapiro                        break;
208464562Sgshapiro                    bw.i = GET_BE_U_4(tptr);
208564562Sgshapiro                    ND_PRINT("%s  Bandwidth constraint CT%u: %.3f Mbps",
208664562Sgshapiro                              ident,
208764562Sgshapiro                              te_class,
208864562Sgshapiro                              bw.f * 8 / 1000000);
208938032Speter                    tptr += 4;
209064562Sgshapiro                    subtlv_len -= 4;
209190792Sgshapiro                    subtlv_sum_len -= 4;
209264562Sgshapiro                    proc_bytes += 4;
209338032Speter                }
209464562Sgshapiro                break;
209564562Sgshapiro            case ISIS_SUBTLV_EXT_IS_REACH_TE_METRIC:
209664562Sgshapiro                if (subtlv_len >= 3)
209764562Sgshapiro                    ND_PRINT(", %u", GET_BE_U_3(tptr));
209864562Sgshapiro                break;
209964562Sgshapiro            case ISIS_SUBTLV_EXT_IS_REACH_LINK_ATTRIBUTE:
210064562Sgshapiro                if (subtlv_len == 2) {
210164562Sgshapiro                    ND_PRINT(", [ %s ] (0x%04x)",
210264562Sgshapiro                              bittok2str(isis_subtlv_link_attribute_values,
210390792Sgshapiro                                         "Unknown",
210490792Sgshapiro                                         GET_BE_U_2(tptr)),
210564562Sgshapiro                              GET_BE_U_2(tptr));
210677349Sgshapiro                }
210738032Speter                break;
210864562Sgshapiro            case ISIS_SUBTLV_EXT_IS_REACH_LINK_PROTECTION_TYPE:
210938032Speter                if (subtlv_len >= 2) {
211064562Sgshapiro                    ND_PRINT(", %s, Priority %u",
211138032Speter                              bittok2str(gmpls_link_prot_values, "none", GET_U_1(tptr)),
211264562Sgshapiro                              GET_U_1(tptr + 1));
211390792Sgshapiro                }
211490792Sgshapiro                break;
211590792Sgshapiro            case ISIS_SUBTLV_SPB_METRIC:
211690792Sgshapiro                if (subtlv_len >= 6) {
211790792Sgshapiro                    ND_PRINT(", LM: %u", GET_BE_U_3(tptr));
211890792Sgshapiro                    tptr += 3;
211990792Sgshapiro                    subtlv_len -= 3;
212090792Sgshapiro                    subtlv_sum_len -= 3;
212190792Sgshapiro                    proc_bytes += 3;
212290792Sgshapiro                    ND_PRINT(", P: %u", GET_U_1(tptr));
212390792Sgshapiro                    tptr++;
212490792Sgshapiro                    subtlv_len--;
212590792Sgshapiro                    subtlv_sum_len--;
212690792Sgshapiro                    proc_bytes++;
212790792Sgshapiro                    ND_PRINT(", P-ID: %u", GET_BE_U_2(tptr));
212890792Sgshapiro                }
212990792Sgshapiro                break;
213090792Sgshapiro            case ISIS_SUBTLV_EXT_IS_REACH_INTF_SW_CAP_DESCR:
213190792Sgshapiro                if (subtlv_len >= 36) {
213290792Sgshapiro                    gmpls_switch_cap = GET_U_1(tptr);
213390792Sgshapiro                    ND_PRINT("%s  Interface Switching Capability:%s",
213490792Sgshapiro                              ident,
213590792Sgshapiro                              tok2str(gmpls_switch_cap_values, "Unknown", gmpls_switch_cap));
213690792Sgshapiro                    ND_PRINT(", LSP Encoding: %s",
213790792Sgshapiro                              tok2str(gmpls_encoding_values, "Unknown", GET_U_1((tptr + 1))));
213890792Sgshapiro                    tptr += 4;
213990792Sgshapiro                    subtlv_len -= 4;
214090792Sgshapiro                    subtlv_sum_len -= 4;
214190792Sgshapiro                    proc_bytes += 4;
214238032Speter                    ND_PRINT("%s  Max LSP Bandwidth:", ident);
214338032Speter                    for (priority_level = 0; priority_level < 8; priority_level++) {
214490792Sgshapiro                        bw.i = GET_BE_U_4(tptr);
214594334Sgshapiro                        ND_PRINT("%s    priority level %u: %.3f Mbps",
214638032Speter                                  ident,
214738032Speter                                  priority_level,
214838032Speter                                  bw.f * 8 / 1000000);
214990792Sgshapiro                        tptr += 4;
215090792Sgshapiro                        subtlv_len -= 4;
215190792Sgshapiro                        subtlv_sum_len -= 4;
215290792Sgshapiro                        proc_bytes += 4;
215390792Sgshapiro                    }
215438032Speter                    switch (gmpls_switch_cap) {
215538032Speter                    case GMPLS_PSC1:
215638032Speter                    case GMPLS_PSC2:
215738032Speter                    case GMPLS_PSC3:
215864562Sgshapiro                    case GMPLS_PSC4:
215990792Sgshapiro                        if (subtlv_len < 6)
216090792Sgshapiro                            break;
216138032Speter                        bw.i = GET_BE_U_4(tptr);
216290792Sgshapiro                        ND_PRINT("%s  Min LSP Bandwidth: %.3f Mbps", ident, bw.f * 8 / 1000000);
216338032Speter                        ND_PRINT("%s  Interface MTU: %u", ident,
216438032Speter                                 GET_BE_U_2(tptr + 4));
216538032Speter                        break;
216638032Speter                    case GMPLS_TSC:
216738032Speter                        if (subtlv_len < 8)
216838032Speter                            break;
216938032Speter                        bw.i = GET_BE_U_4(tptr);
217038032Speter                        ND_PRINT("%s  Min LSP Bandwidth: %.3f Mbps", ident, bw.f * 8 / 1000000);
217138032Speter                        ND_PRINT("%s  Indication %s", ident,
217238032Speter                                  tok2str(gmpls_switch_cap_tsc_indication_values, "Unknown (%u)", GET_U_1((tptr + 4))));
217338032Speter                        break;
217438032Speter                    default:
217538032Speter                        /* there is some optional stuff left to decode but this is as of yet
217638032Speter                           not specified so just lets hexdump what is left */
217738032Speter                        if (subtlv_len != 0) {
217838032Speter                            if (!print_unknown_data(ndo, tptr, "\n\t\t    ", subtlv_len))
217938032Speter                                return(0);
218038032Speter                        }
218138032Speter                    }
218238032Speter                }
218338032Speter                break;
218438032Speter            case ISIS_SUBTLV_EXT_IS_REACH_LAN_ADJ_SEGMENT_ID:
218538032Speter                if (subtlv_len >= 8) {
218638032Speter                    ND_PRINT("%s  Flags: [%s]", ident,
218738032Speter                              bittok2str(isis_lan_adj_sid_flag_values,
218838032Speter                                         "none",
218938032Speter                                         GET_U_1(tptr)));
219038032Speter                    int vflag = (GET_U_1(tptr) & 0x20) ? 1:0;
219138032Speter                    int lflag = (GET_U_1(tptr) & 0x10) ? 1:0;
219238032Speter                    tptr++;
219338032Speter                    subtlv_len--;
219438032Speter                    subtlv_sum_len--;
219538032Speter                    proc_bytes++;
219664562Sgshapiro                    ND_PRINT("%s  Weight: %u", ident, GET_U_1(tptr));
219738032Speter                    tptr++;
219838032Speter                    subtlv_len--;
219938032Speter                    subtlv_sum_len--;
220038032Speter                    proc_bytes++;
220138032Speter                    if(subtlv_len>=SYSTEM_ID_LEN) {
220238032Speter                        ND_TCHECK_LEN(tptr, SYSTEM_ID_LEN);
220338032Speter                        ND_PRINT("%s  Neighbor System-ID: %s", ident,
220438032Speter                            isis_print_id(ndo, tptr, SYSTEM_ID_LEN));
220538032Speter                    }
220638032Speter                    /* RFC 8667 section 2.2.2 */
220738032Speter                    /* if V-flag is set to 1 and L-flag is set to 1 ==> 3 octet label */
220838032Speter                    /* if V-flag is set to 0 and L-flag is set to 0 ==> 4 octet index */
220938032Speter                    if (vflag && lflag) {
221090792Sgshapiro                        ND_PRINT("%s  Label: %u",
221190792Sgshapiro                                  ident, GET_BE_U_3(tptr+SYSTEM_ID_LEN));
221238032Speter                    } else if ((!vflag) && (!lflag)) {
221390792Sgshapiro                        ND_PRINT("%s  Index: %u",
221490792Sgshapiro                                  ident, GET_BE_U_4(tptr+SYSTEM_ID_LEN));
221590792Sgshapiro                    } else
221690792Sgshapiro                        nd_print_invalid(ndo);
221790792Sgshapiro                }
221838032Speter                break;
221938032Speter            default:
222038032Speter                if (!print_unknown_data(ndo, tptr, "\n\t\t    ", subtlv_len))
222138032Speter                    return(0);
222264562Sgshapiro                break;
222338032Speter            }
222438032Speter
222538032Speter            tptr += subtlv_len;
222638032Speter            tlv_remaining -= subtlv_len;
222738032Speter            subtlv_sum_len -= subtlv_len;
222890792Sgshapiro            proc_bytes += subtlv_len;
222938032Speter        }
223090792Sgshapiro    }
223138032Speter    return(proc_bytes);
223238032Speter
223338032Spetertrunc:
223438032Speter    return(0);
223538032Speter}
223638032Speter
223738032Speter/*
223838032Speter * this is the common Multi Topology ID decoder
223938032Speter * it is called from various MT-TLVs (222,229,235,237)
224090792Sgshapiro */
224190792Sgshapiro
224290792Sgshapirostatic uint8_t
224338032Speterisis_print_mtid(netdissect_options *ndo,
224490792Sgshapiro                const uint8_t *tptr, const char *ident, u_int tlv_remaining)
224538032Speter{
224638032Speter    if (tlv_remaining < 2)
224738032Speter        goto trunc;
224838032Speter
224938032Speter    ND_PRINT("%s%s",
225038032Speter           ident,
225138032Speter           tok2str(isis_mt_values,
225238032Speter                   "Reserved for IETF Consensus",
225338032Speter                   ISIS_MASK_MTID(GET_BE_U_2(tptr))));
225490792Sgshapiro
225590792Sgshapiro    ND_PRINT(" Topology (0x%03x), Flags: [%s]",
225690792Sgshapiro           ISIS_MASK_MTID(GET_BE_U_2(tptr)),
225790792Sgshapiro           bittok2str(isis_mt_flag_values, "none",ISIS_MASK_MTFLAGS(GET_BE_U_2(tptr))));
225838032Speter
225938032Speter    return(2);
226038032Spetertrunc:
226190792Sgshapiro    return 0;
226290792Sgshapiro}
226338032Speter
226438032Speter/*
226590792Sgshapiro * this is the common extended IP reach decoder
226690792Sgshapiro * it is called from TLVs (135,235,236,237)
226790792Sgshapiro * we process the TLV and optional subTLVs and return
226890792Sgshapiro * the amount of processed bytes
226938032Speter */
227064562Sgshapiro
227138032Speterstatic u_int
227264562Sgshapiroisis_print_extd_ip_reach(netdissect_options *ndo,
227364562Sgshapiro                         const uint8_t *tptr, const char *ident, uint16_t afi)
227438032Speter{
227564562Sgshapiro    char ident_buffer[20];
227690792Sgshapiro    uint8_t prefix[sizeof(nd_ipv6)]; /* shared copy buffer for IPv4 and IPv6 prefixes */
227790792Sgshapiro    u_int metric, status_byte, bit_length, byte_length, sublen, processed, subtlvtype, subtlvlen;
227864562Sgshapiro
227964562Sgshapiro    metric = GET_BE_U_4(tptr);
228064562Sgshapiro    processed=4;
228190792Sgshapiro    tptr+=4;
228264562Sgshapiro
228364562Sgshapiro    if (afi == AF_INET) {
228438032Speter        status_byte=GET_U_1(tptr);
228564562Sgshapiro        tptr++;
228664562Sgshapiro        bit_length = status_byte&0x3f;
228764562Sgshapiro        if (bit_length > 32) {
228864562Sgshapiro            ND_PRINT("%sIPv4 prefix: bad bit length %u",
228938032Speter                   ident,
229038032Speter                   bit_length);
229138032Speter            return (0);
229238032Speter        }
229338032Speter        processed++;
229438032Speter    } else if (afi == AF_INET6) {
229564562Sgshapiro        status_byte=GET_U_1(tptr);
229638032Speter        bit_length=GET_U_1(tptr + 1);
229738032Speter        if (bit_length > 128) {
229890792Sgshapiro            ND_PRINT("%sIPv6 prefix: bad bit length %u",
229990792Sgshapiro                   ident,
230090792Sgshapiro                   bit_length);
230190792Sgshapiro            return (0);
230264562Sgshapiro        }
230364562Sgshapiro        tptr+=2;
230438032Speter        processed+=2;
230538032Speter    } else
230664562Sgshapiro        return (0); /* somebody is fooling us */
230738032Speter
230838032Speter    byte_length = (bit_length + 7) / 8; /* prefix has variable length encoding */
230938032Speter
231038032Speter    memset(prefix, 0, sizeof(prefix));   /* clear the copy buffer */
231190792Sgshapiro    GET_CPY_BYTES(prefix,tptr,byte_length);    /* copy as much as is stored in the TLV */
231238032Speter    tptr+=byte_length;
231338032Speter    processed+=byte_length;
231464562Sgshapiro
231564562Sgshapiro    if (afi == AF_INET)
231638032Speter        ND_PRINT("%sIPv4 prefix: %15s/%u",
231790792Sgshapiro               ident,
231838032Speter               ipaddr_string(ndo, prefix), /* local buffer, not packet data; don't use GET_IPADDR_STRING() */
231938032Speter               bit_length);
232038032Speter    else if (afi == AF_INET6)
232138032Speter        ND_PRINT("%sIPv6 prefix: %s/%u",
232238032Speter               ident,
232338032Speter               ip6addr_string(ndo, prefix), /* local buffer, not packet data; don't use GET_IP6ADDR_STRING() */
232464562Sgshapiro               bit_length);
232590792Sgshapiro
232638032Speter    ND_PRINT(", Distribution: %s, Metric: %u",
232738032Speter           ISIS_MASK_TLV_EXTD_IP_UPDOWN(status_byte) ? "down" : "up",
232838032Speter           metric);
232990792Sgshapiro
233038032Speter    if (afi == AF_INET && ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte))
233138032Speter        ND_PRINT(", sub-TLVs present");
233238032Speter    else if (afi == AF_INET6)
233390792Sgshapiro        ND_PRINT(", %s%s",
233490792Sgshapiro               ISIS_MASK_TLV_EXTD_IP6_IE(status_byte) ? "External" : "Internal",
233580785Sgshapiro               ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte) ? ", sub-TLVs present" : "");
233690792Sgshapiro
233780785Sgshapiro    if ((afi == AF_INET  && ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte))
233877349Sgshapiro     || (afi == AF_INET6 && ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte))
233977349Sgshapiro            ) {
234090792Sgshapiro        /* assume that one prefix can hold more
234177349Sgshapiro           than one subTLV - therefore the first byte must reflect
234277349Sgshapiro           the aggregate bytecount of the subTLVs for this prefix
234377349Sgshapiro        */
234438032Speter        sublen=GET_U_1(tptr);
234590792Sgshapiro        tptr++;
234690792Sgshapiro        processed+=sublen+1;
234790792Sgshapiro        ND_PRINT(" (%u)", sublen);   /* print out subTLV length */
234838032Speter
234938032Speter        while (sublen>0) {
235090792Sgshapiro            subtlvtype=GET_U_1(tptr);
235190792Sgshapiro            subtlvlen=GET_U_1(tptr + 1);
235290792Sgshapiro            tptr+=2;
235390792Sgshapiro            /* prepend the indent string */
235490792Sgshapiro            snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
235580785Sgshapiro            if (!isis_print_ip_reach_subtlv(ndo, tptr, subtlvtype, subtlvlen, ident_buffer))
235690792Sgshapiro                return(0);
235780785Sgshapiro            tptr+=subtlvlen;
235838032Speter            sublen-=(subtlvlen+2);
235938032Speter        }
236038032Speter    }
236138032Speter    return (processed);
236264562Sgshapiro}
236338032Speter
236438032Speterstatic void
236538032Speterisis_print_router_cap_subtlv(netdissect_options *ndo, const uint8_t *tptr, uint8_t tlen)
236638032Speter{
236738032Speter    uint8_t subt, subl;
236838032Speter
2369110560Sgshapiro    while (tlen >= 2) {
237038032Speter	subt = GET_U_1(tptr);
237138032Speter	subl = GET_U_1(tptr+1);
237238032Speter	tlen -= 2;
237338032Speter	tptr += 2;
237438032Speter
237538032Speter	/* first lets see if we know the subTLVs name*/
2376110560Sgshapiro	ND_PRINT("\n\t\t%s subTLV #%u, length: %u",
2377110560Sgshapiro              tok2str(isis_router_capability_subtlv_values, "unknown", subt),
2378110560Sgshapiro              subt, subl);
2379110560Sgshapiro
2380102528Sgshapiro	/*
2381102528Sgshapiro	 * Boundary check.
2382110560Sgshapiro	 */
2383102528Sgshapiro	if (subl > tlen) {
2384102528Sgshapiro	    break;
2385102528Sgshapiro	}
2386102528Sgshapiro	ND_TCHECK_LEN(tptr, subl);
2387102528Sgshapiro
238838032Speter	switch (subt) {
238964562Sgshapiro	case ISIS_SUBTLV_ROUTER_CAP_SR:
239038032Speter	    {
239190792Sgshapiro		uint8_t flags, sid_tlen, sid_type, sid_len;
239238032Speter		uint32_t range;
239338032Speter		const uint8_t *sid_ptr;
239464562Sgshapiro
239590792Sgshapiro		flags = GET_U_1(tptr);
239638032Speter		range = GET_BE_U_3(tptr+1);
239738032Speter		ND_PRINT(", Flags [%s], Range %u",
239838032Speter			 bittok2str(isis_router_capability_sr_flags, "None", flags),
239938032Speter			 range);
240038032Speter		sid_ptr = tptr + 4;
240138032Speter		sid_tlen = subl - 4;
240238032Speter
240338032Speter		while (sid_tlen >= 5) {
240438032Speter		    sid_type = GET_U_1(sid_ptr);
240538032Speter		    sid_len = GET_U_1(sid_ptr+1);
240690792Sgshapiro		    sid_tlen -= 2;
240790792Sgshapiro		    sid_ptr += 2;
240890792Sgshapiro
240938032Speter		    /*
241090792Sgshapiro		     * Boundary check.
241190792Sgshapiro		     */
241290792Sgshapiro		    if (sid_len > sid_tlen) {
241364562Sgshapiro			break;
241438032Speter		    }
241590792Sgshapiro
241664562Sgshapiro		    switch (sid_type) {
241764562Sgshapiro		    case 1:
241838032Speter			if (sid_len == 3) {
241938032Speter			    ND_PRINT(", SID value %u", GET_BE_U_3(sid_ptr));
242038032Speter			} else if (sid_len == 4) {
242138032Speter			    ND_PRINT(", SID value %u", GET_BE_U_4(sid_ptr));
242238032Speter			} else {
242338032Speter			    ND_PRINT(", Unknown SID length%u", sid_len);
242490792Sgshapiro			}
242590792Sgshapiro			break;
242664562Sgshapiro		    default:
242738032Speter			print_unknown_data(ndo, sid_ptr, "\n\t\t  ", sid_len);
242864562Sgshapiro		    }
242964562Sgshapiro
243038032Speter		    sid_ptr += sid_len;
243138032Speter		    sid_tlen -= sid_len;
243238032Speter		}
243338032Speter	    }
243438032Speter	    break;
243538032Speter	default:
243638032Speter	    print_unknown_data(ndo, tptr, "\n\t\t", subl);
243790792Sgshapiro	    break;
243890792Sgshapiro	}
243990792Sgshapiro
244064562Sgshapiro	tlen -= subl;
244138032Speter	tptr += subl;
244290792Sgshapiro    }
244364562Sgshapiro trunc:
244464562Sgshapiro    return;
244538032Speter}
244638032Speter
244738032Speter/*
244838032Speter * Clear checksum and lifetime prior to signature verification.
244938032Speter */
245038032Speterstatic void
245190792Sgshapiroisis_clear_checksum_lifetime(void *header)
245290792Sgshapiro{
245364562Sgshapiro    struct isis_lsp_header *header_lsp = (struct isis_lsp_header *) header;
245438032Speter
245564562Sgshapiro    header_lsp->checksum[0] = 0;
245664562Sgshapiro    header_lsp->checksum[1] = 0;
245738032Speter    header_lsp->remaining_lifetime[0] = 0;
245838032Speter    header_lsp->remaining_lifetime[1] = 0;
245938032Speter}
246038032Speter
246138032Speter/*
246238032Speter * isis_print
246364562Sgshapiro * Decode IS-IS packets.  Return 0 on error.
246464562Sgshapiro */
246564562Sgshapiro
246664562Sgshapiro#define INVALID_OR_DECREMENT(length,decr) \
246764562Sgshapiro    if ((length) < (decr)) { \
246864562Sgshapiro        ND_PRINT(" [packet length %u < %zu]", (length), (decr)); \
246964562Sgshapiro        nd_print_invalid(ndo); \
247064562Sgshapiro        return 1; \
247190792Sgshapiro    } \
247290792Sgshapiro    length -= (decr);
247390792Sgshapiro
247464562Sgshapirostatic int
247564562Sgshapiroisis_print(netdissect_options *ndo,
247638032Speter           const uint8_t *p, u_int length)
247764562Sgshapiro{
247864562Sgshapiro    const struct isis_common_header *isis_header;
247964562Sgshapiro
248064562Sgshapiro    const struct isis_iih_lan_header *header_iih_lan;
248164562Sgshapiro    const struct isis_iih_ptp_header *header_iih_ptp;
248264562Sgshapiro    const struct isis_lsp_header *header_lsp;
248364562Sgshapiro    const struct isis_csnp_header *header_csnp;
248464562Sgshapiro    const struct isis_psnp_header *header_psnp;
248564562Sgshapiro
248664562Sgshapiro    const struct isis_tlv_lsp *tlv_lsp;
248764562Sgshapiro    const struct isis_tlv_ptp_adj *tlv_ptp_adj;
248898121Sgshapiro    const struct isis_tlv_is_reach *tlv_is_reach;
248964562Sgshapiro    const struct isis_tlv_es_reach *tlv_es_reach;
249090792Sgshapiro
249198121Sgshapiro    uint8_t version, pdu_version, fixed_len;
249298121Sgshapiro    uint8_t pdu_type, pdu_max_area, max_area, pdu_id_length, id_length, tlv_type, tlv_len, tlen, alen, prefix_len;
249364562Sgshapiro    u_int ext_is_len, ext_ip_len;
249464562Sgshapiro    uint8_t mt_len;
249598121Sgshapiro    uint8_t isis_subtlv_idrp;
249664562Sgshapiro    const uint8_t *optr, *pptr, *tptr;
249764562Sgshapiro    u_int packet_len;
249864562Sgshapiro    u_short pdu_len, key_id;
249964562Sgshapiro    u_int i,vendor_id, num_vals;
250064562Sgshapiro    uint8_t auth_type;
250164562Sgshapiro    uint8_t num_system_ids;
250264562Sgshapiro    int sigcheck;
250364562Sgshapiro
250464562Sgshapiro    ndo->ndo_protocol = "isis";
250538032Speter    packet_len=length;
250638032Speter    optr = p; /* initialize the _o_riginal pointer to the packet start -
250790792Sgshapiro                 need it for parsing the checksum TLV and authentication
250838032Speter                 TLV verification */
250980785Sgshapiro    isis_header = (const struct isis_common_header *)p;
251038032Speter    ND_TCHECK_SIZE(isis_header);
251180785Sgshapiro    if (length < ISIS_COMMON_HEADER_SIZE)
251280785Sgshapiro        goto trunc;
251380785Sgshapiro    pptr = p+(ISIS_COMMON_HEADER_SIZE);
251480785Sgshapiro    header_iih_lan = (const struct isis_iih_lan_header *)pptr;
251580785Sgshapiro    header_iih_ptp = (const struct isis_iih_ptp_header *)pptr;
251680785Sgshapiro    header_lsp = (const struct isis_lsp_header *)pptr;
251780785Sgshapiro    header_csnp = (const struct isis_csnp_header *)pptr;
251880785Sgshapiro    header_psnp = (const struct isis_psnp_header *)pptr;
251980785Sgshapiro
252090792Sgshapiro    if (!ndo->ndo_eflag)
252190792Sgshapiro        ND_PRINT("IS-IS");
252290792Sgshapiro
252390792Sgshapiro    /*
252490792Sgshapiro     * Sanity checking of the header.
252590792Sgshapiro     */
252690792Sgshapiro
252790792Sgshapiro    version = GET_U_1(isis_header->version);
252890792Sgshapiro    if (version != ISIS_VERSION) {
252990792Sgshapiro	ND_PRINT("version %u packet not supported", version);
253090792Sgshapiro	return (0);
253190792Sgshapiro    }
253280785Sgshapiro
253390792Sgshapiro    pdu_id_length = GET_U_1(isis_header->id_length);
253490792Sgshapiro    if ((pdu_id_length != SYSTEM_ID_LEN) && (pdu_id_length != 0)) {
253580785Sgshapiro	ND_PRINT("system ID length of %u is not supported",
253638032Speter	       pdu_id_length);
253738032Speter	return (0);
253838032Speter    }
253938032Speter
254038032Speter    pdu_version = GET_U_1(isis_header->pdu_version);
254138032Speter    if (pdu_version != ISIS_VERSION) {
254238032Speter	ND_PRINT("version %u packet not supported", pdu_version);
254338032Speter	return (0);
254494334Sgshapiro    }
254594334Sgshapiro
254694334Sgshapiro    fixed_len = GET_U_1(isis_header->fixed_len);
254794334Sgshapiro    if (length < fixed_len) {
254894334Sgshapiro	ND_PRINT("fixed header length %u > packet length %u", fixed_len, length);
254994334Sgshapiro	return (0);
255094334Sgshapiro    }
255194334Sgshapiro
255294334Sgshapiro    if (fixed_len < ISIS_COMMON_HEADER_SIZE) {
255394334Sgshapiro	ND_PRINT("fixed header length %u < minimum header size %u", fixed_len, (u_int)ISIS_COMMON_HEADER_SIZE);
255494334Sgshapiro	return (0);
255594334Sgshapiro    }
255694334Sgshapiro
255794334Sgshapiro    pdu_max_area = GET_U_1(isis_header->max_area);
255894334Sgshapiro    switch(pdu_max_area) {
255994334Sgshapiro    case 0:
256038032Speter	max_area = 3;	 /* silly shit */
256138032Speter	break;
256264562Sgshapiro    case 255:
256364562Sgshapiro	ND_PRINT("bad packet -- 255 areas");
256464562Sgshapiro	return (0);
256590792Sgshapiro    default:
256690792Sgshapiro        max_area = pdu_max_area;
256764562Sgshapiro	break;
256864562Sgshapiro    }
256964562Sgshapiro
257038032Speter    switch(pdu_id_length) {
257164562Sgshapiro    case 0:
257238032Speter        id_length = 6;	 /* silly shit again */
257364562Sgshapiro	break;
257438032Speter    case 1:              /* 1-8 are valid sys-ID lengths */
257590792Sgshapiro    case 2:
257664562Sgshapiro    case 3:
257764562Sgshapiro    case 4:
257864562Sgshapiro    case 5:
257964562Sgshapiro    case 6:
258038032Speter    case 7:
258164562Sgshapiro    case 8:
258238032Speter        id_length = pdu_id_length;
258390792Sgshapiro        break;
258464562Sgshapiro    case 255:
258564562Sgshapiro        id_length = 0;   /* entirely useless */
258664562Sgshapiro	break;
258764562Sgshapiro    default:
258838032Speter        id_length = pdu_id_length;
258964562Sgshapiro        break;
259038032Speter    }
259190792Sgshapiro
259264562Sgshapiro    /* toss any non 6-byte sys-ID len PDUs */
259364562Sgshapiro    if (id_length != 6 ) {
259464562Sgshapiro	ND_PRINT("bad packet -- illegal sys-ID length (%u)", id_length);
259538032Speter	return (0);
259638032Speter    }
259738032Speter
259838032Speter    pdu_type = GET_U_1(isis_header->pdu_type);
259938032Speter
260064562Sgshapiro    /* in non-verbose mode print the basic PDU Type plus PDU specific brief information*/
260138032Speter    if (ndo->ndo_vflag == 0) {
260290792Sgshapiro        ND_PRINT("%s%s",
260364562Sgshapiro               ndo->ndo_eflag ? "" : ", ",
260464562Sgshapiro               tok2str(isis_pdu_values, "unknown PDU-Type %u", pdu_type));
260538032Speter    } else {
260638032Speter        /* ok they seem to want to know everything - lets fully decode it */
260738032Speter        ND_PRINT("%slength %u", ndo->ndo_eflag ? "" : ", ", length);
260890792Sgshapiro
260990792Sgshapiro        ND_PRINT("\n\t%s, hlen: %u, v: %u, pdu-v: %u, sys-id-len: %u (%u), max-area: %u (%u)",
261090792Sgshapiro               tok2str(isis_pdu_values,
261138032Speter                       "unknown, type %u",
261238032Speter                       pdu_type),
261338032Speter               fixed_len,
261438032Speter               version,
261538032Speter               pdu_version,
261638032Speter               id_length,
261738032Speter               pdu_id_length,
261838032Speter               max_area,
261938032Speter               pdu_max_area);
262038032Speter
262138032Speter        if (ndo->ndo_vflag > 1) {
262298121Sgshapiro            if (!print_unknown_data(ndo, optr, "\n\t", 8)) /* provide the _o_riginal pointer */
262338032Speter                return (0);                         /* for optionally debugging the common header */
262438032Speter        }
262538032Speter    }
262690792Sgshapiro
262798121Sgshapiro    switch (pdu_type) {
262898121Sgshapiro
262998121Sgshapiro    case ISIS_PDU_L1_LAN_IIH:
263038032Speter    case ISIS_PDU_L2_LAN_IIH:
263138032Speter        if (fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE)) {
263238032Speter            ND_PRINT(", bogus fixed header length %u should be %zu",
263338032Speter                     fixed_len, ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
263490792Sgshapiro            return (0);
263590792Sgshapiro        }
263690792Sgshapiro        ND_TCHECK_SIZE(header_iih_lan);
263790792Sgshapiro        if (length < ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE)
263890792Sgshapiro            goto trunc;
263990792Sgshapiro        if (ndo->ndo_vflag == 0) {
264090792Sgshapiro            ND_PRINT(", src-id %s",
264190792Sgshapiro                      isis_print_id(ndo, header_iih_lan->source_id, SYSTEM_ID_LEN));
264290792Sgshapiro            ND_PRINT(", lan-id %s, prio %u",
264390792Sgshapiro                      isis_print_id(ndo, header_iih_lan->lan_id,NODE_ID_LEN),
264490792Sgshapiro                      GET_U_1(header_iih_lan->priority));
264590792Sgshapiro            ND_PRINT(", length %u", length);
264690792Sgshapiro            return (1);
264790792Sgshapiro        }
264890792Sgshapiro        pdu_len=GET_BE_U_2(header_iih_lan->pdu_len);
264990792Sgshapiro        if (packet_len>pdu_len) {
265090792Sgshapiro           packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
265138032Speter           length=pdu_len;
265264562Sgshapiro        }
265364562Sgshapiro
265438032Speter        ND_PRINT("\n\t  source-id: %s,  holding time: %us, Flags: [%s]",
265564562Sgshapiro                  isis_print_id(ndo, header_iih_lan->source_id,SYSTEM_ID_LEN),
265664562Sgshapiro                  GET_BE_U_2(header_iih_lan->holding_time),
265764562Sgshapiro                  tok2str(isis_iih_circuit_type_values,
265864562Sgshapiro                          "unknown circuit type 0x%02x",
265938032Speter                          GET_U_1(header_iih_lan->circuit_type)));
266064562Sgshapiro
266164562Sgshapiro        ND_PRINT("\n\t  lan-id:    %s, Priority: %u, PDU length: %u",
266238032Speter                  isis_print_id(ndo, header_iih_lan->lan_id, NODE_ID_LEN),
266338032Speter                  GET_U_1(header_iih_lan->priority) & ISIS_LAN_PRIORITY_MASK,
266438032Speter                  pdu_len);
266590792Sgshapiro
266690792Sgshapiro        if (ndo->ndo_vflag > 1) {
266738032Speter            if (!print_unknown_data(ndo, pptr, "\n\t  ", ISIS_IIH_LAN_HEADER_SIZE))
266838032Speter                return (0);
266938032Speter        }
267038032Speter
267138032Speter        INVALID_OR_DECREMENT(packet_len,ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
267238032Speter        pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
267338032Speter        break;
267438032Speter
267590792Sgshapiro    case ISIS_PDU_PTP_IIH:
267690792Sgshapiro        if (fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE)) {
267738032Speter            ND_PRINT(", bogus fixed header length %u should be %zu",
267838032Speter                      fixed_len, ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
267938032Speter            return (0);
268038032Speter        }
268138032Speter        ND_TCHECK_SIZE(header_iih_ptp);
268238032Speter        if (length < ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE)
268338032Speter            goto trunc;
268438032Speter        if (ndo->ndo_vflag == 0) {
268538032Speter            ND_PRINT(", src-id %s", isis_print_id(ndo, header_iih_ptp->source_id, SYSTEM_ID_LEN));
268638032Speter            ND_PRINT(", length %u", length);
268764562Sgshapiro            return (1);
268864562Sgshapiro        }
268938032Speter        pdu_len=GET_BE_U_2(header_iih_ptp->pdu_len);
269038032Speter        if (packet_len>pdu_len) {
269194334Sgshapiro            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
269238032Speter            length=pdu_len;
269338032Speter        }
269494334Sgshapiro
269538032Speter        ND_PRINT("\n\t  source-id: %s, holding time: %us, Flags: [%s]",
269638032Speter                  isis_print_id(ndo, header_iih_ptp->source_id,SYSTEM_ID_LEN),
269764562Sgshapiro                  GET_BE_U_2(header_iih_ptp->holding_time),
269864562Sgshapiro                  tok2str(isis_iih_circuit_type_values,
269964562Sgshapiro                          "unknown circuit type 0x%02x",
270038032Speter                          GET_U_1(header_iih_ptp->circuit_type)));
270138032Speter
270264562Sgshapiro        ND_PRINT("\n\t  circuit-id: 0x%02x, PDU length: %u",
270338032Speter                  GET_U_1(header_iih_ptp->circuit_id),
270438032Speter                  pdu_len);
270538032Speter
270638032Speter        if (ndo->ndo_vflag > 1) {
270738032Speter            if (!print_unknown_data(ndo, pptr, "\n\t  ", ISIS_IIH_PTP_HEADER_SIZE))
270838032Speter                return (0);
270938032Speter        }
271038032Speter        INVALID_OR_DECREMENT(packet_len,ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
271138032Speter        pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
271238032Speter        break;
271390792Sgshapiro
271490792Sgshapiro    case ISIS_PDU_L1_LSP:
271590792Sgshapiro    case ISIS_PDU_L2_LSP:
271690792Sgshapiro        if (fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE)) {
271790792Sgshapiro            ND_PRINT(", bogus fixed header length %u should be %zu",
271890792Sgshapiro                   fixed_len, ISIS_LSP_HEADER_SIZE);
271990792Sgshapiro            return (0);
272090792Sgshapiro        }
272190792Sgshapiro        ND_TCHECK_SIZE(header_lsp);
272290792Sgshapiro        if (length < ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE)
272390792Sgshapiro            goto trunc;
272490792Sgshapiro        if (ndo->ndo_vflag == 0) {
272590792Sgshapiro            ND_PRINT(", lsp-id %s, seq 0x%08x, lifetime %5us",
272690792Sgshapiro                      isis_print_id(ndo, header_lsp->lsp_id, LSP_ID_LEN),
272790792Sgshapiro                      GET_BE_U_4(header_lsp->sequence_number),
272890792Sgshapiro                      GET_BE_U_2(header_lsp->remaining_lifetime));
272990792Sgshapiro            ND_PRINT(", length %u", length);
273090792Sgshapiro            return (1);
273190792Sgshapiro        }
273238032Speter        pdu_len=GET_BE_U_2(header_lsp->pdu_len);
273338032Speter        if (packet_len>pdu_len) {
273438032Speter            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
273538032Speter            length=pdu_len;
273638032Speter        }
273738032Speter
273838032Speter        ND_PRINT("\n\t  lsp-id: %s, seq: 0x%08x, lifetime: %5us\n\t  chksum: 0x%04x",
273938032Speter               isis_print_id(ndo, header_lsp->lsp_id, LSP_ID_LEN),
274038032Speter               GET_BE_U_4(header_lsp->sequence_number),
274138032Speter               GET_BE_U_2(header_lsp->remaining_lifetime),
274238032Speter               GET_BE_U_2(header_lsp->checksum));
274338032Speter
274438032Speter        osi_print_cksum(ndo, (const uint8_t *)header_lsp->lsp_id,
274590792Sgshapiro                        GET_BE_U_2(header_lsp->checksum),
274690792Sgshapiro                        12, length-12);
274790792Sgshapiro
274838032Speter        ND_PRINT(", PDU length: %u, Flags: [ %s",
274938032Speter               pdu_len,
275038032Speter               ISIS_MASK_LSP_OL_BIT(header_lsp->typeblock) ? "Overload bit set, " : "");
275190792Sgshapiro
275238032Speter        if (ISIS_MASK_LSP_ATT_BITS(header_lsp->typeblock)) {
275364562Sgshapiro            ND_PRINT("%s", ISIS_MASK_LSP_ATT_DEFAULT_BIT(header_lsp->typeblock) ? "default " : "");
275464562Sgshapiro            ND_PRINT("%s", ISIS_MASK_LSP_ATT_DELAY_BIT(header_lsp->typeblock) ? "delay " : "");
275538032Speter            ND_PRINT("%s", ISIS_MASK_LSP_ATT_EXPENSE_BIT(header_lsp->typeblock) ? "expense " : "");
275638032Speter            ND_PRINT("%s", ISIS_MASK_LSP_ATT_ERROR_BIT(header_lsp->typeblock) ? "error " : "");
275738032Speter            ND_PRINT("ATT bit set, ");
275864562Sgshapiro        }
275964562Sgshapiro        ND_PRINT("%s", ISIS_MASK_LSP_PARTITION_BIT(header_lsp->typeblock) ? "P bit set, " : "");
276090792Sgshapiro        ND_PRINT("%s ]", tok2str(isis_lsp_istype_values, "Unknown(0x%x)",
276190792Sgshapiro                  ISIS_MASK_LSP_ISTYPE_BITS(header_lsp->typeblock)));
276290792Sgshapiro
276364562Sgshapiro        if (ndo->ndo_vflag > 1) {
276438032Speter            if (!print_unknown_data(ndo, pptr, "\n\t  ", ISIS_LSP_HEADER_SIZE))
276564562Sgshapiro                return (0);
276664562Sgshapiro        }
276764562Sgshapiro
276890792Sgshapiro        INVALID_OR_DECREMENT(packet_len,ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
276964562Sgshapiro        pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
277064562Sgshapiro        break;
277164562Sgshapiro
277238032Speter    case ISIS_PDU_L1_CSNP:
277338032Speter    case ISIS_PDU_L2_CSNP:
277438032Speter        if (fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE)) {
277538032Speter            ND_PRINT(", bogus fixed header length %u should be %zu",
277638032Speter                      fixed_len, ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
277738032Speter            return (0);
277838032Speter        }
277938032Speter        ND_TCHECK_SIZE(header_csnp);
278038032Speter        if (length < ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE)
278138032Speter            goto trunc;
278238032Speter        if (ndo->ndo_vflag == 0) {
278338032Speter            ND_PRINT(", src-id %s", isis_print_id(ndo, header_csnp->source_id, NODE_ID_LEN));
278490792Sgshapiro            ND_PRINT(", length %u", length);
278590792Sgshapiro            return (1);
278690792Sgshapiro        }
278790792Sgshapiro        pdu_len=GET_BE_U_2(header_csnp->pdu_len);
278890792Sgshapiro        if (packet_len>pdu_len) {
278990792Sgshapiro            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
279090792Sgshapiro            length=pdu_len;
279171345Sgshapiro        }
279290792Sgshapiro
279364562Sgshapiro        ND_PRINT("\n\t  source-id:    %s, PDU length: %u",
279471345Sgshapiro               isis_print_id(ndo, header_csnp->source_id, NODE_ID_LEN),
279564562Sgshapiro               pdu_len);
279671345Sgshapiro        ND_PRINT("\n\t  start lsp-id: %s",
279771345Sgshapiro               isis_print_id(ndo, header_csnp->start_lsp_id, LSP_ID_LEN));
279871345Sgshapiro        ND_PRINT("\n\t  end lsp-id:   %s",
279938032Speter               isis_print_id(ndo, header_csnp->end_lsp_id, LSP_ID_LEN));
280090792Sgshapiro
280190792Sgshapiro        if (ndo->ndo_vflag > 1) {
280290792Sgshapiro            if (!print_unknown_data(ndo, pptr, "\n\t  ", ISIS_CSNP_HEADER_SIZE))
280390792Sgshapiro                return (0);
280490792Sgshapiro        }
280590792Sgshapiro
280690792Sgshapiro        INVALID_OR_DECREMENT(packet_len,ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
280790792Sgshapiro        pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
280890792Sgshapiro        break;
280990792Sgshapiro
281090792Sgshapiro    case ISIS_PDU_L1_PSNP:
281190792Sgshapiro    case ISIS_PDU_L2_PSNP:
281290792Sgshapiro        if (fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE)) {
281390792Sgshapiro            ND_PRINT("- bogus fixed header length %u should be %zu",
281490792Sgshapiro                   fixed_len, ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
281590792Sgshapiro            return (0);
281690792Sgshapiro        }
281790792Sgshapiro        ND_TCHECK_SIZE(header_psnp);
281890792Sgshapiro        if (length < ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE)
281990792Sgshapiro            goto trunc;
282090792Sgshapiro        if (ndo->ndo_vflag == 0) {
282190792Sgshapiro            ND_PRINT(", src-id %s", isis_print_id(ndo, header_psnp->source_id, NODE_ID_LEN));
282290792Sgshapiro            ND_PRINT(", length %u", length);
282390792Sgshapiro            return (1);
282471345Sgshapiro        }
282590792Sgshapiro        pdu_len=GET_BE_U_2(header_psnp->pdu_len);
282690792Sgshapiro        if (packet_len>pdu_len) {
282790792Sgshapiro            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
282864562Sgshapiro            length=pdu_len;
282990792Sgshapiro        }
283090792Sgshapiro
283190792Sgshapiro        ND_PRINT("\n\t  source-id:    %s, PDU length: %u",
283290792Sgshapiro               isis_print_id(ndo, header_psnp->source_id, NODE_ID_LEN),
283390792Sgshapiro               pdu_len);
283490792Sgshapiro
283590792Sgshapiro        if (ndo->ndo_vflag > 1) {
283690792Sgshapiro            if (!print_unknown_data(ndo, pptr, "\n\t  ", ISIS_PSNP_HEADER_SIZE))
283790792Sgshapiro                return (0);
283890792Sgshapiro        }
283990792Sgshapiro
284090792Sgshapiro        INVALID_OR_DECREMENT(packet_len,ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
284190792Sgshapiro        pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
284290792Sgshapiro        break;
284390792Sgshapiro
284490792Sgshapiro    default:
284590792Sgshapiro        if (ndo->ndo_vflag == 0) {
284690792Sgshapiro            ND_PRINT(", length %u", length);
284790792Sgshapiro            return (1);
284890792Sgshapiro        }
284990792Sgshapiro	(void)print_unknown_data(ndo, pptr, "\n\t  ", length);
285090792Sgshapiro	return (0);
285190792Sgshapiro    }
285290792Sgshapiro
285390792Sgshapiro    /*
285490792Sgshapiro     * Now print the TLV's.
285590792Sgshapiro     */
285690792Sgshapiro
285790792Sgshapiro    while (packet_len > 0) {
285890792Sgshapiro	ND_TCHECK_2(pptr);
285964562Sgshapiro	if (packet_len < 2)
286064562Sgshapiro	    goto trunc;
286164562Sgshapiro	tlv_type = GET_U_1(pptr);
286271345Sgshapiro	tlv_len = GET_U_1(pptr + 1);
286371345Sgshapiro	pptr += 2;
286464562Sgshapiro	packet_len -= 2;
286590792Sgshapiro        tlen = tlv_len; /* copy temporary len & pointer to packet data */
286690792Sgshapiro        tptr = pptr;
286790792Sgshapiro
286890792Sgshapiro        /* first lets see if we know the TLVs name*/
286990792Sgshapiro	ND_PRINT("\n\t    %s TLV #%u, length: %u",
287090792Sgshapiro               tok2str(isis_tlv_values,
287190792Sgshapiro                       "unknown",
287290792Sgshapiro                       tlv_type),
287390792Sgshapiro               tlv_type,
287490792Sgshapiro               tlv_len);
287590792Sgshapiro
287690792Sgshapiro	if (packet_len < tlv_len)
287790792Sgshapiro	    goto trunc;
287890792Sgshapiro
287990792Sgshapiro        /* now check if we have a decoder otherwise do a hexdump at the end*/
288090792Sgshapiro	switch (tlv_type) {
288190792Sgshapiro	case ISIS_TLV_AREA_ADDR:
288290792Sgshapiro	    while (tlen != 0) {
288390792Sgshapiro		alen = GET_U_1(tptr);
288490792Sgshapiro		tptr++;
288590792Sgshapiro		tlen--;
288690792Sgshapiro		if (tlen < alen)
288790792Sgshapiro		    goto tlv_trunc;
288890792Sgshapiro		ND_PRINT("\n\t      Area address (length: %u): %s",
288990792Sgshapiro                       alen,
289090792Sgshapiro                       GET_ISONSAP_STRING(tptr, alen));
289190792Sgshapiro		tptr += alen;
289290792Sgshapiro		tlen -= alen;
289390792Sgshapiro	    }
289464562Sgshapiro	    break;
289564562Sgshapiro	case ISIS_TLV_ISNEIGH:
289671345Sgshapiro	    while (tlen != 0) {
289771345Sgshapiro		if (tlen < MAC_ADDR_LEN)
289864562Sgshapiro		    goto tlv_trunc;
289964562Sgshapiro                ND_TCHECK_LEN(tptr, MAC_ADDR_LEN);
290064562Sgshapiro                ND_PRINT("\n\t      SNPA: %s", isis_print_id(ndo, tptr, MAC_ADDR_LEN));
290164562Sgshapiro                tlen -= MAC_ADDR_LEN;
290264562Sgshapiro                tptr += MAC_ADDR_LEN;
290371345Sgshapiro	    }
290464562Sgshapiro	    break;
290564562Sgshapiro
290664562Sgshapiro        case ISIS_TLV_INSTANCE_ID:
290790792Sgshapiro            if (tlen < 4)
290890792Sgshapiro                goto tlv_trunc;
290966494Sgshapiro            num_vals = (tlen-2)/2;
291064562Sgshapiro            ND_PRINT("\n\t      Instance ID: %u, ITIDs(%u)%s ",
291164562Sgshapiro                     GET_BE_U_2(tptr), num_vals,
291290792Sgshapiro                     num_vals ? ":" : "");
291364562Sgshapiro            tptr += 2;
291490792Sgshapiro            tlen -= 2;
291590792Sgshapiro            for (i=0; i < num_vals; i++) {
2916102528Sgshapiro                ND_PRINT("%u", GET_BE_U_2(tptr));
2917102528Sgshapiro                if (i < (num_vals - 1)) {
291864562Sgshapiro                   ND_PRINT(", ");
291990792Sgshapiro                }
292064562Sgshapiro                tptr += 2;
292164562Sgshapiro                tlen -= 2;
292264562Sgshapiro            }
292364562Sgshapiro            break;
292464562Sgshapiro
292564562Sgshapiro	case ISIS_TLV_PADDING:
292664562Sgshapiro	    break;
292764562Sgshapiro
292864562Sgshapiro        case ISIS_TLV_MT_IS_REACH:
292964562Sgshapiro            mt_len = isis_print_mtid(ndo, tptr, "\n\t      ", tlen);
293064562Sgshapiro            if (mt_len == 0) /* did something go wrong ? */
293164562Sgshapiro                goto trunc;
293264562Sgshapiro            tptr+=mt_len;
293364562Sgshapiro            tlen-=mt_len;
293464562Sgshapiro            while (tlen != 0) {
293564562Sgshapiro                ext_is_len = isis_print_ext_is_reach(ndo, tptr, "\n\t      ", tlv_type, tlen);
293664562Sgshapiro                if (ext_is_len == 0) /* did something go wrong ? */
293764562Sgshapiro                    goto trunc;
293864562Sgshapiro                if (tlen < ext_is_len) {
293964562Sgshapiro                    ND_PRINT(" [remaining tlv length %u < %u]", tlen, ext_is_len);
294064562Sgshapiro                    nd_print_invalid(ndo);
294190792Sgshapiro                    break;
294264562Sgshapiro                }
294364562Sgshapiro                tlen-=(uint8_t)ext_is_len;
294464562Sgshapiro                tptr+=(uint8_t)ext_is_len;
294564562Sgshapiro            }
294664562Sgshapiro            break;
294764562Sgshapiro
294864562Sgshapiro        case ISIS_TLV_IS_ALIAS_ID:
294964562Sgshapiro	    while (tlen != 0) {
295064562Sgshapiro	        ext_is_len = isis_print_ext_is_reach(ndo, tptr, "\n\t      ", tlv_type, tlen);
295164562Sgshapiro		if (ext_is_len == 0) /* did something go wrong ? */
295264562Sgshapiro	            goto trunc;
295364562Sgshapiro                if (tlen < ext_is_len) {
295464562Sgshapiro                    ND_PRINT(" [remaining tlv length %u < %u]", tlen, ext_is_len);
295564562Sgshapiro                    nd_print_invalid(ndo);
295664562Sgshapiro                    break;
295764562Sgshapiro                }
295864562Sgshapiro		tlen-=(uint8_t)ext_is_len;
295964562Sgshapiro		tptr+=(uint8_t)ext_is_len;
296064562Sgshapiro	    }
296164562Sgshapiro	    break;
296264562Sgshapiro
296390792Sgshapiro        case ISIS_TLV_EXT_IS_REACH:
296490792Sgshapiro            while (tlen != 0) {
296564562Sgshapiro                ext_is_len = isis_print_ext_is_reach(ndo, tptr, "\n\t      ", tlv_type, tlen);
296664562Sgshapiro                if (ext_is_len == 0) /* did something go wrong ? */
296764562Sgshapiro                    goto trunc;
296890792Sgshapiro                if (tlen < ext_is_len) {
296990792Sgshapiro                    ND_PRINT(" [remaining tlv length %u < %u]", tlen, ext_is_len);
297064562Sgshapiro                    nd_print_invalid(ndo);
297190792Sgshapiro                    break;
297290792Sgshapiro                }
297364562Sgshapiro                tlen-=(uint8_t)ext_is_len;
297464562Sgshapiro                tptr+=(uint8_t)ext_is_len;
297564562Sgshapiro            }
297664562Sgshapiro            break;
297764562Sgshapiro        case ISIS_TLV_IS_REACH:
297864562Sgshapiro            if (tlen < 1)
297964562Sgshapiro                goto tlv_trunc;
298064562Sgshapiro            ND_PRINT("\n\t      %s",
298164562Sgshapiro                   tok2str(isis_is_reach_virtual_values,
298290792Sgshapiro                           "bogus virtual flag 0x%02x",
298364562Sgshapiro                           GET_U_1(tptr)));
298490792Sgshapiro	    tptr++;
2985102528Sgshapiro	    tlen--;
2986102528Sgshapiro	    tlv_is_reach = (const struct isis_tlv_is_reach *)tptr;
298764562Sgshapiro            while (tlen != 0) {
298864562Sgshapiro                if (tlen < sizeof(struct isis_tlv_is_reach))
298964562Sgshapiro                    goto tlv_trunc;
299064562Sgshapiro		ND_TCHECK_SIZE(tlv_is_reach);
299164562Sgshapiro		ND_PRINT("\n\t      IS Neighbor: %s",
299264562Sgshapiro		       isis_print_id(ndo, tlv_is_reach->neighbor_nodeid, NODE_ID_LEN));
299364562Sgshapiro		isis_print_metric_block(ndo, &tlv_is_reach->isis_metric_block);
299464562Sgshapiro		tlen -= sizeof(struct isis_tlv_is_reach);
299564562Sgshapiro		tlv_is_reach++;
299690792Sgshapiro	    }
299790792Sgshapiro            break;
299864562Sgshapiro
299964562Sgshapiro        case ISIS_TLV_ESNEIGH:
300064562Sgshapiro	    tlv_es_reach = (const struct isis_tlv_es_reach *)tptr;
300164562Sgshapiro            while (tlen != 0) {
300290792Sgshapiro                if (tlen < sizeof(struct isis_tlv_es_reach))
300390792Sgshapiro                    goto tlv_trunc;
300464562Sgshapiro		ND_TCHECK_SIZE(tlv_es_reach);
300564562Sgshapiro		ND_PRINT("\n\t      ES Neighbor: %s",
300664562Sgshapiro                       isis_print_id(ndo, tlv_es_reach->neighbor_sysid, SYSTEM_ID_LEN));
300764562Sgshapiro		isis_print_metric_block(ndo, &tlv_es_reach->isis_metric_block);
300864562Sgshapiro		tlen -= sizeof(struct isis_tlv_es_reach);
300964562Sgshapiro		tlv_es_reach++;
301064562Sgshapiro	    }
301164562Sgshapiro            break;
301264562Sgshapiro
301364562Sgshapiro            /* those two TLVs share the same format */
301490792Sgshapiro	case ISIS_TLV_INT_IP_REACH:
301590792Sgshapiro	case ISIS_TLV_EXT_IP_REACH:
301664562Sgshapiro		if (!isis_print_tlv_ip_reach(ndo, pptr, "\n\t      ", tlv_len))
301764562Sgshapiro			return (1);
301864562Sgshapiro		break;
301964562Sgshapiro
302064562Sgshapiro	case ISIS_TLV_EXTD_IP_REACH:
302164562Sgshapiro	    while (tlen != 0) {
302264562Sgshapiro                ext_ip_len = isis_print_extd_ip_reach(ndo, tptr, "\n\t      ", AF_INET);
302364562Sgshapiro                if (ext_ip_len == 0) /* did something go wrong ? */
302464562Sgshapiro                    goto trunc;
302564562Sgshapiro                if (tlen < ext_ip_len) {
302664562Sgshapiro                    ND_PRINT(" [remaining tlv length %u < %u]", tlen, ext_ip_len);
302771345Sgshapiro                    nd_print_invalid(ndo);
302871345Sgshapiro                    break;
302971345Sgshapiro                }
303064562Sgshapiro                tlen-=(uint8_t)ext_ip_len;
303164562Sgshapiro                tptr+=(uint8_t)ext_ip_len;
303264562Sgshapiro            }
303390792Sgshapiro            break;
303464562Sgshapiro
303564562Sgshapiro        case ISIS_TLV_MT_IP_REACH:
303664562Sgshapiro            mt_len = isis_print_mtid(ndo, tptr, "\n\t      ", tlen);
303764562Sgshapiro            if (mt_len == 0) { /* did something go wrong ? */
303864562Sgshapiro                goto trunc;
303990792Sgshapiro            }
304090792Sgshapiro            tptr+=mt_len;
304190792Sgshapiro            tlen-=mt_len;
304264562Sgshapiro
304364562Sgshapiro            while (tlen != 0) {
304464562Sgshapiro                ext_ip_len = isis_print_extd_ip_reach(ndo, tptr, "\n\t      ", AF_INET);
304571345Sgshapiro                if (ext_ip_len == 0) /* did something go wrong ? */
304671345Sgshapiro                    goto trunc;
304764562Sgshapiro                if (tlen < ext_ip_len) {
304871345Sgshapiro                    ND_PRINT(" [remaining tlv length %u < %u]", tlen, ext_ip_len);
304964562Sgshapiro                    nd_print_invalid(ndo);
305064562Sgshapiro                    break;
305164562Sgshapiro                }
305264562Sgshapiro                tlen-=(uint8_t)ext_ip_len;
305364562Sgshapiro                tptr+=(uint8_t)ext_ip_len;
305464562Sgshapiro            }
305564562Sgshapiro            break;
305664562Sgshapiro
305764562Sgshapiro	case ISIS_TLV_IP6_REACH:
305890792Sgshapiro            while (tlen != 0) {
305964562Sgshapiro                ext_ip_len = isis_print_extd_ip_reach(ndo, tptr, "\n\t      ", AF_INET6);
306090792Sgshapiro                if (ext_ip_len == 0) /* did something go wrong ? */
306190792Sgshapiro                    goto trunc;
306264562Sgshapiro                if (tlen < ext_ip_len) {
306364562Sgshapiro                    ND_PRINT(" [remaining tlv length %u < %u]", tlen, ext_ip_len);
306490792Sgshapiro                    nd_print_invalid(ndo);
306564562Sgshapiro                    break;
306690792Sgshapiro                }
306764562Sgshapiro                tlen-=(uint8_t)ext_ip_len;
306898121Sgshapiro                tptr+=(uint8_t)ext_ip_len;
306998121Sgshapiro            }
307098121Sgshapiro            break;
307164562Sgshapiro
307298121Sgshapiro	case ISIS_TLV_MT_IP6_REACH:
307390792Sgshapiro            mt_len = isis_print_mtid(ndo, tptr, "\n\t      ", tlen);
307490792Sgshapiro            if (mt_len == 0) { /* did something go wrong ? */
307564562Sgshapiro                goto trunc;
307664562Sgshapiro            }
307790792Sgshapiro            tptr+=mt_len;
307864562Sgshapiro            tlen-=mt_len;
307990792Sgshapiro
308090792Sgshapiro            while (tlen != 0) {
308177349Sgshapiro                ext_ip_len = isis_print_extd_ip_reach(ndo, tptr, "\n\t      ", AF_INET6);
308264562Sgshapiro                if (ext_ip_len == 0) /* did something go wrong ? */
308390792Sgshapiro                    goto trunc;
308464562Sgshapiro                if (tlen < ext_ip_len) {
308564562Sgshapiro                    ND_PRINT(" [remaining tlv length %u < %u]", tlen, ext_ip_len);
308690792Sgshapiro                    nd_print_invalid(ndo);
308764562Sgshapiro                    break;
308864562Sgshapiro                }
308964562Sgshapiro                tlen-=(uint8_t)ext_ip_len;
309090792Sgshapiro                tptr+=(uint8_t)ext_ip_len;
309190792Sgshapiro            }
309290792Sgshapiro            break;
309364562Sgshapiro
309490792Sgshapiro	case ISIS_TLV_IP6ADDR:
309590792Sgshapiro	    while (tlen != 0) {
309690792Sgshapiro                if (tlen < sizeof(nd_ipv6))
309764562Sgshapiro                    goto tlv_trunc;
309864562Sgshapiro                ND_PRINT("\n\t      IPv6 interface address: %s",
309964562Sgshapiro		       GET_IP6ADDR_STRING(tptr));
310090792Sgshapiro
310190792Sgshapiro		tptr += sizeof(nd_ipv6);
310264562Sgshapiro		tlen -= sizeof(nd_ipv6);
310364562Sgshapiro	    }
310490792Sgshapiro	    break;
310564562Sgshapiro	case ISIS_TLV_AUTH:
310664562Sgshapiro	    if (tlen < 1)
310764562Sgshapiro	        goto tlv_trunc;
310864562Sgshapiro	    auth_type = GET_U_1(tptr);
310964562Sgshapiro	    tptr++;
311090792Sgshapiro	    tlen--;
311190792Sgshapiro
311290792Sgshapiro            ND_PRINT("\n\t      %s: ",
311390792Sgshapiro                   tok2str(isis_subtlv_auth_values,
311490792Sgshapiro                           "unknown Authentication type 0x%02x",
311590792Sgshapiro                           auth_type));
311690792Sgshapiro
311790792Sgshapiro	    switch (auth_type) {
311890792Sgshapiro	    case ISIS_SUBTLV_AUTH_SIMPLE:
311990792Sgshapiro		nd_printjnp(ndo, tptr, tlen);
312090792Sgshapiro		break;
312190792Sgshapiro	    case ISIS_SUBTLV_AUTH_MD5:
312290792Sgshapiro		for(i=0;i<tlen;i++) {
312390792Sgshapiro		    ND_PRINT("%02x", GET_U_1(tptr + i));
312490792Sgshapiro		}
312590792Sgshapiro		if (tlen != ISIS_SUBTLV_AUTH_MD5_LEN)
312690792Sgshapiro                    ND_PRINT(", (invalid subTLV) ");
312790792Sgshapiro
312890792Sgshapiro                sigcheck = signature_verify(ndo, optr, length, tptr,
312990792Sgshapiro                                            isis_clear_checksum_lifetime,
313090792Sgshapiro                                            header_lsp);
313190792Sgshapiro                ND_PRINT(" (%s)", tok2str(signature_check_values, "Unknown", sigcheck));
313264562Sgshapiro
313364562Sgshapiro		break;
313438032Speter            case ISIS_SUBTLV_AUTH_GENERIC:
313538032Speter                if (tlen < 2)
313664562Sgshapiro                    goto tlv_trunc;
313738032Speter                key_id = GET_BE_U_2(tptr);
313838032Speter                ND_PRINT("%u, password: ", key_id);
313938032Speter                tptr += 2;
314038032Speter                tlen -= 2;
314138032Speter                for(i=0;i<tlen;i++) {
314238032Speter                    ND_PRINT("%02x", GET_U_1(tptr + i));
314338032Speter                }
314438032Speter                break;
314538032Speter	    case ISIS_SUBTLV_AUTH_PRIVATE:
314638032Speter	    default:
314738032Speter		if (!print_unknown_data(ndo, tptr, "\n\t\t  ", tlen))
314838032Speter		    return(0);
314938032Speter		break;
315090792Sgshapiro	    }
315190792Sgshapiro	    break;
315238032Speter
315338032Speter	case ISIS_TLV_PTP_ADJ:
315438032Speter	    tlv_ptp_adj = (const struct isis_tlv_ptp_adj *)tptr;
315538032Speter	    if(tlen>=1) {
315690792Sgshapiro		ND_PRINT("\n\t      Adjacency State: %s (%u)",
315738032Speter		       tok2str(isis_ptp_adjancey_values, "unknown", GET_U_1(tptr)),
315838032Speter		       GET_U_1(tptr));
315938032Speter		tlen--;
316064562Sgshapiro	    }
316138032Speter	    if(tlen>sizeof(tlv_ptp_adj->extd_local_circuit_id)) {
316238032Speter		ND_PRINT("\n\t      Extended Local circuit-ID: 0x%08x",
316338032Speter		       GET_BE_U_4(tlv_ptp_adj->extd_local_circuit_id));
316490792Sgshapiro		tlen-=sizeof(tlv_ptp_adj->extd_local_circuit_id);
316590792Sgshapiro	    }
316638032Speter	    if(tlen>=SYSTEM_ID_LEN) {
316738032Speter		ND_TCHECK_LEN(tlv_ptp_adj->neighbor_sysid, SYSTEM_ID_LEN);
316890792Sgshapiro		ND_PRINT("\n\t      Neighbor System-ID: %s",
316990792Sgshapiro		       isis_print_id(ndo, tlv_ptp_adj->neighbor_sysid, SYSTEM_ID_LEN));
317090792Sgshapiro		tlen-=SYSTEM_ID_LEN;
317190792Sgshapiro	    }
317290792Sgshapiro	    if(tlen>=sizeof(tlv_ptp_adj->neighbor_extd_local_circuit_id)) {
317390792Sgshapiro		ND_PRINT("\n\t      Neighbor Extended Local circuit-ID: 0x%08x",
317490792Sgshapiro		       GET_BE_U_4(tlv_ptp_adj->neighbor_extd_local_circuit_id));
317590792Sgshapiro	    }
317690792Sgshapiro	    break;
317790792Sgshapiro
317890792Sgshapiro	case ISIS_TLV_PROTOCOLS:
317990792Sgshapiro	    ND_PRINT("\n\t      NLPID(s): ");
318090792Sgshapiro	    while (tlen != 0) {
318190792Sgshapiro		ND_PRINT("%s (0x%02x)",
318290792Sgshapiro                       tok2str(nlpid_values,
318390792Sgshapiro                               "unknown",
318490792Sgshapiro                               GET_U_1(tptr)),
318590792Sgshapiro                       GET_U_1(tptr));
318690792Sgshapiro		if (tlen>1) /* further NPLIDs ? - put comma */
318790792Sgshapiro		    ND_PRINT(", ");
318890792Sgshapiro                tptr++;
318990792Sgshapiro                tlen--;
319090792Sgshapiro	    }
319190792Sgshapiro	    break;
319290792Sgshapiro
319390792Sgshapiro        case ISIS_TLV_MT_PORT_CAP:
319490792Sgshapiro        {
319590792Sgshapiro            if (tlen < 2)
319690792Sgshapiro                goto tlv_trunc;
319790792Sgshapiro
319890792Sgshapiro            ND_PRINT("\n\t       RES: %u, MTID(s): %u",
319938032Speter                    (GET_BE_U_2(tptr) >> 12),
320038032Speter                    (GET_BE_U_2(tptr) & 0x0fff));
320138032Speter
320238032Speter            tptr += 2;
320338032Speter            tlen -= 2;
320473188Sgshapiro
320538032Speter            if (tlen)
320638032Speter                isis_print_mt_port_cap_subtlv(ndo, tptr, tlen);
320738032Speter
320864562Sgshapiro            break;
320990792Sgshapiro        }
321090792Sgshapiro
321190792Sgshapiro        case ISIS_TLV_MT_CAPABILITY:
321238032Speter            if (tlen < 2)
321338032Speter                goto tlv_trunc;
321464562Sgshapiro
321538032Speter            ND_PRINT("\n\t      O: %u, RES: %u, MTID(s): %u",
321638032Speter                      (GET_BE_U_2(tptr) >> 15) & 0x01,
321738032Speter                      (GET_BE_U_2(tptr) >> 12) & 0x07,
321838032Speter                      GET_BE_U_2(tptr) & 0x0fff);
321938032Speter
322038032Speter            tptr += 2;
322138032Speter            tlen -= 2;
322238032Speter
322338032Speter            if (tlen)
322438032Speter                isis_print_mt_capability_subtlv(ndo, tptr, tlen);
322538032Speter
322638032Speter            break;
322743730Speter
322838032Speter	case ISIS_TLV_TE_ROUTER_ID:
322938032Speter	    if (tlen < sizeof(nd_ipv4))
323038032Speter	        goto tlv_trunc;
323138032Speter	    ND_PRINT("\n\t      Traffic Engineering Router ID: %s", GET_IPADDR_STRING(pptr));
323290792Sgshapiro	    break;
323373188Sgshapiro
323473188Sgshapiro	case ISIS_TLV_IPADDR:
323573188Sgshapiro	    while (tlen != 0) {
323673188Sgshapiro                if (tlen < sizeof(nd_ipv4))
323773188Sgshapiro                    goto tlv_trunc;
323873188Sgshapiro		ND_PRINT("\n\t      IPv4 interface address: %s", GET_IPADDR_STRING(tptr));
323990792Sgshapiro		tptr += sizeof(nd_ipv4);
324090792Sgshapiro		tlen -= sizeof(nd_ipv4);
324190792Sgshapiro	    }
324273188Sgshapiro	    break;
324338032Speter
324438032Speter	case ISIS_TLV_HOSTNAME:
324538032Speter	    ND_PRINT("\n\t      Hostname: ");
324638032Speter	    nd_printjnp(ndo, tptr, tlen);
324738032Speter	    break;
324838032Speter
324938032Speter	case ISIS_TLV_SHARED_RISK_GROUP:
325090792Sgshapiro	    if (tlen < NODE_ID_LEN)
325138032Speter	        break;
325238032Speter	    ND_TCHECK_LEN(tptr, NODE_ID_LEN);
325338032Speter	    ND_PRINT("\n\t      IS Neighbor: %s", isis_print_id(ndo, tptr, NODE_ID_LEN));
325438032Speter	    tptr+=NODE_ID_LEN;
325590792Sgshapiro	    tlen-=NODE_ID_LEN;
325690792Sgshapiro
325790792Sgshapiro	    if (tlen < 1)
325838032Speter	        break;
325938032Speter	    ND_PRINT(", Flags: [%s]",
326038032Speter                     ISIS_MASK_TLV_SHARED_RISK_GROUP(GET_U_1(tptr)) ? "numbered" : "unnumbered");
326190792Sgshapiro	    tptr++;
326290792Sgshapiro	    tlen--;
326390792Sgshapiro
326490792Sgshapiro	    if (tlen < sizeof(nd_ipv4))
326590792Sgshapiro	        break;
326690792Sgshapiro	    ND_PRINT("\n\t      IPv4 interface address: %s", GET_IPADDR_STRING(tptr));
326764562Sgshapiro	    tptr+=sizeof(nd_ipv4);
326838032Speter	    tlen-=sizeof(nd_ipv4);
326938032Speter
327090792Sgshapiro	    if (tlen < sizeof(nd_ipv4))
327138032Speter	        break;
327264562Sgshapiro	    ND_PRINT("\n\t      IPv4 neighbor address: %s", GET_IPADDR_STRING(tptr));
327390792Sgshapiro	    tptr+=sizeof(nd_ipv4);
327490792Sgshapiro	    tlen-=sizeof(nd_ipv4);
327590792Sgshapiro
327664562Sgshapiro	    while (tlen != 0) {
327764562Sgshapiro		if (tlen < 4)
3278102528Sgshapiro		    goto tlv_trunc;
3279102528Sgshapiro                ND_PRINT("\n\t      Link-ID: 0x%08x", GET_BE_U_4(tptr));
328064562Sgshapiro                tptr+=4;
328138032Speter                tlen-=4;
328290792Sgshapiro	    }
328390792Sgshapiro	    break;
328490792Sgshapiro
328590792Sgshapiro	case ISIS_TLV_LSP:
328690792Sgshapiro	    tlv_lsp = (const struct isis_tlv_lsp *)tptr;
328790792Sgshapiro	    while (tlen != 0) {
328890792Sgshapiro		if (tlen < sizeof(struct isis_tlv_lsp))
328990792Sgshapiro		    goto tlv_trunc;
329064562Sgshapiro		ND_TCHECK_1(tlv_lsp->lsp_id + LSP_ID_LEN - 1);
329138032Speter		ND_PRINT("\n\t      lsp-id: %s",
329264562Sgshapiro                       isis_print_id(ndo, tlv_lsp->lsp_id, LSP_ID_LEN));
329364562Sgshapiro		ND_PRINT(", seq: 0x%08x",
329490792Sgshapiro                         GET_BE_U_4(tlv_lsp->sequence_number));
329590792Sgshapiro		ND_PRINT(", lifetime: %5ds",
329690792Sgshapiro                         GET_BE_U_2(tlv_lsp->remaining_lifetime));
329790792Sgshapiro		ND_PRINT(", chksum: 0x%04x", GET_BE_U_2(tlv_lsp->checksum));
329864562Sgshapiro		tlen-=sizeof(struct isis_tlv_lsp);
329990792Sgshapiro		tlv_lsp++;
330090792Sgshapiro	    }
330190792Sgshapiro	    break;
330290792Sgshapiro
330390792Sgshapiro	case ISIS_TLV_CHECKSUM:
330490792Sgshapiro	    if (tlen < ISIS_TLV_CHECKSUM_MINLEN)
330590792Sgshapiro	        break;
330690792Sgshapiro	    ND_TCHECK_LEN(tptr, ISIS_TLV_CHECKSUM_MINLEN);
330790792Sgshapiro	    ND_PRINT("\n\t      checksum: 0x%04x ", GET_BE_U_2(tptr));
330890792Sgshapiro            /* do not attempt to verify the checksum if it is zero
330990792Sgshapiro             * most likely a HMAC-MD5 TLV is also present and
331090792Sgshapiro             * to avoid conflicts the checksum TLV is zeroed.
331190792Sgshapiro             * see rfc3358 for details
331290792Sgshapiro             */
331390792Sgshapiro            osi_print_cksum(ndo, optr, GET_BE_U_2(tptr), (int)(tptr-optr),
331464562Sgshapiro                            length);
331590792Sgshapiro	    break;
331690792Sgshapiro
331738032Speter	case ISIS_TLV_POI:
331890792Sgshapiro	    if (tlen < 1)
331998841Sgshapiro	        goto tlv_trunc;
332090792Sgshapiro	    num_system_ids = GET_U_1(tptr);
332190792Sgshapiro	    tptr++;
332290792Sgshapiro	    tlen--;
332338032Speter	    if (num_system_ids == 0) {
332438032Speter		/* Not valid */
332538032Speter		ND_PRINT(" No system IDs supplied");
332690792Sgshapiro	    } else {
332790792Sgshapiro		if (tlen < SYSTEM_ID_LEN)
332890792Sgshapiro		    goto tlv_trunc;
332990792Sgshapiro		ND_TCHECK_LEN(tptr, SYSTEM_ID_LEN);
333090792Sgshapiro		ND_PRINT("\n\t      Purge Originator System-ID: %s",
333190792Sgshapiro		       isis_print_id(ndo, tptr, SYSTEM_ID_LEN));
333238032Speter		tptr += SYSTEM_ID_LEN;
333338032Speter		tlen -= SYSTEM_ID_LEN;
333438032Speter
333538032Speter		if (num_system_ids > 1) {
333638032Speter		    if (tlen < SYSTEM_ID_LEN)
333738032Speter			goto tlv_trunc;
333838032Speter		    ND_TCHECK_LEN(tptr, SYSTEM_ID_LEN);
333938032Speter		    ND_TCHECK_LEN(tptr, 2 * SYSTEM_ID_LEN + 1);
334038032Speter		    ND_PRINT("\n\t      Received from System-ID: %s",
334190792Sgshapiro			   isis_print_id(ndo, tptr, SYSTEM_ID_LEN));
334238032Speter		}
334338032Speter	    }
334464562Sgshapiro	    break;
334538032Speter
334638032Speter	case ISIS_TLV_MT_SUPPORTED:
334738032Speter	    while (tlen != 0) {
334838032Speter		/* length can only be a multiple of 2, otherwise there is
334938032Speter		   something broken -> so decode down until length is 1 */
335038032Speter		if (tlen!=1) {
335138032Speter                    mt_len = isis_print_mtid(ndo, tptr, "\n\t      ", tlen);
335238032Speter                    if (mt_len == 0) /* did something go wrong ? */
335364562Sgshapiro                        goto trunc;
335438032Speter                    tptr+=mt_len;
335538032Speter                    tlen-=mt_len;
335638032Speter		} else {
335738032Speter		    ND_PRINT("\n\t      invalid MT-ID");
335838032Speter		    break;
335938032Speter		}
336038032Speter	    }
336138032Speter	    break;
336238032Speter
336338032Speter	case ISIS_TLV_RESTART_SIGNALING:
336438032Speter            /* first attempt to decode the flags */
336538032Speter            if (tlen < ISIS_TLV_RESTART_SIGNALING_FLAGLEN)
336638032Speter                break;
336738032Speter            ND_TCHECK_LEN(tptr, ISIS_TLV_RESTART_SIGNALING_FLAGLEN);
336838032Speter            ND_PRINT("\n\t      Flags [%s]",
336938032Speter                   bittok2str(isis_restart_flag_values, "none", GET_U_1(tptr)));
337090792Sgshapiro            tptr+=ISIS_TLV_RESTART_SIGNALING_FLAGLEN;
337190792Sgshapiro            tlen-=ISIS_TLV_RESTART_SIGNALING_FLAGLEN;
337238032Speter
337338032Speter            /* is there anything other than the flags field? */
337438032Speter            if (tlen == 0)
337538032Speter                break;
337638032Speter
337738032Speter            if (tlen < ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN)
337838032Speter                break;
337964562Sgshapiro            ND_TCHECK_LEN(tptr, ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN);
338038032Speter
338138032Speter            ND_PRINT(", Remaining holding time %us", GET_BE_U_2(tptr));
338238032Speter            tptr+=ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN;
338338032Speter            tlen-=ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN;
338438032Speter
338538032Speter            /* is there an additional sysid field present ?*/
338638032Speter            if (tlen == SYSTEM_ID_LEN) {
338738032Speter                    ND_TCHECK_LEN(tptr, SYSTEM_ID_LEN);
338838032Speter                    ND_PRINT(", for %s", isis_print_id(ndo, tptr,SYSTEM_ID_LEN));
338990792Sgshapiro            }
339090792Sgshapiro	    break;
339190792Sgshapiro
339290792Sgshapiro        case ISIS_TLV_IDRP_INFO:
339390792Sgshapiro	    if (tlen < 1)
339438032Speter	        break;
339538032Speter            isis_subtlv_idrp = GET_U_1(tptr);
339638032Speter            ND_PRINT("\n\t      Inter-Domain Information Type: %s",
339738032Speter                   tok2str(isis_subtlv_idrp_values,
339890792Sgshapiro                           "Unknown (0x%02x)",
339964562Sgshapiro                           isis_subtlv_idrp));
340090792Sgshapiro            tptr++;
340138032Speter            tlen--;
340238032Speter            switch (isis_subtlv_idrp) {
340338032Speter            case ISIS_SUBTLV_IDRP_ASN:
340438032Speter                if (tlen < 2)
340538032Speter                    goto tlv_trunc;
340638032Speter                ND_PRINT("AS Number: %u", GET_BE_U_2(tptr));
340738032Speter                break;
340838032Speter            case ISIS_SUBTLV_IDRP_LOCAL:
340938032Speter            case ISIS_SUBTLV_IDRP_RES:
341038032Speter            default:
341138032Speter                if (!print_unknown_data(ndo, tptr, "\n\t      ", tlen))
341290792Sgshapiro                    return(0);
341338032Speter                break;
341438032Speter            }
341538032Speter            break;
341638032Speter
341738032Speter        case ISIS_TLV_LSP_BUFFERSIZE:
341864562Sgshapiro	    if (tlen < 2)
341938032Speter	        break;
342038032Speter            ND_PRINT("\n\t      LSP Buffersize: %u", GET_BE_U_2(tptr));
342164562Sgshapiro            break;
342264562Sgshapiro
342364562Sgshapiro        case ISIS_TLV_PART_DIS:
342464562Sgshapiro            while (tlen != 0) {
342564562Sgshapiro                if (tlen < SYSTEM_ID_LEN)
342666494Sgshapiro                    goto tlv_trunc;
342764562Sgshapiro                ND_TCHECK_LEN(tptr, SYSTEM_ID_LEN);
342890792Sgshapiro                ND_PRINT("\n\t      %s", isis_print_id(ndo, tptr, SYSTEM_ID_LEN));
342964562Sgshapiro                tptr+=SYSTEM_ID_LEN;
343064562Sgshapiro                tlen-=SYSTEM_ID_LEN;
343164562Sgshapiro            }
343238032Speter            break;
343338032Speter
343438032Speter        case ISIS_TLV_PREFIX_NEIGH:
343538032Speter	    if (tlen < sizeof(struct isis_metric_block))
343638032Speter	        break;
343790792Sgshapiro            ND_TCHECK_LEN(tptr, sizeof(struct isis_metric_block));
343890792Sgshapiro            ND_PRINT("\n\t      Metric Block");
343990792Sgshapiro            isis_print_metric_block(ndo, (const struct isis_metric_block *)tptr);
344038032Speter            tptr+=sizeof(struct isis_metric_block);
344138032Speter            tlen-=sizeof(struct isis_metric_block);
344238032Speter
344338032Speter            while (tlen != 0) {
344438032Speter                prefix_len=GET_U_1(tptr); /* read out prefix length in semioctets*/
344538032Speter                tptr++;
344690792Sgshapiro                tlen--;
344790792Sgshapiro                if (prefix_len < 2) {
344890792Sgshapiro                    ND_PRINT("\n\t\tAddress: prefix length %u < 2", prefix_len);
344938032Speter                    break;
345090792Sgshapiro                }
345190792Sgshapiro                if (tlen < prefix_len/2)
345290792Sgshapiro                    break;
345390792Sgshapiro                ND_PRINT("\n\t\tAddress: %s/%u",
345490792Sgshapiro                       GET_ISONSAP_STRING(tptr, prefix_len / 2), prefix_len * 4);
345590792Sgshapiro                tptr+=prefix_len/2;
345690792Sgshapiro                tlen-=prefix_len/2;
345790792Sgshapiro            }
345890792Sgshapiro            break;
345990792Sgshapiro
346090792Sgshapiro        case ISIS_TLV_IIH_SEQNR:
346190792Sgshapiro	    if (tlen < 4)
346290792Sgshapiro	        break;
346390792Sgshapiro            ND_PRINT("\n\t      Sequence number: %u", GET_BE_U_4(tptr));
346490792Sgshapiro            break;
346590792Sgshapiro
346690792Sgshapiro        case ISIS_TLV_ROUTER_CAPABILITY:
346790792Sgshapiro            if (tlen < 5) {
346890792Sgshapiro                ND_PRINT(" [object length %u < 5]", tlen);
346990792Sgshapiro                nd_print_invalid(ndo);
347090792Sgshapiro                break;
347190792Sgshapiro            }
347290792Sgshapiro            ND_PRINT("\n\t      Router-ID %s", GET_IPADDR_STRING(tptr));
347390792Sgshapiro            ND_PRINT(", Flags [%s]",
347490792Sgshapiro		     bittok2str(isis_tlv_router_capability_flags, "none", GET_U_1(tptr+4)));
347590792Sgshapiro
347690792Sgshapiro	    /* Optional set of sub-TLV */
347738032Speter	    if (tlen > 5) {
347838032Speter		isis_print_router_cap_subtlv(ndo, tptr+5, tlen-5);
347938032Speter	    }
348038032Speter            break;
348138032Speter
348238032Speter        case ISIS_TLV_VENDOR_PRIVATE:
348338032Speter	    if (tlen < 3)
348438032Speter	        break;
348538032Speter            vendor_id = GET_BE_U_3(tptr);
348638032Speter            ND_PRINT("\n\t      Vendor: %s (%u)",
348738032Speter                   tok2str(oui_values, "Unknown", vendor_id),
348838032Speter                   vendor_id);
348938032Speter            tptr+=3;
349090792Sgshapiro            tlen-=3;
349190792Sgshapiro            if (tlen != 0) /* hexdump the rest */
349290792Sgshapiro                if (!print_unknown_data(ndo, tptr, "\n\t\t", tlen))
349390792Sgshapiro                    return(0);
349438032Speter            break;
349538032Speter            /*
349638032Speter             * FIXME those are the defined TLVs that lack a decoder
349738032Speter             * you are welcome to contribute code ;-)
349890792Sgshapiro             */
349990792Sgshapiro
350090792Sgshapiro        case ISIS_TLV_DECNET_PHASE4:
350190792Sgshapiro        case ISIS_TLV_LUCENT_PRIVATE:
350290792Sgshapiro        case ISIS_TLV_IPAUTH:
350390792Sgshapiro        case ISIS_TLV_NORTEL_PRIVATE1:
350490792Sgshapiro        case ISIS_TLV_NORTEL_PRIVATE2:
350590792Sgshapiro
350690792Sgshapiro	default:
350790792Sgshapiro		if (ndo->ndo_vflag <= 1) {
350890792Sgshapiro			if (!print_unknown_data(ndo, pptr, "\n\t\t", tlv_len))
350990792Sgshapiro				return(0);
351090792Sgshapiro		}
351190792Sgshapiro		break;
351290792Sgshapiro	}
351390792Sgshapirotlv_trunc:
351490792Sgshapiro        /* do we want to see an additionally hexdump ? */
351590792Sgshapiro	if (ndo->ndo_vflag> 1) {
351690792Sgshapiro		if (!print_unknown_data(ndo, pptr, "\n\t      ", tlv_len))
351790792Sgshapiro			return(0);
351890792Sgshapiro	}
351990792Sgshapiro
352090792Sgshapiro	pptr += tlv_len;
352190792Sgshapiro	packet_len -= tlv_len;
352238032Speter    }
352390792Sgshapiro
352438032Speter    if (packet_len != 0) {
352538032Speter	ND_PRINT("\n\t      %u straggler bytes", packet_len);
352690792Sgshapiro    }
352790792Sgshapiro    return (1);
352890792Sgshapiro
352990792Sgshapirotrunc:
353090792Sgshapiro    nd_print_trunc(ndo);
353190792Sgshapiro    return (1);
353290792Sgshapiro}
353338032Speter
353438032Speterstatic void
353538032Speterosi_print_cksum(netdissect_options *ndo, const uint8_t *pptr,
353638032Speter	        uint16_t checksum, int checksum_offset, u_int length)
353738032Speter{
353890792Sgshapiro        uint16_t calculated_checksum;
353990792Sgshapiro
354090792Sgshapiro        /* do not attempt to verify the checksum if it is zero,
354190792Sgshapiro         * if the offset is nonsense,
354290792Sgshapiro         * or the base pointer is not sane
354390792Sgshapiro         */
354490792Sgshapiro        if (!checksum
354538032Speter            || checksum_offset < 0
354638032Speter            || !ND_TTEST_2(pptr + checksum_offset)
354738032Speter            || (u_int)checksum_offset > length
354838032Speter            || !ND_TTEST_LEN(pptr, length)) {
354990792Sgshapiro                ND_PRINT(" (unverified)");
355090792Sgshapiro        } else {
355190792Sgshapiro#if 0
355290792Sgshapiro                ND_PRINT("\nosi_print_cksum: %p %d %u\n", pptr, checksum_offset, length);
355390792Sgshapiro#endif
355490792Sgshapiro                calculated_checksum = create_osi_cksum(pptr, checksum_offset, length);
355538032Speter                if (checksum == calculated_checksum) {
355664562Sgshapiro                        ND_PRINT(" (correct)");
355738032Speter                } else {
355890792Sgshapiro                        ND_PRINT(" (incorrect should be 0x%04x)", calculated_checksum);
355990792Sgshapiro                }
356090792Sgshapiro        }
356190792Sgshapiro}
356290792Sgshapiro