Commit message: CVE-2017-13055/IS-IS: fix an Extended IS Reachability sub-TLV

In isis_print_is_reach_subtlv() one of the case blocks did not check that
the sub-TLV "V" is actually present and could over-read the input buffer.
Add a length check to fix that and remove a useless boundary check from
a loop because the boundary is tested for the full length of "V" before
the switch block.

Update one of the prior test cases as it turns out it depended on this
previously incorrect code path to make it to its own malformed structure
further down the buffer, the bugfix has changed its output.

This fixes a buffer over-read discovered by Bhargava Shastry,
SecT/TU Berlin.

Add a test using the capture file supplied by the reporter(s).
CVE: CVE-2017-13055
CWE: CWE-125
Vulnerability description: The ISO IS-IS parser in tcpdump before 4.9.2 has a buffer over-read in print-isoclns.c:isis_print_is_reach_subtlv().

Project: tcpdump
File: print-isoclns.c

clnp_print(netdissect_options *ndo,
           const uint8_t *pptr, u_int length)
{
	const uint8_t *optr,*source_address,*dest_address;
        u_int li,tlen,nsap_offset,source_address_length,dest_address_length, clnp_pdu_type, clnp_flags;
	const struct clnp_header_t *clnp_header;
	const struct clnp_segment_header_t *clnp_segment_header;
        uint8_t rfd_error_major,rfd_error_minor;

	clnp_header = (const struct clnp_header_t *) pptr;
        ND_TCHECK(*clnp_header);

        li = clnp_header->length_indicator;
        optr = pptr;

        if (!ndo->ndo_eflag)
            ND_PRINT((ndo, "CLNP"));

        /*
         * Sanity checking of the header.
         */

        if (clnp_header->version != CLNP_VERSION) {
            ND_PRINT((ndo, "version %d packet not supported", clnp_header->version));
            return (0);
        }

	if (li > length) {
            ND_PRINT((ndo, " length indicator(%u) > PDU size (%u)!", li, length));
            return (0);
	}

        if (li < sizeof(struct clnp_header_t)) {
            ND_PRINT((ndo, " length indicator %u < min PDU size:", li));
            while (pptr < ndo->ndo_snapend)
                ND_PRINT((ndo, "%02X", *pptr++));
            return (0);
        }

        /* FIXME further header sanity checking */

        clnp_pdu_type = clnp_header->type & CLNP_PDU_TYPE_MASK;
        clnp_flags = clnp_header->type & CLNP_FLAG_MASK;

        pptr += sizeof(struct clnp_header_t);
        li -= sizeof(struct clnp_header_t);

        if (li < 1) {
            ND_PRINT((ndo, "li < size of fixed part of CLNP header and addresses"));
            return (0);
        }
	ND_TCHECK(*pptr);
        dest_address_length = *pptr;
        pptr += 1;
        li -= 1;
        if (li < dest_address_length) {
            ND_PRINT((ndo, "li < size of fixed part of CLNP header and addresses"));
            return (0);
        }
        ND_TCHECK2(*pptr, dest_address_length);
        dest_address = pptr;
        pptr += dest_address_length;
        li -= dest_address_length;

        if (li < 1) {
            ND_PRINT((ndo, "li < size of fixed part of CLNP header and addresses"));
            return (0);
        }
	ND_TCHECK(*pptr);
        source_address_length = *pptr;
        pptr += 1;
        li -= 1;
        if (li < source_address_length) {
            ND_PRINT((ndo, "li < size of fixed part of CLNP header and addresses"));
            return (0);
        }
        ND_TCHECK2(*pptr, source_address_length);
        source_address = pptr;
        pptr += source_address_length;
        li -= source_address_length;

        if (ndo->ndo_vflag < 1) {
            ND_PRINT((ndo, "%s%s > %s, %s, length %u",
                   ndo->ndo_eflag ? "" : ", ",
                   isonsap_string(ndo, source_address, source_address_length),
                   isonsap_string(ndo, dest_address, dest_address_length),
                   tok2str(clnp_pdu_values,"unknown (%u)",clnp_pdu_type),
                   length));
            return (1);
        }
        ND_PRINT((ndo, "%slength %u", ndo->ndo_eflag ? "" : ", ", length));

        ND_PRINT((ndo, "\n\t%s PDU, hlen: %u, v: %u, lifetime: %u.%us, Segment PDU length: %u, checksum: 0x%04x",
               tok2str(clnp_pdu_values, "unknown (%u)",clnp_pdu_type),
               clnp_header->length_indicator,
               clnp_header->version,
               clnp_header->lifetime/2,
               (clnp_header->lifetime%2)*5,
               EXTRACT_16BITS(clnp_header->segment_length),
               EXTRACT_16BITS(clnp_header->cksum)));

        osi_print_cksum(ndo, optr, EXTRACT_16BITS(clnp_header->cksum), 7,
                        clnp_header->length_indicator);

        ND_PRINT((ndo, "\n\tFlags [%s]",
               bittok2str(clnp_flag_values, "none", clnp_flags)));

        ND_PRINT((ndo, "\n\tsource address (length %u): %s\n\tdest   address (length %u): %s",
               source_address_length,
               isonsap_string(ndo, source_address, source_address_length),
               dest_address_length,
               isonsap_string(ndo, dest_address, dest_address_length)));

        if (clnp_flags & CLNP_SEGMENT_PART) {
                if (li < sizeof(const struct clnp_segment_header_t)) {
                    ND_PRINT((ndo, "li < size of fixed part of CLNP header, addresses, and segment part"));
                    return (0);
                }
            	clnp_segment_header = (const struct clnp_segment_header_t *) pptr;
                ND_TCHECK(*clnp_segment_header);
                ND_PRINT((ndo, "\n\tData Unit ID: 0x%04x, Segment Offset: %u, Total PDU Length: %u",
                       EXTRACT_16BITS(clnp_segment_header->data_unit_id),
                       EXTRACT_16BITS(clnp_segment_header->segment_offset),
                       EXTRACT_16BITS(clnp_segment_header->total_length)));
                pptr+=sizeof(const struct clnp_segment_header_t);
                li-=sizeof(const struct clnp_segment_header_t);
        }

        /* now walk the options */
        while (li >= 2) {
            u_int op, opli;
            const uint8_t *tptr;

            if (li < 2) {
                ND_PRINT((ndo, ", bad opts/li"));
                return (0);
            }
            ND_TCHECK2(*pptr, 2);
            op = *pptr++;
            opli = *pptr++;
            li -= 2;
            if (opli > li) {
                ND_PRINT((ndo, ", opt (%d) too long", op));
                return (0);
            }
            ND_TCHECK2(*pptr, opli);
            li -= opli;
            tptr = pptr;
            tlen = opli;

            ND_PRINT((ndo, "\n\t  %s Option #%u, length %u, value: ",
                   tok2str(clnp_option_values,"Unknown",op),
                   op,
                   opli));

            /*
             * We've already checked that the entire option is present
             * in the captured packet with the ND_TCHECK2() call.
             * Therefore, we don't need to do ND_TCHECK()/ND_TCHECK2()
             * checks.
             * We do, however, need to check tlen, to make sure we
             * don't run past the end of the option.
	     */
            switch (op) {


            case CLNP_OPTION_ROUTE_RECORDING: /* those two options share the format */
            case CLNP_OPTION_SOURCE_ROUTING:
                    if (tlen < 2) {
                            ND_PRINT((ndo, ", bad opt len"));
                            return (0);
                    }
                    ND_PRINT((ndo, "%s %s",
                           tok2str(clnp_option_sr_rr_values,"Unknown",*tptr),
                           tok2str(clnp_option_sr_rr_string_values, "Unknown Option %u", op)));
                    nsap_offset=*(tptr+1);
                    if (nsap_offset == 0) {
                            ND_PRINT((ndo, " Bad NSAP offset (0)"));
                            break;
                    }
                    nsap_offset-=1; /* offset to nsap list */
                    if (nsap_offset > tlen) {
                            ND_PRINT((ndo, " Bad NSAP offset (past end of option)"));
                            break;
                    }
                    tptr+=nsap_offset;
                    tlen-=nsap_offset;
                    while (tlen > 0) {
                            source_address_length=*tptr;
                            if (tlen < source_address_length+1) {
                                    ND_PRINT((ndo, "\n\t    NSAP address goes past end of option"));
                                    break;
                            }
                            if (source_address_length > 0) {
                                    source_address=(tptr+1);
                                    ND_TCHECK2(*source_address, source_address_length);
                                    ND_PRINT((ndo, "\n\t    NSAP address (length %u): %s",
                                           source_address_length,
                                           isonsap_string(ndo, source_address, source_address_length)));
                            }
                            tlen-=source_address_length+1;
                    }
                    break;

            case CLNP_OPTION_PRIORITY:
                    if (tlen < 1) {
                            ND_PRINT((ndo, ", bad opt len"));
                            return (0);
                    }
                    ND_PRINT((ndo, "0x%1x", *tptr&0x0f));
                    break;

            case CLNP_OPTION_QOS_MAINTENANCE:
                    if (tlen < 1) {
                            ND_PRINT((ndo, ", bad opt len"));
                            return (0);
                    }
                    ND_PRINT((ndo, "\n\t    Format Code: %s",
                           tok2str(clnp_option_scope_values, "Reserved", *tptr&CLNP_OPTION_SCOPE_MASK)));

                    if ((*tptr&CLNP_OPTION_SCOPE_MASK) == CLNP_OPTION_SCOPE_GLOBAL)
                            ND_PRINT((ndo, "\n\t    QoS Flags [%s]",
                                   bittok2str(clnp_option_qos_global_values,
                                              "none",
                                              *tptr&CLNP_OPTION_OPTION_QOS_MASK)));
                    break;

            case CLNP_OPTION_SECURITY:
                    if (tlen < 2) {
                            ND_PRINT((ndo, ", bad opt len"));
                            return (0);
                    }
                    ND_PRINT((ndo, "\n\t    Format Code: %s, Security-Level %u",
                           tok2str(clnp_option_scope_values,"Reserved",*tptr&CLNP_OPTION_SCOPE_MASK),
                           *(tptr+1)));
                    break;

            case CLNP_OPTION_DISCARD_REASON:
                if (tlen < 1) {
                        ND_PRINT((ndo, ", bad opt len"));
                        return (0);
                }
                rfd_error_major = (*tptr&0xf0) >> 4;
                rfd_error_minor = *tptr&0x0f;
                ND_PRINT((ndo, "\n\t    Class: %s Error (0x%01x), %s (0x%01x)",
                       tok2str(clnp_option_rfd_class_values,"Unknown",rfd_error_major),
                       rfd_error_major,
                       tok2str(clnp_option_rfd_error_class[rfd_error_major],"Unknown",rfd_error_minor),
                       rfd_error_minor));
                break;

            case CLNP_OPTION_PADDING:
                    ND_PRINT((ndo, "padding data"));
                break;

                /*
                 * FIXME those are the defined Options that lack a decoder
                 * you are welcome to contribute code ;-)
                 */

            default:
                print_unknown_data(ndo, tptr, "\n\t  ", opli);
                break;
            }
            if (ndo->ndo_vflag > 1)
                print_unknown_data(ndo, pptr, "\n\t  ", opli);
            pptr += opli;
        }

        switch (clnp_pdu_type) {

        case    CLNP_PDU_ER: /* fall through */
        case 	CLNP_PDU_ERP:
            ND_TCHECK(*pptr);
            if (*(pptr) == NLPID_CLNP) {
                ND_PRINT((ndo, "\n\t-----original packet-----\n\t"));
                /* FIXME recursion protection */
                clnp_print(ndo, pptr, length - clnp_header->length_indicator);
                break;
            }

        case 	CLNP_PDU_DT:
        case 	CLNP_PDU_MD:
        case 	CLNP_PDU_ERQ:

        default:
            /* dump the PDU specific data */
            if (length-(pptr-optr) > 0) {
                ND_PRINT((ndo, "\n\t  undecoded non-header data, length %u", length-clnp_header->length_indicator));
                print_unknown_data(ndo, pptr, "\n\t  ", length - (pptr - optr));
            }
        }

        return (1);

 trunc:
    ND_PRINT((ndo, "[|clnp]"));
    return (1);

}

