+
+ /*
+ * print the remnants of the IP packet.
+ * save the snaplength as this may get overidden in the IP printer.
+ */
+ if (ndo->ndo_vflag >= 1 && ICMP_ERRTYPE(dp->icmp_type)) {
+ bp += 8;
+ ND_PRINT((ndo, "\n\t"));
+ ip = (const struct ip *)bp;
+ ndo->ndo_snaplen = ndo->ndo_snapend - bp;
+ snapend_save = ndo->ndo_snapend;
+ ip_print(ndo, bp, EXTRACT_16BITS(&ip->ip_len));
+ ndo->ndo_snapend = snapend_save;
+ }
+
+ /*
+ * Attempt to decode the MPLS extensions only for some ICMP types.
+ */
+ if (ndo->ndo_vflag >= 1 && plen > ICMP_EXTD_MINLEN && ICMP_MPLS_EXT_TYPE(dp->icmp_type)) {
+
+ ND_TCHECK(*ext_dp);
+
+ /*
+ * Check first if the mpls extension header shows a non-zero length.
+ * If the length field is not set then silently verify the checksum
+ * to check if an extension header is present. This is expedient,
+ * however not all implementations set the length field proper.
+ */
+ if (!ext_dp->icmp_length) {
+ vec[0].ptr = (const uint8_t *)(void *)&ext_dp->icmp_ext_version_res;
+ vec[0].len = plen - ICMP_EXTD_MINLEN;
+ if (in_cksum(vec, 1)) {
+ return;
+ }
+ }
+
+ ND_PRINT((ndo, "\n\tMPLS extension v%u",
+ ICMP_MPLS_EXT_EXTRACT_VERSION(*(ext_dp->icmp_ext_version_res))));
+
+ /*
+ * Sanity checking of the header.
+ */
+ if (ICMP_MPLS_EXT_EXTRACT_VERSION(*(ext_dp->icmp_ext_version_res)) !=
+ ICMP_MPLS_EXT_VERSION) {
+ ND_PRINT((ndo, " packet not supported"));
+ return;
+ }
+
+ hlen = plen - ICMP_EXTD_MINLEN;
+ vec[0].ptr = (const uint8_t *)(void *)&ext_dp->icmp_ext_version_res;
+ vec[0].len = hlen;
+ ND_PRINT((ndo, ", checksum 0x%04x (%scorrect), length %u",
+ EXTRACT_16BITS(ext_dp->icmp_ext_checksum),
+ in_cksum(vec, 1) ? "in" : "",
+ hlen));
+
+ hlen -= 4; /* subtract common header size */
+ obj_tptr = (const uint8_t *)ext_dp->icmp_ext_data;
+
+ while (hlen > sizeof(struct icmp_mpls_ext_object_header_t)) {
+
+ icmp_mpls_ext_object_header = (const struct icmp_mpls_ext_object_header_t *)obj_tptr;
+ ND_TCHECK(*icmp_mpls_ext_object_header);
+ obj_tlen = EXTRACT_16BITS(icmp_mpls_ext_object_header->length);
+ obj_class_num = icmp_mpls_ext_object_header->class_num;
+ obj_ctype = icmp_mpls_ext_object_header->ctype;
+ obj_tptr += sizeof(struct icmp_mpls_ext_object_header_t);
+
+ ND_PRINT((ndo, "\n\t %s Object (%u), Class-Type: %u, length %u",
+ tok2str(icmp_mpls_ext_obj_values,"unknown",obj_class_num),
+ obj_class_num,
+ obj_ctype,
+ obj_tlen));
+
+ hlen-=sizeof(struct icmp_mpls_ext_object_header_t); /* length field includes tlv header */
+
+ /* infinite loop protection */
+ if ((obj_class_num == 0) ||
+ (obj_tlen < sizeof(struct icmp_mpls_ext_object_header_t))) {
+ return;
+ }
+ obj_tlen-=sizeof(struct icmp_mpls_ext_object_header_t);
+
+ switch (obj_class_num) {
+ case 1:
+ switch(obj_ctype) {
+ case 1:
+ ND_TCHECK2(*obj_tptr, 4);
+ raw_label = EXTRACT_32BITS(obj_tptr);
+ ND_PRINT((ndo, "\n\t label %u, exp %u", MPLS_LABEL(raw_label), MPLS_EXP(raw_label)));
+ if (MPLS_STACK(raw_label))
+ ND_PRINT((ndo, ", [S]"));
+ ND_PRINT((ndo, ", ttl %u", MPLS_TTL(raw_label)));
+ break;
+ default:
+ print_unknown_data(ndo, obj_tptr, "\n\t ", obj_tlen);
+ }
+ break;
+
+ /*
+ * FIXME those are the defined objects that lack a decoder
+ * you are welcome to contribute code ;-)
+ */
+ case 2:
+ default:
+ print_unknown_data(ndo, obj_tptr, "\n\t ", obj_tlen);
+ break;
+ }
+ if (hlen < obj_tlen)
+ break;
+ hlen -= obj_tlen;
+ obj_tptr += obj_tlen;
+ }
+ }
+