"Fossies" - the Fresh Open Source Software Archive

Member "tcpdump-4.99.1/./print-isoclns.c" (7 Jun 2021, 120539 Bytes) of package /linux/misc/tcpdump-4.99.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "print-isoclns.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.99.0_vs_4.99.1.

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