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