Project: tcpdump
File: print-isoclns.c

esis_print(netdissect_options *ndo,
           const uint8_t *pptr, u_int length)
{
	const uint8_t *optr;
	u_int li,esis_pdu_type,source_address_length, source_address_number;
	const struct esis_header_t *esis_header;

	if (!ndo->ndo_eflag)
		ND_PRINT((ndo, "ES-IS"));

	if (length <= 2) {
		ND_PRINT((ndo, ndo->ndo_qflag ? "bad pkt!" : "no header at all!"));
		return;
	}

	esis_header = (const struct esis_header_t *) pptr;
        ND_TCHECK(*esis_header);
        li = esis_header->length_indicator;
        optr = pptr;

        /*
         * Sanity checking of the header.
         */

        if (esis_header->nlpid != NLPID_ESIS) {
            ND_PRINT((ndo, " nlpid 0x%02x packet not supported", esis_header->nlpid));
            return;
        }

        if (esis_header->version != ESIS_VERSION) {
            ND_PRINT((ndo, " version %d packet not supported", esis_header->version));
            return;
        }

	if (li > length) {
            ND_PRINT((ndo, " length indicator(%u) > PDU size (%u)!", li, length));
            return;
	}

	if (li < sizeof(struct esis_header_t) + 2) {
            ND_PRINT((ndo, " length indicator %u < min PDU size:", li));
            while (pptr < ndo->ndo_snapend)
                ND_PRINT((ndo, "%02X", *pptr++));
            return;
	}

        esis_pdu_type = esis_header->type & ESIS_PDU_TYPE_MASK;

        if (ndo->ndo_vflag < 1) {
            ND_PRINT((ndo, "%s%s, length %u",
                   ndo->ndo_eflag ? "" : ", ",
                   tok2str(esis_pdu_values,"unknown type (%u)",esis_pdu_type),
                   length));
            return;
        } else
            ND_PRINT((ndo, "%slength %u\n\t%s (%u)",
                   ndo->ndo_eflag ? "" : ", ",
                   length,
                   tok2str(esis_pdu_values,"unknown type: %u", esis_pdu_type),
                   esis_pdu_type));

        ND_PRINT((ndo, ", v: %u%s", esis_header->version, esis_header->version == ESIS_VERSION ? "" : "unsupported" ));
        ND_PRINT((ndo, ", checksum: 0x%04x", EXTRACT_16BITS(esis_header->cksum)));

        osi_print_cksum(ndo, pptr, EXTRACT_16BITS(esis_header->cksum), 7, li);

        ND_PRINT((ndo, ", holding time: %us, length indicator: %u",
                  EXTRACT_16BITS(esis_header->holdtime), li));

        if (ndo->ndo_vflag > 1)
            print_unknown_data(ndo, optr, "\n\t", sizeof(struct esis_header_t));

	pptr += sizeof(struct esis_header_t);
	li -= sizeof(struct esis_header_t);

	switch (esis_pdu_type) {
	case ESIS_PDU_REDIRECT: {
		const uint8_t *dst, *snpa, *neta;
		u_int dstl, snpal, netal;

		ND_TCHECK(*pptr);
		if (li < 1) {
			ND_PRINT((ndo, ", bad redirect/li"));
			return;
		}
		dstl = *pptr;
		pptr++;
		li--;
		ND_TCHECK2(*pptr, dstl);
		if (li < dstl) {
			ND_PRINT((ndo, ", bad redirect/li"));
			return;
		}
		dst = pptr;
		pptr += dstl;
                li -= dstl;
		ND_PRINT((ndo, "\n\t  %s", isonsap_string(ndo, dst, dstl)));

		ND_TCHECK(*pptr);
		if (li < 1) {
			ND_PRINT((ndo, ", bad redirect/li"));
			return;
		}
		snpal = *pptr;
		pptr++;
		li--;
		ND_TCHECK2(*pptr, snpal);
		if (li < snpal) {
			ND_PRINT((ndo, ", bad redirect/li"));
			return;
		}
		snpa = pptr;
		pptr += snpal;
                li -= snpal;
		ND_TCHECK(*pptr);
		if (li < 1) {
			ND_PRINT((ndo, ", bad redirect/li"));
			return;
		}
		netal = *pptr;
		pptr++;
		ND_TCHECK2(*pptr, netal);
		if (li < netal) {
			ND_PRINT((ndo, ", bad redirect/li"));
			return;
		}
		neta = pptr;
		pptr += netal;
                li -= netal;

		if (snpal == 6)
			ND_PRINT((ndo, "\n\t  SNPA (length: %u): %s",
			       snpal,
			       etheraddr_string(ndo, snpa)));
		else
			ND_PRINT((ndo, "\n\t  SNPA (length: %u): %s",
			       snpal,
			       linkaddr_string(ndo, snpa, LINKADDR_OTHER, snpal)));
		if (netal != 0)
			ND_PRINT((ndo, "\n\t  NET (length: %u) %s",
			       netal,
			       isonsap_string(ndo, neta, netal)));
		break;
	}

	case ESIS_PDU_ESH:
            ND_TCHECK(*pptr);
            if (li < 1) {
                ND_PRINT((ndo, ", bad esh/li"));
                return;
            }
            source_address_number = *pptr;
            pptr++;
            li--;

            ND_PRINT((ndo, "\n\t  Number of Source Addresses: %u", source_address_number));

            while (source_address_number > 0) {
                ND_TCHECK(*pptr);
            	if (li < 1) {
                    ND_PRINT((ndo, ", bad esh/li"));
            	    return;
            	}
                source_address_length = *pptr;
                pptr++;
            	li--;

                ND_TCHECK2(*pptr, source_address_length);
            	if (li < source_address_length) {
                    ND_PRINT((ndo, ", bad esh/li"));
            	    return;
            	}
                ND_PRINT((ndo, "\n\t  NET (length: %u): %s",
                       source_address_length,
                       isonsap_string(ndo, pptr, source_address_length)));
                pptr += source_address_length;
                li -= source_address_length;
                source_address_number--;
            }

            break;

	case ESIS_PDU_ISH: {
            ND_TCHECK(*pptr);
            if (li < 1) {
                ND_PRINT((ndo, ", bad ish/li"));
                return;
            }
            source_address_length = *pptr;
            pptr++;
            li--;
            ND_TCHECK2(*pptr, source_address_length);
            if (li < source_address_length) {
                ND_PRINT((ndo, ", bad ish/li"));
                return;
            }
            ND_PRINT((ndo, "\n\t  NET (length: %u): %s", source_address_length, isonsap_string(ndo, pptr, source_address_length)));
            pptr += source_address_length;
            li -= source_address_length;
            break;
	}

	default:
		if (ndo->ndo_vflag <= 1) {
			if (pptr < ndo->ndo_snapend)
				print_unknown_data(ndo, pptr, "\n\t  ", ndo->ndo_snapend - pptr);
		}
		return;
	}

        /* now walk the options */
        while (li != 0) {
            u_int op, opli;
            const uint8_t *tptr;

            if (li < 2) {
                ND_PRINT((ndo, ", bad opts/li"));
                return;
            }
            ND_TCHECK2(*pptr, 2);
            op = *pptr++;
            opli = *pptr++;
            li -= 2;
            if (opli > li) {
                ND_PRINT((ndo, ", opt (%d) too long", op));
                return;
            }
            li -= opli;
            tptr = pptr;

            ND_PRINT((ndo, "\n\t  %s Option #%u, length %u, value: ",
                   tok2str(esis_option_values,"Unknown",op),
                   op,
                   opli));

            switch (op) {

            case ESIS_OPTION_ES_CONF_TIME:
                if (opli == 2) {
                    ND_TCHECK2(*pptr, 2);
                    ND_PRINT((ndo, "%us", EXTRACT_16BITS(tptr)));
                } else
                    ND_PRINT((ndo, "(bad length)"));
                break;

            case ESIS_OPTION_PROTOCOLS:
                while (opli>0) {
                    ND_TCHECK(*tptr);
                    ND_PRINT((ndo, "%s (0x%02x)",
                           tok2str(nlpid_values,
                                   "unknown",
                                   *tptr),
                           *tptr));
                    if (opli>1) /* further NPLIDs ? - put comma */
                        ND_PRINT((ndo, ", "));
                    tptr++;
                    opli--;
                }
                break;

                /*
                 * FIXME those are the defined Options that lack a decoder
                 * you are welcome to contribute code ;-)
                 */

            case ESIS_OPTION_QOS_MAINTENANCE:
            case ESIS_OPTION_SECURITY:
            case ESIS_OPTION_PRIORITY:
            case ESIS_OPTION_ADDRESS_MASK:
            case ESIS_OPTION_SNPA_MASK:

            default:
                print_unknown_data(ndo, tptr, "\n\t  ", opli);
                break;
            }
            if (ndo->ndo_vflag > 1)
                print_unknown_data(ndo, pptr, "\n\t  ", opli);
            pptr += opli;
        }
trunc:
        ND_PRINT((ndo, "[|esis]"));
}

