+/*
+ * Sub-TLVs consume the "extra data" of Babel TLVs (see Section 4.3 of RFC6126),
+ * their encoding is similar to the encoding of TLVs, but the type namespace is
+ * different:
+ *
+ * o Type 0 stands for Pad1 sub-TLV with the same encoding as the Pad1 TLV.
+ * o Type 1 stands for PadN sub-TLV with the same encoding as the PadN TLV.
+ * o Type 2 stands for Diversity sub-TLV, which propagates diversity routing
+ * data. Its body is a variable-length sequence of 8-bit unsigned integers,
+ * each representing per-hop number of interferring radio channel for the
+ * prefix. Channel 0 is invalid and must not be used in the sub-TLV, channel
+ * 255 interferes with any other channel.
+ * o Type 3 stands for Timestamp sub-TLV, used to compute RTT between
+ * neighbours. In the case of a Hello TLV, the body stores a 32-bits
+ * timestamp, while in the case of a IHU TLV, two 32-bits timestamps are
+ * stored.
+ *
+ * Sub-TLV types 0 and 1 are valid for any TLV type, whether sub-TLV type 2 is
+ * only valid for TLV type 8 (Update). Note that within an Update TLV a missing
+ * Diversity sub-TLV is not the same as a Diversity sub-TLV with an empty body.
+ * The former would mean a lack of any claims about the interference, and the
+ * latter would state that interference is definitely absent.
+ * A type 3 sub-TLV is valid both for Hello and IHU TLVs, though the exact
+ * semantic of the sub-TLV is different in each case.
+ */
+static void
+subtlvs_print(netdissect_options *ndo,
+ const u_char *cp, const u_char *ep, const uint8_t tlv_type)
+{
+ uint8_t subtype, sublen;
+ const char *sep;
+ uint32_t t1, t2;
+
+ while (cp < ep) {
+ subtype = *cp++;
+ if(subtype == MESSAGE_SUB_PAD1) {
+ ND_PRINT((ndo, " sub-pad1"));
+ continue;
+ }
+ if(cp == ep)
+ goto invalid;
+ sublen = *cp++;
+ if(cp + sublen > ep)
+ goto invalid;
+
+ switch(subtype) {
+ case MESSAGE_SUB_PADN:
+ ND_PRINT((ndo, " sub-padn"));
+ cp += sublen;
+ break;
+ case MESSAGE_SUB_DIVERSITY:
+ ND_PRINT((ndo, " sub-diversity"));
+ if (sublen == 0) {
+ ND_PRINT((ndo, " empty"));
+ break;
+ }
+ sep = " ";
+ while(sublen--) {
+ ND_PRINT((ndo, "%s%s", sep, tok2str(diversity_str, "%u", *cp++)));
+ sep = "-";
+ }
+ if(tlv_type != MESSAGE_UPDATE &&
+ tlv_type != MESSAGE_UPDATE_SRC_SPECIFIC)
+ ND_PRINT((ndo, " (bogus)"));
+ break;
+ case MESSAGE_SUB_TIMESTAMP:
+ ND_PRINT((ndo, " sub-timestamp"));
+ if(tlv_type == MESSAGE_HELLO) {
+ if(sublen < 4)
+ goto invalid;
+ t1 = EXTRACT_32BITS(cp);
+ ND_PRINT((ndo, " %s", format_timestamp(t1)));
+ } else if(tlv_type == MESSAGE_IHU) {
+ if(sublen < 8)
+ goto invalid;
+ t1 = EXTRACT_32BITS(cp);
+ ND_PRINT((ndo, " %s", format_timestamp(t1)));
+ t2 = EXTRACT_32BITS(cp + 4);
+ ND_PRINT((ndo, "|%s", format_timestamp(t2)));
+ } else
+ ND_PRINT((ndo, " (bogus)"));
+ cp += sublen;
+ break;
+ default:
+ ND_PRINT((ndo, " sub-unknown-0x%02x", subtype));
+ cp += sublen;
+ } /* switch */
+ } /* while */
+ return;
+
+ invalid:
+ ND_PRINT((ndo, "%s", istr));
+}
+