+ ND_PRINT("\n\t Digest: ");
+
+ for(i=1;i<=8; i++)
+ {
+ ND_PRINT("%08x ", EXTRACT_BE_U_4(tptr));
+ if (i%4 == 0 && i != 8)
+ ND_PRINT("\n\t ");
+ tptr = tptr + 4;
+ }
+
+ len = len - ISIS_SUBTLV_SPB_DIGEST_MIN_LEN;
+ stlv_len = stlv_len - ISIS_SUBTLV_SPB_DIGEST_MIN_LEN;
+
+ break;
+ }
+
+ case ISIS_SUBTLV_SPB_BVID:
+ {
+ while (stlv_len >= ISIS_SUBTLV_SPB_BVID_MIN_LEN)
+ {
+ ND_PRINT("\n\t ECT: %08x",
+ EXTRACT_BE_U_4(tptr));
+
+ tptr = tptr+4;
+
+ ND_PRINT(" BVID: %u, U:%01x M:%01x ",
+ (EXTRACT_BE_U_2(tptr) >> 4) ,
+ (EXTRACT_BE_U_2(tptr) >> 3) & 0x01,
+ (EXTRACT_BE_U_2(tptr) >> 2) & 0x01);
+
+ tptr = tptr + 2;
+ len = len - ISIS_SUBTLV_SPB_BVID_MIN_LEN;
+ stlv_len = stlv_len - ISIS_SUBTLV_SPB_BVID_MIN_LEN;
+ }
+
+ break;
+ }
+
+ default:
+ break;
+ }
+ tptr += stlv_len;
+ len -= stlv_len;
+ }
+
+ return 0;
+
+ trunc:
+ nd_print_trunc(ndo);
+ return(1);
+}
+
+static int
+isis_print_mt_capability_subtlv(netdissect_options *ndo,
+ const uint8_t *tptr, u_int len)
+{
+ u_int stlv_type, stlv_len, tmp;
+
+ while (len > 2)
+ {
+ ND_TCHECK_2(tptr);
+ stlv_type = EXTRACT_U_1(tptr);
+ stlv_len = EXTRACT_U_1(tptr + 1);
+ tptr = tptr + 2;
+ len = len - 2;
+
+ /* first lets see if we know the subTLVs name*/
+ ND_PRINT("\n\t %s subTLV #%u, length: %u",
+ tok2str(isis_mt_capability_subtlv_values, "unknown", stlv_type),
+ stlv_type,
+ stlv_len);
+
+ /* Make sure the subTLV fits within the space left */
+ if (len < stlv_len)
+ goto trunc;
+ /* Make sure the entire subTLV is in the captured data */
+ ND_TCHECK_LEN(tptr, stlv_len);
+
+ switch (stlv_type)
+ {
+ case ISIS_SUBTLV_SPB_INSTANCE:
+ if (stlv_len < ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN)
+ goto trunc;
+
+ ND_PRINT("\n\t CIST Root-ID: %08x", EXTRACT_BE_U_4(tptr));
+ tptr = tptr+4;
+ ND_PRINT(" %08x", EXTRACT_BE_U_4(tptr));
+ tptr = tptr+4;
+ ND_PRINT(", Path Cost: %08x", EXTRACT_BE_U_4(tptr));
+ tptr = tptr+4;
+ ND_PRINT(", Prio: %u", EXTRACT_BE_U_2(tptr));
+ tptr = tptr + 2;
+ ND_PRINT("\n\t RES: %u",
+ EXTRACT_BE_U_2(tptr) >> 5);
+ ND_PRINT(", V: %u",
+ (EXTRACT_BE_U_2(tptr) >> 4) & 0x0001);
+ ND_PRINT(", SPSource-ID: %u",
+ (EXTRACT_BE_U_4(tptr) & 0x000fffff));
+ tptr = tptr+4;
+ ND_PRINT(", No of Trees: %x", EXTRACT_U_1(tptr));
+
+ tmp = EXTRACT_U_1(tptr);
+ tptr++;
+
+ len = len - ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN;
+ stlv_len = stlv_len - ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN;
+
+ while (tmp)
+ {
+ if (stlv_len < ISIS_SUBTLV_SPB_INSTANCE_VLAN_TUPLE_LEN)
+ goto trunc;
+
+ ND_PRINT("\n\t U:%u, M:%u, A:%u, RES:%u",
+ EXTRACT_U_1(tptr) >> 7,
+ (EXTRACT_U_1(tptr) >> 6) & 0x01,
+ (EXTRACT_U_1(tptr) >> 5) & 0x01,
+ (EXTRACT_U_1(tptr) & 0x1f));
+
+ tptr++;
+
+ ND_PRINT(", ECT: %08x", EXTRACT_BE_U_4(tptr));
+
+ tptr = tptr + 4;
+
+ ND_PRINT(", BVID: %u, SPVID: %u",
+ (EXTRACT_BE_U_3(tptr) >> 12) & 0x000fff,
+ EXTRACT_BE_U_3(tptr) & 0x000fff);
+
+ tptr = tptr + 3;
+ len = len - ISIS_SUBTLV_SPB_INSTANCE_VLAN_TUPLE_LEN;
+ stlv_len = stlv_len - ISIS_SUBTLV_SPB_INSTANCE_VLAN_TUPLE_LEN;
+ tmp--;
+ }
+
+ break;
+
+ case ISIS_SUBTLV_SPBM_SI:
+ if (stlv_len < 8)
+ goto trunc;
+
+ ND_PRINT("\n\t BMAC: %08x", EXTRACT_BE_U_4(tptr));
+ tptr = tptr+4;
+ ND_PRINT("%04x", EXTRACT_BE_U_2(tptr));
+ tptr = tptr+2;
+
+ ND_PRINT(", RES: %u, VID: %u", EXTRACT_BE_U_2(tptr) >> 12,
+ (EXTRACT_BE_U_2(tptr)) & 0x0fff);
+
+ tptr = tptr+2;
+ len = len - 8;
+ stlv_len = stlv_len - 8;
+
+ while (stlv_len >= 4) {
+ ND_TCHECK_4(tptr);
+ ND_PRINT("\n\t T: %u, R: %u, RES: %u, ISID: %u",
+ (EXTRACT_BE_U_4(tptr) >> 31),
+ (EXTRACT_BE_U_4(tptr) >> 30) & 0x01,
+ (EXTRACT_BE_U_4(tptr) >> 24) & 0x03f,
+ (EXTRACT_BE_U_4(tptr)) & 0x0ffffff);
+
+ tptr = tptr + 4;
+ len = len - 4;
+ stlv_len = stlv_len - 4;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+ tptr += stlv_len;
+ len -= stlv_len;
+ }
+ return 0;
+
+ trunc:
+ nd_print_trunc(ndo);
+ return(1);
+}
+
+/* shared routine for printing system, node and lsp-ids */
+static char *
+isis_print_id(const uint8_t *cp, u_int id_len)
+{
+ u_int i;
+ static char id[sizeof("xxxx.xxxx.xxxx.yy-zz")];
+ char *pos = id;
+ u_int sysid_len;
+
+ sysid_len = SYSTEM_ID_LEN;
+ if (sysid_len > id_len)
+ sysid_len = id_len;
+ for (i = 1; i <= sysid_len; i++) {
+ nd_snprintf(pos, sizeof(id) - (pos - id), "%02x", EXTRACT_U_1(cp));
+ cp++;
+ pos += strlen(pos);
+ if (i == 2 || i == 4)
+ *pos++ = '.';
+ }
+ if (id_len >= NODE_ID_LEN) {
+ nd_snprintf(pos, sizeof(id) - (pos - id), ".%02x", EXTRACT_U_1(cp));
+ cp++;
+ pos += strlen(pos);
+ }
+ if (id_len == LSP_ID_LEN)
+ nd_snprintf(pos, sizeof(id) - (pos - id), "-%02x", EXTRACT_U_1(cp));
+ return (id);
+}
+
+/* print the 4-byte metric block which is common found in the old-style TLVs */
+static int
+isis_print_metric_block(netdissect_options *ndo,
+ const struct isis_metric_block *isis_metric_block)
+{
+ ND_PRINT(", Default Metric: %u, %s",
+ ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_default),
+ ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_default) ? "External" : "Internal");
+ if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_delay))
+ ND_PRINT("\n\t\t Delay Metric: %u, %s",
+ ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_delay),
+ ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_delay) ? "External" : "Internal");
+ if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_expense))
+ ND_PRINT("\n\t\t Expense Metric: %u, %s",
+ ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_expense),
+ ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_expense) ? "External" : "Internal");
+ if (!ISIS_LSP_TLV_METRIC_SUPPORTED(isis_metric_block->metric_error))
+ ND_PRINT("\n\t\t Error Metric: %u, %s",
+ ISIS_LSP_TLV_METRIC_VALUE(isis_metric_block->metric_error),
+ ISIS_LSP_TLV_METRIC_IE(isis_metric_block->metric_error) ? "External" : "Internal");
+
+ return(1); /* everything is ok */
+}
+
+static int
+isis_print_tlv_ip_reach(netdissect_options *ndo,
+ const uint8_t *cp, const char *ident, u_int length)
+{
+ int prefix_len;
+ const struct isis_tlv_ip_reach *tlv_ip_reach;
+
+ tlv_ip_reach = (const struct isis_tlv_ip_reach *)cp;
+
+ while (length > 0) {
+ if ((size_t)length < sizeof(*tlv_ip_reach)) {
+ ND_PRINT("short IPv4 Reachability (%u vs %lu)",
+ length,
+ (unsigned long)sizeof(*tlv_ip_reach));
+ return (0);
+ }
+
+ if (!ND_TTEST_SIZE(tlv_ip_reach))
+ return (0);
+
+ prefix_len = mask2plen(EXTRACT_IPV4_TO_HOST_ORDER(tlv_ip_reach->mask));
+
+ if (prefix_len == -1)
+ ND_PRINT("%sIPv4 prefix: %s mask %s",
+ ident,
+ ipaddr_string(ndo, (tlv_ip_reach->prefix)),
+ ipaddr_string(ndo, (tlv_ip_reach->mask)));
+ else
+ ND_PRINT("%sIPv4 prefix: %15s/%u",