Project: tcpdump
File: print-isoclns.c

isis_clear_checksum_lifetime(void *header)
{
    struct isis_lsp_header *header_lsp = (struct isis_lsp_header *) header;

    header_lsp->checksum[0] = 0;
    header_lsp->checksum[1] = 0;
    header_lsp->remaining_lifetime[0] = 0;
    header_lsp->remaining_lifetime[1] = 0;
}

Project: tcpdump
File: print-isoclns.c

isis_print(netdissect_options *ndo,
           const uint8_t *p, u_int length)
{
    const struct isis_common_header *isis_header;

    const struct isis_iih_lan_header *header_iih_lan;
    const struct isis_iih_ptp_header *header_iih_ptp;
    const struct isis_lsp_header *header_lsp;
    const struct isis_csnp_header *header_csnp;
    const struct isis_psnp_header *header_psnp;

    const struct isis_tlv_lsp *tlv_lsp;
    const struct isis_tlv_ptp_adj *tlv_ptp_adj;
    const struct isis_tlv_is_reach *tlv_is_reach;
    const struct isis_tlv_es_reach *tlv_es_reach;

    uint8_t pdu_type, max_area, id_length, tlv_type, tlv_len, tmp, alen, lan_alen, prefix_len;
    uint8_t ext_is_len, ext_ip_len, mt_len;
    const uint8_t *optr, *pptr, *tptr;
    u_short packet_len,pdu_len, key_id;
    u_int i,vendor_id;
    int sigcheck;

    packet_len=length;
    optr = p; /* initialize the _o_riginal pointer to the packet start -
                 need it for parsing the checksum TLV and authentication
                 TLV verification */
    isis_header = (const struct isis_common_header *)p;
    ND_TCHECK(*isis_header);
    if (length < ISIS_COMMON_HEADER_SIZE)
        goto trunc;
    pptr = p+(ISIS_COMMON_HEADER_SIZE);
    header_iih_lan = (const struct isis_iih_lan_header *)pptr;
    header_iih_ptp = (const struct isis_iih_ptp_header *)pptr;
    header_lsp = (const struct isis_lsp_header *)pptr;
    header_csnp = (const struct isis_csnp_header *)pptr;
    header_psnp = (const struct isis_psnp_header *)pptr;

    if (!ndo->ndo_eflag)
        ND_PRINT((ndo, "IS-IS"));

    /*
     * Sanity checking of the header.
     */

    if (isis_header->version != ISIS_VERSION) {
	ND_PRINT((ndo, "version %d packet not supported", isis_header->version));
	return (0);
    }

    if ((isis_header->id_length != SYSTEM_ID_LEN) && (isis_header->id_length != 0)) {
	ND_PRINT((ndo, "system ID length of %d is not supported",
	       isis_header->id_length));
	return (0);
    }

    if (isis_header->pdu_version != ISIS_VERSION) {
	ND_PRINT((ndo, "version %d packet not supported", isis_header->pdu_version));
	return (0);
    }

    if (length < isis_header->fixed_len) {
	ND_PRINT((ndo, "fixed header length %u > packet length %u", isis_header->fixed_len, length));
	return (0);
    }

    if (isis_header->fixed_len < ISIS_COMMON_HEADER_SIZE) {
	ND_PRINT((ndo, "fixed header length %u < minimum header size %u", isis_header->fixed_len, (u_int)ISIS_COMMON_HEADER_SIZE));
	return (0);
    }

    max_area = isis_header->max_area;
    switch(max_area) {
    case 0:
	max_area = 3;	 /* silly shit */
	break;
    case 255:
	ND_PRINT((ndo, "bad packet -- 255 areas"));
	return (0);
    default:
	break;
    }

    id_length = isis_header->id_length;
    switch(id_length) {
    case 0:
        id_length = 6;	 /* silly shit again */
	break;
    case 1:              /* 1-8 are valid sys-ID lenghts */
    case 2:
    case 3:
    case 4:
    case 5:
    case 6:
    case 7:
    case 8:
        break;
    case 255:
        id_length = 0;   /* entirely useless */
	break;
    default:
        break;
    }

    /* toss any non 6-byte sys-ID len PDUs */
    if (id_length != 6 ) {
	ND_PRINT((ndo, "bad packet -- illegal sys-ID length (%u)", id_length));
	return (0);
    }

    pdu_type=isis_header->pdu_type;

    /* in non-verbose mode print the basic PDU Type plus PDU specific brief information*/
    if (ndo->ndo_vflag == 0) {
        ND_PRINT((ndo, "%s%s",
               ndo->ndo_eflag ? "" : ", ",
               tok2str(isis_pdu_values, "unknown PDU-Type %u", pdu_type)));
    } else {
        /* ok they seem to want to know everything - lets fully decode it */
        ND_PRINT((ndo, "%slength %u", ndo->ndo_eflag ? "" : ", ", length));

        ND_PRINT((ndo, "\n\t%s, hlen: %u, v: %u, pdu-v: %u, sys-id-len: %u (%u), max-area: %u (%u)",
               tok2str(isis_pdu_values,
                       "unknown, type %u",
                       pdu_type),
               isis_header->fixed_len,
               isis_header->version,
               isis_header->pdu_version,
               id_length,
               isis_header->id_length,
               max_area,
               isis_header->max_area));

        if (ndo->ndo_vflag > 1) {
            if (!print_unknown_data(ndo, optr, "\n\t", 8)) /* provide the _o_riginal pointer */
                return (0);                         /* for optionally debugging the common header */
        }
    }

    switch (pdu_type) {

    case ISIS_PDU_L1_LAN_IIH:
    case ISIS_PDU_L2_LAN_IIH:
        if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE)) {
            ND_PRINT((ndo, ", bogus fixed header length %u should be %lu",
                     isis_header->fixed_len, (unsigned long)(ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE)));
            return (0);
        }
        ND_TCHECK(*header_iih_lan);
        if (length < ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE)
            goto trunc;
        if (ndo->ndo_vflag == 0) {
            ND_PRINT((ndo, ", src-id %s",
                      isis_print_id(header_iih_lan->source_id, SYSTEM_ID_LEN)));
            ND_PRINT((ndo, ", lan-id %s, prio %u",
                      isis_print_id(header_iih_lan->lan_id,NODE_ID_LEN),
                      header_iih_lan->priority));
            ND_PRINT((ndo, ", length %u", length));
            return (1);
        }
        pdu_len=EXTRACT_16BITS(header_iih_lan->pdu_len);
        if (packet_len>pdu_len) {
           packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
           length=pdu_len;
        }

        ND_PRINT((ndo, "\n\t  source-id: %s,  holding time: %us, Flags: [%s]",
                  isis_print_id(header_iih_lan->source_id,SYSTEM_ID_LEN),
                  EXTRACT_16BITS(header_iih_lan->holding_time),
                  tok2str(isis_iih_circuit_type_values,
                          "unknown circuit type 0x%02x",
                          header_iih_lan->circuit_type)));

        ND_PRINT((ndo, "\n\t  lan-id:    %s, Priority: %u, PDU length: %u",
                  isis_print_id(header_iih_lan->lan_id, NODE_ID_LEN),
                  (header_iih_lan->priority) & ISIS_LAN_PRIORITY_MASK,
                  pdu_len));

        if (ndo->ndo_vflag > 1) {
            if (!print_unknown_data(ndo, pptr, "\n\t  ", ISIS_IIH_LAN_HEADER_SIZE))
                return (0);
        }

        packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
        pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_LAN_HEADER_SIZE);
        break;

    case ISIS_PDU_PTP_IIH:
        if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE)) {
            ND_PRINT((ndo, ", bogus fixed header length %u should be %lu",
                      isis_header->fixed_len, (unsigned long)(ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE)));
            return (0);
        }
        ND_TCHECK(*header_iih_ptp);
        if (length < ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE)
            goto trunc;
        if (ndo->ndo_vflag == 0) {
            ND_PRINT((ndo, ", src-id %s", isis_print_id(header_iih_ptp->source_id, SYSTEM_ID_LEN)));
            ND_PRINT((ndo, ", length %u", length));
            return (1);
        }
        pdu_len=EXTRACT_16BITS(header_iih_ptp->pdu_len);
        if (packet_len>pdu_len) {
            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
            length=pdu_len;
        }

        ND_PRINT((ndo, "\n\t  source-id: %s, holding time: %us, Flags: [%s]",
                  isis_print_id(header_iih_ptp->source_id,SYSTEM_ID_LEN),
                  EXTRACT_16BITS(header_iih_ptp->holding_time),
                  tok2str(isis_iih_circuit_type_values,
                          "unknown circuit type 0x%02x",
                          header_iih_ptp->circuit_type)));

        ND_PRINT((ndo, "\n\t  circuit-id: 0x%02x, PDU length: %u",
                  header_iih_ptp->circuit_id,
                  pdu_len));

        if (ndo->ndo_vflag > 1) {
            if (!print_unknown_data(ndo, pptr, "\n\t  ", ISIS_IIH_PTP_HEADER_SIZE))
                return (0);
        }

        packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
        pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_IIH_PTP_HEADER_SIZE);
        break;

    case ISIS_PDU_L1_LSP:
    case ISIS_PDU_L2_LSP:
        if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE)) {
            ND_PRINT((ndo, ", bogus fixed header length %u should be %lu",
                   isis_header->fixed_len, (unsigned long)ISIS_LSP_HEADER_SIZE));
            return (0);
        }
        ND_TCHECK(*header_lsp);
        if (length < ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE)
            goto trunc;
        if (ndo->ndo_vflag == 0) {
            ND_PRINT((ndo, ", lsp-id %s, seq 0x%08x, lifetime %5us",
                      isis_print_id(header_lsp->lsp_id, LSP_ID_LEN),
                      EXTRACT_32BITS(header_lsp->sequence_number),
                      EXTRACT_16BITS(header_lsp->remaining_lifetime)));
            ND_PRINT((ndo, ", length %u", length));
            return (1);
        }
        pdu_len=EXTRACT_16BITS(header_lsp->pdu_len);
        if (packet_len>pdu_len) {
            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
            length=pdu_len;
        }

        ND_PRINT((ndo, "\n\t  lsp-id: %s, seq: 0x%08x, lifetime: %5us\n\t  chksum: 0x%04x",
               isis_print_id(header_lsp->lsp_id, LSP_ID_LEN),
               EXTRACT_32BITS(header_lsp->sequence_number),
               EXTRACT_16BITS(header_lsp->remaining_lifetime),
               EXTRACT_16BITS(header_lsp->checksum)));

        osi_print_cksum(ndo, (const uint8_t *)header_lsp->lsp_id,
                        EXTRACT_16BITS(header_lsp->checksum),
                        12, length-12);

        ND_PRINT((ndo, ", PDU length: %u, Flags: [ %s",
               pdu_len,
               ISIS_MASK_LSP_OL_BIT(header_lsp->typeblock) ? "Overload bit set, " : ""));

        if (ISIS_MASK_LSP_ATT_BITS(header_lsp->typeblock)) {
            ND_PRINT((ndo, "%s", ISIS_MASK_LSP_ATT_DEFAULT_BIT(header_lsp->typeblock) ? "default " : ""));
            ND_PRINT((ndo, "%s", ISIS_MASK_LSP_ATT_DELAY_BIT(header_lsp->typeblock) ? "delay " : ""));
            ND_PRINT((ndo, "%s", ISIS_MASK_LSP_ATT_EXPENSE_BIT(header_lsp->typeblock) ? "expense " : ""));
            ND_PRINT((ndo, "%s", ISIS_MASK_LSP_ATT_ERROR_BIT(header_lsp->typeblock) ? "error " : ""));
            ND_PRINT((ndo, "ATT bit set, "));
        }
        ND_PRINT((ndo, "%s", ISIS_MASK_LSP_PARTITION_BIT(header_lsp->typeblock) ? "P bit set, " : ""));
        ND_PRINT((ndo, "%s ]", tok2str(isis_lsp_istype_values, "Unknown(0x%x)",
                  ISIS_MASK_LSP_ISTYPE_BITS(header_lsp->typeblock))));

        if (ndo->ndo_vflag > 1) {
            if (!print_unknown_data(ndo, pptr, "\n\t  ", ISIS_LSP_HEADER_SIZE))
                return (0);
        }

        packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
        pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_LSP_HEADER_SIZE);
        break;

    case ISIS_PDU_L1_CSNP:
    case ISIS_PDU_L2_CSNP:
        if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE)) {
            ND_PRINT((ndo, ", bogus fixed header length %u should be %lu",
                      isis_header->fixed_len, (unsigned long)(ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE)));
            return (0);
        }
        ND_TCHECK(*header_csnp);
        if (length < ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE)
            goto trunc;
        if (ndo->ndo_vflag == 0) {
            ND_PRINT((ndo, ", src-id %s", isis_print_id(header_csnp->source_id, NODE_ID_LEN)));
            ND_PRINT((ndo, ", length %u", length));
            return (1);
        }
        pdu_len=EXTRACT_16BITS(header_csnp->pdu_len);
        if (packet_len>pdu_len) {
            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
            length=pdu_len;
        }

        ND_PRINT((ndo, "\n\t  source-id:    %s, PDU length: %u",
               isis_print_id(header_csnp->source_id, NODE_ID_LEN),
               pdu_len));
        ND_PRINT((ndo, "\n\t  start lsp-id: %s",
               isis_print_id(header_csnp->start_lsp_id, LSP_ID_LEN)));
        ND_PRINT((ndo, "\n\t  end lsp-id:   %s",
               isis_print_id(header_csnp->end_lsp_id, LSP_ID_LEN)));

        if (ndo->ndo_vflag > 1) {
            if (!print_unknown_data(ndo, pptr, "\n\t  ", ISIS_CSNP_HEADER_SIZE))
                return (0);
        }

        packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
        pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_CSNP_HEADER_SIZE);
        break;

    case ISIS_PDU_L1_PSNP:
    case ISIS_PDU_L2_PSNP:
        if (isis_header->fixed_len != (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE)) {
            ND_PRINT((ndo, "- bogus fixed header length %u should be %lu",
                   isis_header->fixed_len, (unsigned long)(ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE)));
            return (0);
        }
        ND_TCHECK(*header_psnp);
        if (length < ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE)
            goto trunc;
        if (ndo->ndo_vflag == 0) {
            ND_PRINT((ndo, ", src-id %s", isis_print_id(header_psnp->source_id, NODE_ID_LEN)));
            ND_PRINT((ndo, ", length %u", length));
            return (1);
        }
        pdu_len=EXTRACT_16BITS(header_psnp->pdu_len);
        if (packet_len>pdu_len) {
            packet_len=pdu_len; /* do TLV decoding as long as it makes sense */
            length=pdu_len;
        }

        ND_PRINT((ndo, "\n\t  source-id:    %s, PDU length: %u",
               isis_print_id(header_psnp->source_id, NODE_ID_LEN),
               pdu_len));

        if (ndo->ndo_vflag > 1) {
            if (!print_unknown_data(ndo, pptr, "\n\t  ", ISIS_PSNP_HEADER_SIZE))
                return (0);
        }

        packet_len -= (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
        pptr = p + (ISIS_COMMON_HEADER_SIZE+ISIS_PSNP_HEADER_SIZE);
        break;

    default:
        if (ndo->ndo_vflag == 0) {
            ND_PRINT((ndo, ", length %u", length));
            return (1);
        }
	(void)print_unknown_data(ndo, pptr, "\n\t  ", length);
	return (0);
    }

    /*
     * Now print the TLV's.
     */

    while (packet_len > 0) {
	ND_TCHECK2(*pptr, 2);
	if (packet_len < 2)
	    goto trunc;
	tlv_type = *pptr++;
	tlv_len = *pptr++;
        tmp =tlv_len; /* copy temporary len & pointer to packet data */
        tptr = pptr;
	packet_len -= 2;

        /* first lets see if we know the TLVs name*/
	ND_PRINT((ndo, "\n\t    %s TLV #%u, length: %u",
               tok2str(isis_tlv_values,
                       "unknown",
                       tlv_type),
               tlv_type,
               tlv_len));

        if (tlv_len == 0) /* something is invalid */
	    continue;

	if (packet_len < tlv_len)
	    goto trunc;

        /* now check if we have a decoder otherwise do a hexdump at the end*/
	switch (tlv_type) {
	case ISIS_TLV_AREA_ADDR:
	    ND_TCHECK2(*tptr, 1);
	    alen = *tptr++;
	    while (tmp && alen < tmp) {
	        ND_TCHECK2(*tptr, alen);
		ND_PRINT((ndo, "\n\t      Area address (length: %u): %s",
                       alen,
                       isonsap_string(ndo, tptr, alen)));
		tptr += alen;
		tmp -= alen + 1;
		if (tmp==0) /* if this is the last area address do not attemt a boundary check */
                    break;
		ND_TCHECK2(*tptr, 1);
		alen = *tptr++;
	    }
	    break;
	case ISIS_TLV_ISNEIGH:
	    while (tmp >= ETHER_ADDR_LEN) {
                ND_TCHECK2(*tptr, ETHER_ADDR_LEN);
                ND_PRINT((ndo, "\n\t      SNPA: %s", isis_print_id(tptr, ETHER_ADDR_LEN)));
                tmp -= ETHER_ADDR_LEN;
                tptr += ETHER_ADDR_LEN;
	    }
	    break;

        case ISIS_TLV_ISNEIGH_VARLEN:
            if (!ND_TTEST2(*tptr, 1) || tmp < 3) /* min. TLV length */
		goto trunctlv;
	    lan_alen = *tptr++; /* LAN address length */
	    if (lan_alen == 0) {
                ND_PRINT((ndo, "\n\t      LAN address length 0 bytes (invalid)"));
                break;
            }
            tmp --;
            ND_PRINT((ndo, "\n\t      LAN address length %u bytes ", lan_alen));
	    while (tmp >= lan_alen) {
                ND_TCHECK2(*tptr, lan_alen);
                ND_PRINT((ndo, "\n\t\tIS Neighbor: %s", isis_print_id(tptr, lan_alen)));
                tmp -= lan_alen;
                tptr +=lan_alen;
            }
            break;

	case ISIS_TLV_PADDING:
	    break;

        case ISIS_TLV_MT_IS_REACH:
            mt_len = isis_print_mtid(ndo, tptr, "\n\t      ");
            if (mt_len == 0) /* did something go wrong ? */
                goto trunctlv;
            tptr+=mt_len;
            tmp-=mt_len;
            while (tmp >= 2+NODE_ID_LEN+3+1) {
                ext_is_len = isis_print_ext_is_reach(ndo, tptr, "\n\t      ", tlv_type);
                if (ext_is_len == 0) /* did something go wrong ? */
                    goto trunctlv;

                tmp-=ext_is_len;
                tptr+=ext_is_len;
            }
            break;

        case ISIS_TLV_IS_ALIAS_ID:
	    while (tmp >= NODE_ID_LEN+1) { /* is it worth attempting a decode ? */
	        ext_is_len = isis_print_ext_is_reach(ndo, tptr, "\n\t      ", tlv_type);
		if (ext_is_len == 0) /* did something go wrong ? */
	            goto trunctlv;
		tmp-=ext_is_len;
		tptr+=ext_is_len;
	    }
	    break;

        case ISIS_TLV_EXT_IS_REACH:
            while (tmp >= NODE_ID_LEN+3+1) { /* is it worth attempting a decode ? */
                ext_is_len = isis_print_ext_is_reach(ndo, tptr, "\n\t      ", tlv_type);
                if (ext_is_len == 0) /* did something go wrong ? */
                    goto trunctlv;
                tmp-=ext_is_len;
                tptr+=ext_is_len;
            }
            break;
        case ISIS_TLV_IS_REACH:
	    ND_TCHECK2(*tptr,1);  /* check if there is one byte left to read out the virtual flag */
            ND_PRINT((ndo, "\n\t      %s",
                   tok2str(isis_is_reach_virtual_values,
                           "bogus virtual flag 0x%02x",
                           *tptr++)));
	    tlv_is_reach = (const struct isis_tlv_is_reach *)tptr;
            while (tmp >= sizeof(struct isis_tlv_is_reach)) {
		ND_TCHECK(*tlv_is_reach);
		ND_PRINT((ndo, "\n\t      IS Neighbor: %s",
		       isis_print_id(tlv_is_reach->neighbor_nodeid, NODE_ID_LEN)));
		isis_print_metric_block(ndo, &tlv_is_reach->isis_metric_block);
		tmp -= sizeof(struct isis_tlv_is_reach);
		tlv_is_reach++;
	    }
            break;

        case ISIS_TLV_ESNEIGH:
	    tlv_es_reach = (const struct isis_tlv_es_reach *)tptr;
            while (tmp >= sizeof(struct isis_tlv_es_reach)) {
		ND_TCHECK(*tlv_es_reach);
		ND_PRINT((ndo, "\n\t      ES Neighbor: %s",
                       isis_print_id(tlv_es_reach->neighbor_sysid, SYSTEM_ID_LEN)));
		isis_print_metric_block(ndo, &tlv_es_reach->isis_metric_block);
		tmp -= sizeof(struct isis_tlv_es_reach);
		tlv_es_reach++;
	    }
            break;

            /* those two TLVs share the same format */
	case ISIS_TLV_INT_IP_REACH:
	case ISIS_TLV_EXT_IP_REACH:
		if (!isis_print_tlv_ip_reach(ndo, pptr, "\n\t      ", tlv_len))
			return (1);
		break;

	case ISIS_TLV_EXTD_IP_REACH:
	    while (tmp>0) {
                ext_ip_len = isis_print_extd_ip_reach(ndo, tptr, "\n\t      ", AF_INET);
                if (ext_ip_len == 0) /* did something go wrong ? */
                    goto trunctlv;
                tptr+=ext_ip_len;
		tmp-=ext_ip_len;
	    }
	    break;

        case ISIS_TLV_MT_IP_REACH:
            mt_len = isis_print_mtid(ndo, tptr, "\n\t      ");
            if (mt_len == 0) { /* did something go wrong ? */
                goto trunctlv;
            }
            tptr+=mt_len;
            tmp-=mt_len;

            while (tmp>0) {
                ext_ip_len = isis_print_extd_ip_reach(ndo, tptr, "\n\t      ", AF_INET);
                if (ext_ip_len == 0) /* did something go wrong ? */
                    goto trunctlv;
                tptr+=ext_ip_len;
		tmp-=ext_ip_len;
	    }
	    break;

	case ISIS_TLV_IP6_REACH:
	    while (tmp>0) {
                ext_ip_len = isis_print_extd_ip_reach(ndo, tptr, "\n\t      ", AF_INET6);
                if (ext_ip_len == 0) /* did something go wrong ? */
                    goto trunctlv;
                tptr+=ext_ip_len;
		tmp-=ext_ip_len;
	    }
	    break;

	case ISIS_TLV_MT_IP6_REACH:
            mt_len = isis_print_mtid(ndo, tptr, "\n\t      ");
            if (mt_len == 0) { /* did something go wrong ? */
                goto trunctlv;
            }
            tptr+=mt_len;
            tmp-=mt_len;

	    while (tmp>0) {
                ext_ip_len = isis_print_extd_ip_reach(ndo, tptr, "\n\t      ", AF_INET6);
                if (ext_ip_len == 0) /* did something go wrong ? */
                    goto trunctlv;
                tptr+=ext_ip_len;
		tmp-=ext_ip_len;
	    }
	    break;

	case ISIS_TLV_IP6ADDR:
	    while (tmp>=sizeof(struct in6_addr)) {
		ND_TCHECK2(*tptr, sizeof(struct in6_addr));

                ND_PRINT((ndo, "\n\t      IPv6 interface address: %s",
		       ip6addr_string(ndo, tptr)));

		tptr += sizeof(struct in6_addr);
		tmp -= sizeof(struct in6_addr);
	    }
	    break;
	case ISIS_TLV_AUTH:
	    ND_TCHECK2(*tptr, 1);

            ND_PRINT((ndo, "\n\t      %s: ",
                   tok2str(isis_subtlv_auth_values,
                           "unknown Authentication type 0x%02x",
                           *tptr)));

	    switch (*tptr) {
	    case ISIS_SUBTLV_AUTH_SIMPLE:
		if (fn_printzp(ndo, tptr + 1, tlv_len - 1, ndo->ndo_snapend))
		    goto trunctlv;
		break;
	    case ISIS_SUBTLV_AUTH_MD5:
		for(i=1;i<tlv_len;i++) {
		    ND_TCHECK2(*(tptr + i), 1);
		    ND_PRINT((ndo, "%02x", *(tptr + i)));
		}
		if (tlv_len != ISIS_SUBTLV_AUTH_MD5_LEN+1)
                    ND_PRINT((ndo, ", (invalid subTLV) "));

                sigcheck = signature_verify(ndo, optr, length, tptr + 1,
                                            isis_clear_checksum_lifetime,
                                            header_lsp);
                ND_PRINT((ndo, " (%s)", tok2str(signature_check_values, "Unknown", sigcheck)));

		break;
            case ISIS_SUBTLV_AUTH_GENERIC:
		ND_TCHECK2(*(tptr + 1), 2);
                key_id = EXTRACT_16BITS((tptr+1));
                ND_PRINT((ndo, "%u, password: ", key_id));
                for(i=1 + sizeof(uint16_t);i<tlv_len;i++) {
                    ND_TCHECK2(*(tptr + i), 1);
                    ND_PRINT((ndo, "%02x", *(tptr + i)));
                }
                break;
	    case ISIS_SUBTLV_AUTH_PRIVATE:
	    default:
		if (!print_unknown_data(ndo, tptr + 1, "\n\t\t  ", tlv_len - 1))
		    return(0);
		break;
	    }
	    break;

	case ISIS_TLV_PTP_ADJ:
	    tlv_ptp_adj = (const struct isis_tlv_ptp_adj *)tptr;
	    if(tmp>=1) {
		ND_TCHECK2(*tptr, 1);
		ND_PRINT((ndo, "\n\t      Adjacency State: %s (%u)",
		       tok2str(isis_ptp_adjancey_values, "unknown", *tptr),
                        *tptr));
		tmp--;
	    }
	    if(tmp>sizeof(tlv_ptp_adj->extd_local_circuit_id)) {
		ND_TCHECK(tlv_ptp_adj->extd_local_circuit_id);
		ND_PRINT((ndo, "\n\t      Extended Local circuit-ID: 0x%08x",
		       EXTRACT_32BITS(tlv_ptp_adj->extd_local_circuit_id)));
		tmp-=sizeof(tlv_ptp_adj->extd_local_circuit_id);
	    }
	    if(tmp>=SYSTEM_ID_LEN) {
		ND_TCHECK2(tlv_ptp_adj->neighbor_sysid, SYSTEM_ID_LEN);
		ND_PRINT((ndo, "\n\t      Neighbor System-ID: %s",
		       isis_print_id(tlv_ptp_adj->neighbor_sysid, SYSTEM_ID_LEN)));
		tmp-=SYSTEM_ID_LEN;
	    }
	    if(tmp>=sizeof(tlv_ptp_adj->neighbor_extd_local_circuit_id)) {
		ND_TCHECK(tlv_ptp_adj->neighbor_extd_local_circuit_id);
		ND_PRINT((ndo, "\n\t      Neighbor Extended Local circuit-ID: 0x%08x",
		       EXTRACT_32BITS(tlv_ptp_adj->neighbor_extd_local_circuit_id)));
	    }
	    break;

	case ISIS_TLV_PROTOCOLS:
	    ND_PRINT((ndo, "\n\t      NLPID(s): "));
	    while (tmp>0) {
		ND_TCHECK2(*(tptr), 1);
		ND_PRINT((ndo, "%s (0x%02x)",
                       tok2str(nlpid_values,
                               "unknown",
                               *tptr),
                       *tptr));
		if (tmp>1) /* further NPLIDs ? - put comma */
		    ND_PRINT((ndo, ", "));
                tptr++;
                tmp--;
	    }
	    break;

    case ISIS_TLV_MT_PORT_CAP:
    {
      ND_TCHECK2(*(tptr), 2);

      ND_PRINT((ndo, "\n\t       RES: %d, MTID(s): %d",
              (EXTRACT_16BITS (tptr) >> 12),
              (EXTRACT_16BITS (tptr) & 0x0fff)));

      tmp = tmp-2;
      tptr = tptr+2;

      if (tmp)
        isis_print_mt_port_cap_subtlv(ndo, tptr, tmp);

      break;
    }

    case ISIS_TLV_MT_CAPABILITY:

      ND_TCHECK2(*(tptr), 2);

      ND_PRINT((ndo, "\n\t      O: %d, RES: %d, MTID(s): %d",
                (EXTRACT_16BITS(tptr) >> 15) & 0x01,
                (EXTRACT_16BITS(tptr) >> 12) & 0x07,
                EXTRACT_16BITS(tptr) & 0x0fff));

      tmp = tmp-2;
      tptr = tptr+2;

      if (tmp)
        isis_print_mt_capability_subtlv(ndo, tptr, tmp);

      break;

	case ISIS_TLV_TE_ROUTER_ID:
	    ND_TCHECK2(*pptr, sizeof(struct in_addr));
	    ND_PRINT((ndo, "\n\t      Traffic Engineering Router ID: %s", ipaddr_string(ndo, pptr)));
	    break;

	case ISIS_TLV_IPADDR:
	    while (tmp>=sizeof(struct in_addr)) {
		ND_TCHECK2(*tptr, sizeof(struct in_addr));
		ND_PRINT((ndo, "\n\t      IPv4 interface address: %s", ipaddr_string(ndo, tptr)));
		tptr += sizeof(struct in_addr);
		tmp -= sizeof(struct in_addr);
	    }
	    break;

	case ISIS_TLV_HOSTNAME:
	    ND_PRINT((ndo, "\n\t      Hostname: "));
	    if (fn_printzp(ndo, tptr, tmp, ndo->ndo_snapend))
		goto trunctlv;
	    break;

	case ISIS_TLV_SHARED_RISK_GROUP:
	    if (tmp < NODE_ID_LEN)
	        break;
	    ND_TCHECK2(*tptr, NODE_ID_LEN);
	    ND_PRINT((ndo, "\n\t      IS Neighbor: %s", isis_print_id(tptr, NODE_ID_LEN)));
	    tptr+=(NODE_ID_LEN);
	    tmp-=(NODE_ID_LEN);

	    if (tmp < 1)
	        break;
	    ND_TCHECK2(*tptr, 1);
	    ND_PRINT((ndo, ", Flags: [%s]", ISIS_MASK_TLV_SHARED_RISK_GROUP(*tptr++) ? "numbered" : "unnumbered"));
	    tmp--;

	    if (tmp < sizeof(struct in_addr))
	        break;
	    ND_TCHECK2(*tptr, sizeof(struct in_addr));
	    ND_PRINT((ndo, "\n\t      IPv4 interface address: %s", ipaddr_string(ndo, tptr)));
	    tptr+=sizeof(struct in_addr);
	    tmp-=sizeof(struct in_addr);

	    if (tmp < sizeof(struct in_addr))
	        break;
	    ND_TCHECK2(*tptr, sizeof(struct in_addr));
	    ND_PRINT((ndo, "\n\t      IPv4 neighbor address: %s", ipaddr_string(ndo, tptr)));
	    tptr+=sizeof(struct in_addr);
	    tmp-=sizeof(struct in_addr);

	    while (tmp>=4) {
                ND_TCHECK2(*tptr, 4);
                ND_PRINT((ndo, "\n\t      Link-ID: 0x%08x", EXTRACT_32BITS(tptr)));
                tptr+=4;
                tmp-=4;
	    }
	    break;

	case ISIS_TLV_LSP:
	    tlv_lsp = (const struct isis_tlv_lsp *)tptr;
	    while(tmp>=sizeof(struct isis_tlv_lsp)) {
		ND_TCHECK((tlv_lsp->lsp_id)[LSP_ID_LEN-1]);
		ND_PRINT((ndo, "\n\t      lsp-id: %s",
                       isis_print_id(tlv_lsp->lsp_id, LSP_ID_LEN)));
		ND_TCHECK2(tlv_lsp->sequence_number, 4);
		ND_PRINT((ndo, ", seq: 0x%08x", EXTRACT_32BITS(tlv_lsp->sequence_number)));
		ND_TCHECK2(tlv_lsp->remaining_lifetime, 2);
		ND_PRINT((ndo, ", lifetime: %5ds", EXTRACT_16BITS(tlv_lsp->remaining_lifetime)));
		ND_TCHECK2(tlv_lsp->checksum, 2);
		ND_PRINT((ndo, ", chksum: 0x%04x", EXTRACT_16BITS(tlv_lsp->checksum)));
		tmp-=sizeof(struct isis_tlv_lsp);
		tlv_lsp++;
	    }
	    break;

	case ISIS_TLV_CHECKSUM:
	    if (tmp < ISIS_TLV_CHECKSUM_MINLEN)
	        break;
	    ND_TCHECK2(*tptr, ISIS_TLV_CHECKSUM_MINLEN);
	    ND_PRINT((ndo, "\n\t      checksum: 0x%04x ", EXTRACT_16BITS(tptr)));
            /* do not attempt to verify the checksum if it is zero
             * most likely a HMAC-MD5 TLV is also present and
             * to avoid conflicts the checksum TLV is zeroed.
             * see rfc3358 for details
             */
            osi_print_cksum(ndo, optr, EXTRACT_16BITS(tptr), tptr-optr,
                length);
	    break;

	case ISIS_TLV_POI:
	    if (tlv_len >= SYSTEM_ID_LEN + 1) {
		ND_TCHECK2(*tptr, SYSTEM_ID_LEN + 1);
		ND_PRINT((ndo, "\n\t      Purge Originator System-ID: %s",
		       isis_print_id(tptr + 1, SYSTEM_ID_LEN)));
	    }

	    if (tlv_len == 2 * SYSTEM_ID_LEN + 1) {
		ND_TCHECK2(*tptr, 2 * SYSTEM_ID_LEN + 1);
		ND_PRINT((ndo, "\n\t      Received from System-ID: %s",
		       isis_print_id(tptr + SYSTEM_ID_LEN + 1, SYSTEM_ID_LEN)));
	    }
	    break;

	case ISIS_TLV_MT_SUPPORTED:
            if (tmp < ISIS_TLV_MT_SUPPORTED_MINLEN)
                break;
	    while (tmp>1) {
		/* length can only be a multiple of 2, otherwise there is
		   something broken -> so decode down until length is 1 */
		if (tmp!=1) {
                    mt_len = isis_print_mtid(ndo, tptr, "\n\t      ");
                    if (mt_len == 0) /* did something go wrong ? */
                        goto trunctlv;
                    tptr+=mt_len;
                    tmp-=mt_len;
		} else {
		    ND_PRINT((ndo, "\n\t      invalid MT-ID"));
		    break;
		}
	    }
	    break;

	case ISIS_TLV_RESTART_SIGNALING:
            /* first attempt to decode the flags */
            if (tmp < ISIS_TLV_RESTART_SIGNALING_FLAGLEN)
                break;
            ND_TCHECK2(*tptr, ISIS_TLV_RESTART_SIGNALING_FLAGLEN);
            ND_PRINT((ndo, "\n\t      Flags [%s]",
                   bittok2str(isis_restart_flag_values, "none", *tptr)));
            tptr+=ISIS_TLV_RESTART_SIGNALING_FLAGLEN;
            tmp-=ISIS_TLV_RESTART_SIGNALING_FLAGLEN;

            /* is there anything other than the flags field? */
            if (tmp == 0)
                break;

            if (tmp < ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN)
                break;
            ND_TCHECK2(*tptr, ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN);

            ND_PRINT((ndo, ", Remaining holding time %us", EXTRACT_16BITS(tptr)));
            tptr+=ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN;
            tmp-=ISIS_TLV_RESTART_SIGNALING_HOLDTIMELEN;

            /* is there an additional sysid field present ?*/
            if (tmp == SYSTEM_ID_LEN) {
                    ND_TCHECK2(*tptr, SYSTEM_ID_LEN);
                    ND_PRINT((ndo, ", for %s", isis_print_id(tptr,SYSTEM_ID_LEN)));
            }
	    break;

        case ISIS_TLV_IDRP_INFO:
	    if (tmp < ISIS_TLV_IDRP_INFO_MINLEN)
	        break;
            ND_TCHECK2(*tptr, ISIS_TLV_IDRP_INFO_MINLEN);
            ND_PRINT((ndo, "\n\t      Inter-Domain Information Type: %s",
                   tok2str(isis_subtlv_idrp_values,
                           "Unknown (0x%02x)",
                           *tptr)));
            switch (*tptr++) {
            case ISIS_SUBTLV_IDRP_ASN:
                ND_TCHECK2(*tptr, 2); /* fetch AS number */
                ND_PRINT((ndo, "AS Number: %u", EXTRACT_16BITS(tptr)));
                break;
            case ISIS_SUBTLV_IDRP_LOCAL:
            case ISIS_SUBTLV_IDRP_RES:
            default:
                if (!print_unknown_data(ndo, tptr, "\n\t      ", tlv_len - 1))
                    return(0);
                break;
            }
            break;

        case ISIS_TLV_LSP_BUFFERSIZE:
	    if (tmp < ISIS_TLV_LSP_BUFFERSIZE_MINLEN)
	        break;
            ND_TCHECK2(*tptr, ISIS_TLV_LSP_BUFFERSIZE_MINLEN);
            ND_PRINT((ndo, "\n\t      LSP Buffersize: %u", EXTRACT_16BITS(tptr)));
            break;

        case ISIS_TLV_PART_DIS:
            while (tmp >= SYSTEM_ID_LEN) {
                ND_TCHECK2(*tptr, SYSTEM_ID_LEN);
                ND_PRINT((ndo, "\n\t      %s", isis_print_id(tptr, SYSTEM_ID_LEN)));
                tptr+=SYSTEM_ID_LEN;
                tmp-=SYSTEM_ID_LEN;
            }
            break;

        case ISIS_TLV_PREFIX_NEIGH:
	    if (tmp < sizeof(struct isis_metric_block))
	        break;
            ND_TCHECK2(*tptr, sizeof(struct isis_metric_block));
            ND_PRINT((ndo, "\n\t      Metric Block"));
            isis_print_metric_block(ndo, (const struct isis_metric_block *)tptr);
            tptr+=sizeof(struct isis_metric_block);
            tmp-=sizeof(struct isis_metric_block);

            while(tmp>0) {
                ND_TCHECK2(*tptr, 1);
                prefix_len=*tptr++; /* read out prefix length in semioctets*/
                if (prefix_len < 2) {
                    ND_PRINT((ndo, "\n\t\tAddress: prefix length %u < 2", prefix_len));
                    break;
                }
                tmp--;
                if (tmp < prefix_len/2)
                    break;
                ND_TCHECK2(*tptr, prefix_len / 2);
                ND_PRINT((ndo, "\n\t\tAddress: %s/%u",
                       isonsap_string(ndo, tptr, prefix_len / 2), prefix_len * 4));
                tptr+=prefix_len/2;
                tmp-=prefix_len/2;
            }
            break;

        case ISIS_TLV_IIH_SEQNR:
	    if (tmp < ISIS_TLV_IIH_SEQNR_MINLEN)
	        break;
            ND_TCHECK2(*tptr, ISIS_TLV_IIH_SEQNR_MINLEN); /* check if four bytes are on the wire */
            ND_PRINT((ndo, "\n\t      Sequence number: %u", EXTRACT_32BITS(tptr)));
            break;

        case ISIS_TLV_VENDOR_PRIVATE:
	    if (tmp < ISIS_TLV_VENDOR_PRIVATE_MINLEN)
	        break;
            ND_TCHECK2(*tptr, ISIS_TLV_VENDOR_PRIVATE_MINLEN); /* check if enough byte for a full oui */
            vendor_id = EXTRACT_24BITS(tptr);
            ND_PRINT((ndo, "\n\t      Vendor: %s (%u)",
                   tok2str(oui_values, "Unknown", vendor_id),
                   vendor_id));
            tptr+=3;
            tmp-=3;
            if (tmp > 0) /* hexdump the rest */
                if (!print_unknown_data(ndo, tptr, "\n\t\t", tmp))
                    return(0);
            break;
            /*
             * FIXME those are the defined TLVs that lack a decoder
             * you are welcome to contribute code ;-)
             */

        case ISIS_TLV_DECNET_PHASE4:
        case ISIS_TLV_LUCENT_PRIVATE:
        case ISIS_TLV_IPAUTH:
        case ISIS_TLV_NORTEL_PRIVATE1:
        case ISIS_TLV_NORTEL_PRIVATE2:

	default:
		if (ndo->ndo_vflag <= 1) {
			if (!print_unknown_data(ndo, pptr, "\n\t\t", tlv_len))
				return(0);
		}
		break;
	}
        /* do we want to see an additionally hexdump ? */
	if (ndo->ndo_vflag> 1) {
		if (!print_unknown_data(ndo, pptr, "\n\t      ", tlv_len))
			return(0);
	}

	pptr += tlv_len;
	packet_len -= tlv_len;
    }

    if (packet_len != 0) {
	ND_PRINT((ndo, "\n\t      %u straggler bytes", packet_len));
    }
    return (1);

 trunc:
    ND_PRINT((ndo, "%s", tstr));
    return (1);

 trunctlv:
    ND_PRINT((ndo, "\n\t\t"));
    ND_PRINT((ndo, "%s", tstr));
    return(1);
}

Project: tcpdump
File: print-isoclns.c

isis_print_ext_is_reach(netdissect_options *ndo,
                        const uint8_t *tptr, const char *ident, int tlv_type)
{
    char ident_buffer[20];
    int subtlv_type,subtlv_len,subtlv_sum_len;
    int proc_bytes = 0; /* how many bytes did we process ? */

    if (!ND_TTEST2(*tptr, NODE_ID_LEN))
        return(0);

    ND_PRINT((ndo, "%sIS Neighbor: %s", ident, isis_print_id(tptr, NODE_ID_LEN)));
    tptr+=(NODE_ID_LEN);

    if (tlv_type != ISIS_TLV_IS_ALIAS_ID) { /* the Alias TLV Metric field is implicit 0 */
        if (!ND_TTEST2(*tptr, 3))    /* and is therefore skipped */
	    return(0);
	ND_PRINT((ndo, ", Metric: %d", EXTRACT_24BITS(tptr)));
	tptr+=3;
    }

    if (!ND_TTEST2(*tptr, 1))
        return(0);
    subtlv_sum_len=*(tptr++); /* read out subTLV length */
    proc_bytes=NODE_ID_LEN+3+1;
    ND_PRINT((ndo, ", %ssub-TLVs present",subtlv_sum_len ? "" : "no "));
    if (subtlv_sum_len) {
        ND_PRINT((ndo, " (%u)", subtlv_sum_len));
        while (subtlv_sum_len>0) {
            if (!ND_TTEST2(*tptr,2))
                return(0);
            subtlv_type=*(tptr++);
            subtlv_len=*(tptr++);
            /* prepend the indent string */
            snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
            if (!isis_print_is_reach_subtlv(ndo, tptr, subtlv_type, subtlv_len, ident_buffer))
                return(0);
            tptr+=subtlv_len;
            subtlv_sum_len-=(subtlv_len+2);
            proc_bytes+=(subtlv_len+2);
        }
    }
    return(proc_bytes);
}

Project: tcpdump
File: print-isoclns.c

isis_print_extd_ip_reach(netdissect_options *ndo,
                         const uint8_t *tptr, const char *ident, uint16_t afi)
{
    char ident_buffer[20];
    uint8_t prefix[sizeof(struct in6_addr)]; /* shared copy buffer for IPv4 and IPv6 prefixes */
    u_int metric, status_byte, bit_length, byte_length, sublen, processed, subtlvtype, subtlvlen;

    if (!ND_TTEST2(*tptr, 4))
        return (0);
    metric = EXTRACT_32BITS(tptr);
    processed=4;
    tptr+=4;

    if (afi == AF_INET) {
        if (!ND_TTEST2(*tptr, 1)) /* fetch status byte */
            return (0);
        status_byte=*(tptr++);
        bit_length = status_byte&0x3f;
        if (bit_length > 32) {
            ND_PRINT((ndo, "%sIPv4 prefix: bad bit length %u",
                   ident,
                   bit_length));
            return (0);
        }
        processed++;
    } else if (afi == AF_INET6) {
        if (!ND_TTEST2(*tptr, 2)) /* fetch status & prefix_len byte */
            return (0);
        status_byte=*(tptr++);
        bit_length=*(tptr++);
        if (bit_length > 128) {
            ND_PRINT((ndo, "%sIPv6 prefix: bad bit length %u",
                   ident,
                   bit_length));
            return (0);
        }
        processed+=2;
    } else
        return (0); /* somebody is fooling us */

    byte_length = (bit_length + 7) / 8; /* prefix has variable length encoding */

    if (!ND_TTEST2(*tptr, byte_length))
        return (0);
    memset(prefix, 0, sizeof prefix);   /* clear the copy buffer */
    memcpy(prefix,tptr,byte_length);    /* copy as much as is stored in the TLV */
    tptr+=byte_length;
    processed+=byte_length;

    if (afi == AF_INET)
        ND_PRINT((ndo, "%sIPv4 prefix: %15s/%u",
               ident,
               ipaddr_string(ndo, prefix),
               bit_length));
    else if (afi == AF_INET6)
        ND_PRINT((ndo, "%sIPv6 prefix: %s/%u",
               ident,
               ip6addr_string(ndo, prefix),
               bit_length));

    ND_PRINT((ndo, ", Distribution: %s, Metric: %u",
           ISIS_MASK_TLV_EXTD_IP_UPDOWN(status_byte) ? "down" : "up",
           metric));

    if (afi == AF_INET && ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte))
        ND_PRINT((ndo, ", sub-TLVs present"));
    else if (afi == AF_INET6)
        ND_PRINT((ndo, ", %s%s",
               ISIS_MASK_TLV_EXTD_IP6_IE(status_byte) ? "External" : "Internal",
               ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte) ? ", sub-TLVs present" : ""));

    if ((afi == AF_INET  && ISIS_MASK_TLV_EXTD_IP_SUBTLV(status_byte))
     || (afi == AF_INET6 && ISIS_MASK_TLV_EXTD_IP6_SUBTLV(status_byte))
	) {
        /* assume that one prefix can hold more
           than one subTLV - therefore the first byte must reflect
           the aggregate bytecount of the subTLVs for this prefix
        */
        if (!ND_TTEST2(*tptr, 1))
            return (0);
        sublen=*(tptr++);
        processed+=sublen+1;
        ND_PRINT((ndo, " (%u)", sublen));   /* print out subTLV length */

        while (sublen>0) {
            if (!ND_TTEST2(*tptr,2))
                return (0);
            subtlvtype=*(tptr++);
            subtlvlen=*(tptr++);
            /* prepend the indent string */
            snprintf(ident_buffer, sizeof(ident_buffer), "%s  ",ident);
            if (!isis_print_ip_reach_subtlv(ndo, tptr, subtlvtype, subtlvlen, ident_buffer))
                return(0);
            tptr+=subtlvlen;
            sublen-=(subtlvlen+2);
        }
    }
    return (processed);
}

Project: tcpdump
File: print-isoclns.c

isis_print_id(const uint8_t *cp, int id_len)
{
    int i;
    static char id[sizeof("xxxx.xxxx.xxxx.yy-zz")];
    char *pos = id;
    int sysid_len;

    sysid_len = SYSTEM_ID_LEN;
    if (sysid_len > id_len)
        sysid_len = id_len;
    for (i = 1; i <= sysid_len; i++) {
        snprintf(pos, sizeof(id) - (pos - id), "%02x", *cp++);
	pos += strlen(pos);
	if (i == 2 || i == 4)
	    *pos++ = '.';
	}
    if (id_len >= NODE_ID_LEN) {
        snprintf(pos, sizeof(id) - (pos - id), ".%02x", *cp++);
	pos += strlen(pos);
    }
    if (id_len == LSP_ID_LEN)
        snprintf(pos, sizeof(id) - (pos - id), "-%02x", *cp);
    return (id);
}

Project: tcpdump
File: print-isoclns.c

isis_print_ip_reach_subtlv(netdissect_options *ndo,
                           const uint8_t *tptr, int subt, int subl,
                           const char *ident)
{
    /* first lets see if we know the subTLVs name*/
    ND_PRINT((ndo, "%s%s subTLV #%u, length: %u",
              ident, tok2str(isis_ext_ip_reach_subtlv_values, "unknown", subt),
              subt, subl));

    ND_TCHECK2(*tptr,subl);

    switch(subt) {
    case ISIS_SUBTLV_EXTD_IP_REACH_MGMT_PREFIX_COLOR: /* fall through */
    case ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG32:
        while (subl >= 4) {
	    ND_PRINT((ndo, ", 0x%08x (=%u)",
		   EXTRACT_32BITS(tptr),
		   EXTRACT_32BITS(tptr)));
	    tptr+=4;
	    subl-=4;
	}
	break;
    case ISIS_SUBTLV_EXTD_IP_REACH_ADMIN_TAG64:
        while (subl >= 8) {
	    ND_PRINT((ndo, ", 0x%08x%08x",
		   EXTRACT_32BITS(tptr),
		   EXTRACT_32BITS(tptr+4)));
	    tptr+=8;
	    subl-=8;
	}
	break;
    default:
	if (!print_unknown_data(ndo, tptr, "\n\t\t    ", subl))
	  return(0);
	break;
    }
    return(1);

trunc:
    ND_PRINT((ndo, "%s", ident));
    ND_PRINT((ndo, "%s", tstr));
    return(0);
}

Project: tcpdump
File: print-isoclns.c

isis_print_metric_block(netdissect_options *ndo,
                        const struct isis_metric_block *isis_metric_block)
{
    ND_PRINT((ndo, ", Default Metric: %d, %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((ndo, "\n\t\t  Delay Metric: %d, %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((ndo, "\n\t\t  Expense Metric: %d, %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((ndo, "\n\t\t  Error Metric: %d, %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 */
}

Project: tcpdump
File: print-isoclns.c

isis_print_mt_capability_subtlv(netdissect_options *ndo,
                                const uint8_t *tptr, int len)
{
  int stlv_type, stlv_len, tmp;

  while (len > 2)
  {
    ND_TCHECK2(*tptr, 2);
    stlv_type = *(tptr++);
    stlv_len  = *(tptr++);

    /* first lets see if we know the subTLVs name*/
    ND_PRINT((ndo, "\n\t      %s subTLV #%u, length: %u",
               tok2str(isis_mt_capability_subtlv_values, "unknown", stlv_type),
               stlv_type,
               stlv_len));

    len = len - 2;

    /* 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_TCHECK2(*(tptr), stlv_len);

    switch (stlv_type)
    {
      case ISIS_SUBTLV_SPB_INSTANCE:
          if (stlv_len < ISIS_SUBTLV_SPB_INSTANCE_MIN_LEN)
            goto trunc;

          ND_PRINT((ndo, "\n\t        CIST Root-ID: %08x", EXTRACT_32BITS(tptr)));
          tptr = tptr+4;
          ND_PRINT((ndo, " %08x", EXTRACT_32BITS(tptr)));
          tptr = tptr+4;
          ND_PRINT((ndo, ", Path Cost: %08x", EXTRACT_32BITS(tptr)));
          tptr = tptr+4;
          ND_PRINT((ndo, ", Prio: %d", EXTRACT_16BITS(tptr)));
          tptr = tptr + 2;
          ND_PRINT((ndo, "\n\t        RES: %d",
                    EXTRACT_16BITS(tptr) >> 5));
          ND_PRINT((ndo, ", V: %d",
                    (EXTRACT_16BITS(tptr) >> 4) & 0x0001));
          ND_PRINT((ndo, ", SPSource-ID: %d",
                    (EXTRACT_32BITS(tptr) & 0x000fffff)));
          tptr = tptr+4;
          ND_PRINT((ndo, ", No of Trees: %x", *(tptr)));

          tmp = *(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((ndo, "\n\t         U:%d, M:%d, A:%d, RES:%d",
                      *(tptr) >> 7, (*(tptr) >> 6) & 0x01,
                      (*(tptr) >> 5) & 0x01, (*(tptr) & 0x1f)));

            tptr++;

            ND_PRINT((ndo, ", ECT: %08x", EXTRACT_32BITS(tptr)));

            tptr = tptr + 4;

            ND_PRINT((ndo, ", BVID: %d, SPVID: %d",
                      (EXTRACT_24BITS(tptr) >> 12) & 0x000fff,
                      EXTRACT_24BITS(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((ndo, "\n\t        BMAC: %08x", EXTRACT_32BITS(tptr)));
          tptr = tptr+4;
          ND_PRINT((ndo, "%04x", EXTRACT_16BITS(tptr)));
          tptr = tptr+2;

          ND_PRINT((ndo, ", RES: %d, VID: %d", EXTRACT_16BITS(tptr) >> 12,
                    (EXTRACT_16BITS(tptr)) & 0x0fff));

          tptr = tptr+2;
          len = len - 8;
          stlv_len = stlv_len - 8;

          while (stlv_len >= 4) {
            ND_TCHECK2(*tptr, 4);
            ND_PRINT((ndo, "\n\t        T: %d, R: %d, RES: %d, ISID: %d",
                    (EXTRACT_32BITS(tptr) >> 31),
                    (EXTRACT_32BITS(tptr) >> 30) & 0x01,
                    (EXTRACT_32BITS(tptr) >> 24) & 0x03f,
                    (EXTRACT_32BITS(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((ndo, "\n\t\t"));
    ND_PRINT((ndo, "%s", tstr));
    return(1);
}

Project: tcpdump
File: print-isoclns.c

isis_print_mtid(netdissect_options *ndo,
                const uint8_t *tptr, const char *ident)
{
    if (!ND_TTEST2(*tptr, 2))
        return(0);

    ND_PRINT((ndo, "%s%s",
           ident,
           tok2str(isis_mt_values,
                   "Reserved for IETF Consensus",
                   ISIS_MASK_MTID(EXTRACT_16BITS(tptr)))));

    ND_PRINT((ndo, " Topology (0x%03x), Flags: [%s]",
           ISIS_MASK_MTID(EXTRACT_16BITS(tptr)),
           bittok2str(isis_mt_flag_values, "none",ISIS_MASK_MTFLAGS(EXTRACT_16BITS(tptr)))));

    return(2);
}

Project: tcpdump
File: print-isoclns.c

isis_print_tlv_ip_reach(netdissect_options *ndo,
                        const uint8_t *cp, const char *ident, 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((ndo, "short IPv4 Reachability (%d vs %lu)",
                               length,
                               (unsigned long)sizeof(*tlv_ip_reach)));
			return (0);
		}

		if (!ND_TTEST(*tlv_ip_reach))
		    return (0);

		prefix_len = mask2plen(EXTRACT_32BITS(tlv_ip_reach->mask));

		if (prefix_len == -1)
			ND_PRINT((ndo, "%sIPv4 prefix: %s mask %s",
                               ident,
			       ipaddr_string(ndo, (tlv_ip_reach->prefix)),
			       ipaddr_string(ndo, (tlv_ip_reach->mask))));
		else
			ND_PRINT((ndo, "%sIPv4 prefix: %15s/%u",
                               ident,
			       ipaddr_string(ndo, (tlv_ip_reach->prefix)),
			       prefix_len));

		ND_PRINT((ndo, ", Distribution: %s, Metric: %u, %s",
                       ISIS_LSP_TLV_METRIC_UPDOWN(tlv_ip_reach->isis_metric_block.metric_default) ? "down" : "up",
                       ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_default),
                       ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_default) ? "External" : "Internal"));

		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_delay))
                    ND_PRINT((ndo, "%s  Delay Metric: %u, %s",
                           ident,
                           ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_delay),
                           ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_delay) ? "External" : "Internal"));

		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_expense))
                    ND_PRINT((ndo, "%s  Expense Metric: %u, %s",
                           ident,
                           ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_expense),
                           ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_expense) ? "External" : "Internal"));

		if (!ISIS_LSP_TLV_METRIC_SUPPORTED(tlv_ip_reach->isis_metric_block.metric_error))
                    ND_PRINT((ndo, "%s  Error Metric: %u, %s",
                           ident,
                           ISIS_LSP_TLV_METRIC_VALUE(tlv_ip_reach->isis_metric_block.metric_error),
                           ISIS_LSP_TLV_METRIC_IE(tlv_ip_reach->isis_metric_block.metric_error) ? "External" : "Internal"));

		length -= sizeof(struct isis_tlv_ip_reach);
		tlv_ip_reach++;
	}
	return (1);
}

Project: tcpdump
File: print-isoclns.c

isoclns_print(netdissect_options *ndo, const uint8_t *p, u_int length)
{
	if (!ND_TTEST(*p)) { /* enough bytes on the wire ? */
		ND_PRINT((ndo, "|OSI"));
		return;
	}

	if (ndo->ndo_eflag)
		ND_PRINT((ndo, "OSI NLPID %s (0x%02x): ", tok2str(nlpid_values, "Unknown", *p), *p));

	switch (*p) {

	case NLPID_CLNP:
		if (!clnp_print(ndo, p, length))
			print_unknown_data(ndo, p, "\n\t", length);
		break;

	case NLPID_ESIS:
		esis_print(ndo, p, length);
		return;

	case NLPID_ISIS:
		if (!isis_print(ndo, p, length))
			print_unknown_data(ndo, p, "\n\t", length);
		break;

	case NLPID_NULLNS:
		ND_PRINT((ndo, "%slength: %u", ndo->ndo_eflag ? "" : ", ", length));
		break;

	case NLPID_Q933:
		q933_print(ndo, p + 1, length - 1);
		break;

	case NLPID_IP:
		ip_print(ndo, p + 1, length - 1);
		break;

	case NLPID_IP6:
		ip6_print(ndo, p + 1, length - 1);
		break;

	case NLPID_PPP:
		ppp_print(ndo, p + 1, length - 1);
		break;

	default:
		if (!ndo->ndo_eflag)
			ND_PRINT((ndo, "OSI NLPID 0x%02x unknown", *p));
		ND_PRINT((ndo, "%slength: %u", ndo->ndo_eflag ? "" : ", ", length));
		if (length > 1)
			print_unknown_data(ndo, p, "\n\t", length);
		break;
	}
}

Project: tcpdump
File: print-isoclns.c

osi_print_cksum(netdissect_options *ndo, const uint8_t *pptr,
	        uint16_t checksum, int checksum_offset, u_int length)
{
        uint16_t calculated_checksum;

        /* do not attempt to verify the checksum if it is zero,
         * if the offset is nonsense,
         * or the base pointer is not sane
         */
        if (!checksum
            || checksum_offset < 0
            || !ND_TTEST2(*(pptr + checksum_offset), 2)
            || (u_int)checksum_offset > length
            || !ND_TTEST2(*pptr, length)) {
                ND_PRINT((ndo, " (unverified)"));
        } else {
#if 0
                printf("\nosi_print_cksum: %p %u %u\n", pptr, checksum_offset, length);
#endif
                calculated_checksum = create_osi_cksum(pptr, checksum_offset, length);
                if (checksum == calculated_checksum) {
                        ND_PRINT((ndo, " (correct)"));
                } else {
                        ND_PRINT((ndo, " (incorrect should be 0x%04x)", calculated_checksum));
                }
        }
}