+
+trunc:
+ nd_print_trunc(ndo);
+ return 0;
+
+}
+
+u_int
+mfr_if_print(netdissect_options *ndo,
+ const struct pcap_pkthdr *h, const u_char *p)
+{
+ u_int length = h->len;
+ u_int caplen = h->caplen;
+
+ ndo->ndo_protocol = "mfr_if";
+ ND_TCHECK_2(p); /* minimum frame header length */
+
+ if ((length = mfr_print(ndo, p, length)) == 0)
+ return (0);
+ else
+ return length;
+trunc:
+ nd_print_trunc(ndo);
+ return caplen;
+}
+
+
+#define MFR_CTRL_MSG_ADD_LINK 1
+#define MFR_CTRL_MSG_ADD_LINK_ACK 2
+#define MFR_CTRL_MSG_ADD_LINK_REJ 3
+#define MFR_CTRL_MSG_HELLO 4
+#define MFR_CTRL_MSG_HELLO_ACK 5
+#define MFR_CTRL_MSG_REMOVE_LINK 6
+#define MFR_CTRL_MSG_REMOVE_LINK_ACK 7
+
+static const struct tok mfr_ctrl_msg_values[] = {
+ { MFR_CTRL_MSG_ADD_LINK, "Add Link" },
+ { MFR_CTRL_MSG_ADD_LINK_ACK, "Add Link ACK" },
+ { MFR_CTRL_MSG_ADD_LINK_REJ, "Add Link Reject" },
+ { MFR_CTRL_MSG_HELLO, "Hello" },
+ { MFR_CTRL_MSG_HELLO_ACK, "Hello ACK" },
+ { MFR_CTRL_MSG_REMOVE_LINK, "Remove Link" },
+ { MFR_CTRL_MSG_REMOVE_LINK_ACK, "Remove Link ACK" },
+ { 0, NULL }
+};
+
+#define MFR_CTRL_IE_BUNDLE_ID 1
+#define MFR_CTRL_IE_LINK_ID 2
+#define MFR_CTRL_IE_MAGIC_NUM 3
+#define MFR_CTRL_IE_TIMESTAMP 5
+#define MFR_CTRL_IE_VENDOR_EXT 6
+#define MFR_CTRL_IE_CAUSE 7
+
+static const struct tok mfr_ctrl_ie_values[] = {
+ { MFR_CTRL_IE_BUNDLE_ID, "Bundle ID"},
+ { MFR_CTRL_IE_LINK_ID, "Link ID"},
+ { MFR_CTRL_IE_MAGIC_NUM, "Magic Number"},
+ { MFR_CTRL_IE_TIMESTAMP, "Timestamp"},
+ { MFR_CTRL_IE_VENDOR_EXT, "Vendor Extension"},
+ { MFR_CTRL_IE_CAUSE, "Cause"},
+ { 0, NULL }
+};
+
+#define MFR_ID_STRING_MAXLEN 50
+
+struct ie_tlv_header_t {
+ uint8_t ie_type;
+ uint8_t ie_len;
+};
+
+u_int
+mfr_print(netdissect_options *ndo,
+ const u_char *p, u_int length)
+{
+ u_int tlen,idx,hdr_len = 0;
+ uint16_t sequence_num;
+ uint8_t ie_type,ie_len;
+ const uint8_t *tptr;
+
+
+/*
+ * FRF.16 Link Integrity Control Frame
+ *
+ * 7 6 5 4 3 2 1 0
+ * +----+----+----+----+----+----+----+----+
+ * | B | E | C=1| 0 0 0 0 | EA |
+ * +----+----+----+----+----+----+----+----+
+ * | 0 0 0 0 0 0 0 0 |
+ * +----+----+----+----+----+----+----+----+
+ * | message type |
+ * +----+----+----+----+----+----+----+----+
+ */
+
+ ndo->ndo_protocol = "mfr";
+
+ if (length < 4) { /* minimum frame header length */
+ ND_PRINT("[length %u < 4]", length);
+ nd_print_invalid(ndo);
+ return length;
+ }
+ ND_TCHECK_4(p);
+
+ if ((GET_U_1(p) & MFR_BEC_MASK) == MFR_CTRL_FRAME && GET_U_1(p + 1) == 0) {
+ ND_PRINT("FRF.16 Control, Flags [%s], %s, length %u",
+ bittok2str(frf_flag_values,"none",(GET_U_1(p) & MFR_BEC_MASK)),
+ tok2str(mfr_ctrl_msg_values,"Unknown Message (0x%02x)",GET_U_1(p + 2)),
+ length);
+ tptr = p + 3;
+ tlen = length -3;
+ hdr_len = 3;
+
+ if (!ndo->ndo_vflag)
+ return hdr_len;
+
+ while (tlen>sizeof(struct ie_tlv_header_t)) {
+ ND_TCHECK_LEN(tptr, sizeof(struct ie_tlv_header_t));
+ ie_type=GET_U_1(tptr);
+ ie_len=GET_U_1(tptr + 1);
+
+ ND_PRINT("\n\tIE %s (%u), length %u: ",
+ tok2str(mfr_ctrl_ie_values,"Unknown",ie_type),
+ ie_type,
+ ie_len);
+
+ /* infinite loop check */
+ if (ie_type == 0 || ie_len <= sizeof(struct ie_tlv_header_t))
+ return hdr_len;
+
+ ND_TCHECK_LEN(tptr, ie_len);
+ tptr+=sizeof(struct ie_tlv_header_t);
+ /* tlv len includes header */
+ ie_len-=sizeof(struct ie_tlv_header_t);
+ tlen-=sizeof(struct ie_tlv_header_t);
+
+ switch (ie_type) {
+
+ case MFR_CTRL_IE_MAGIC_NUM:
+ /* FRF.16.1 Section 3.4.3 Magic Number Information Element */
+ if (ie_len != 4) {
+ ND_PRINT("[IE data length %d != 4]", ie_len);
+ nd_print_invalid(ndo);
+ break;
+ }
+ ND_PRINT("0x%08x", GET_BE_U_4(tptr));
+ break;
+
+ case MFR_CTRL_IE_BUNDLE_ID: /* same message format */
+ case MFR_CTRL_IE_LINK_ID:
+ for (idx = 0; idx < ie_len && idx < MFR_ID_STRING_MAXLEN; idx++) {
+ if (GET_U_1(tptr + idx) != 0) /* don't print null termination */
+ fn_print_char(ndo, GET_U_1(tptr + idx));
+ else
+ break;
+ }
+ break;
+
+ case MFR_CTRL_IE_TIMESTAMP:
+ if (ie_len == sizeof(struct timeval)) {
+ ts_print(ndo, (const struct timeval *)tptr);
+ break;
+ }
+ /* fall through and hexdump if no unix timestamp */
+ ND_FALL_THROUGH;
+
+ /*
+ * FIXME those are the defined IEs that lack a decoder
+ * you are welcome to contribute code ;-)
+ */
+
+ case MFR_CTRL_IE_VENDOR_EXT:
+ case MFR_CTRL_IE_CAUSE:
+
+ default:
+ if (ndo->ndo_vflag <= 1)
+ print_unknown_data(ndo, tptr, "\n\t ", ie_len);
+ break;
+ }
+
+ /* do we want to see a hexdump of the IE ? */
+ if (ndo->ndo_vflag > 1 )
+ print_unknown_data(ndo, tptr, "\n\t ", ie_len);
+
+ tlen-=ie_len;
+ tptr+=ie_len;
+ }
+ return hdr_len;
+ }
+/*
+ * FRF.16 Fragmentation Frame
+ *
+ * 7 6 5 4 3 2 1 0
+ * +----+----+----+----+----+----+----+----+
+ * | B | E | C=0|seq. (high 4 bits) | EA |
+ * +----+----+----+----+----+----+----+----+
+ * | sequence (low 8 bits) |
+ * +----+----+----+----+----+----+----+----+
+ * | DLCI (6 bits) | CR | EA |
+ * +----+----+----+----+----+----+----+----+
+ * | DLCI (4 bits) |FECN|BECN| DE | EA |
+ * +----+----+----+----+----+----+----+----+
+ */
+
+ sequence_num = (GET_U_1(p)&0x1e)<<7 | GET_U_1(p + 1);
+ /* whole packet or first fragment ? */
+ if ((GET_U_1(p) & MFR_BEC_MASK) == MFR_FRAG_FRAME ||
+ (GET_U_1(p) & MFR_BEC_MASK) == MFR_B_BIT) {
+ ND_PRINT("FRF.16 Frag, seq %u, Flags [%s], ",
+ sequence_num,
+ bittok2str(frf_flag_values,"none",(GET_U_1(p) & MFR_BEC_MASK)));
+ hdr_len = 2;
+ fr_print(ndo, p+hdr_len,length-hdr_len);
+ return hdr_len;
+ }
+
+ /* must be a middle or the last fragment */
+ ND_PRINT("FRF.16 Frag, seq %u, Flags [%s]",
+ sequence_num,
+ bittok2str(frf_flag_values,"none",(GET_U_1(p) & MFR_BEC_MASK)));
+ print_unknown_data(ndo, p, "\n\t", length);
+
+ return hdr_len;
+
+trunc:
+ nd_print_trunc(ndo);
+ return length;
+}
+
+/* an NLPID of 0xb1 indicates a 2-byte
+ * FRF.15 header
+ *
+ * 7 6 5 4 3 2 1 0
+ * +----+----+----+----+----+----+----+----+
+ * ~ Q.922 header ~
+ * +----+----+----+----+----+----+----+----+
+ * | NLPID (8 bits) | NLPID=0xb1
+ * +----+----+----+----+----+----+----+----+
+ * | B | E | C |seq. (high 4 bits) | R |
+ * +----+----+----+----+----+----+----+----+
+ * | sequence (low 8 bits) |
+ * +----+----+----+----+----+----+----+----+
+ */
+
+#define FR_FRF15_FRAGTYPE 0x01
+
+static void
+frf15_print(netdissect_options *ndo,
+ const u_char *p, u_int length)
+{
+ uint16_t sequence_num, flags;
+
+ if (length < 2)
+ goto trunc;
+ ND_TCHECK_2(p);
+
+ flags = GET_U_1(p)&MFR_BEC_MASK;
+ sequence_num = (GET_U_1(p)&0x1e)<<7 | GET_U_1(p + 1);
+
+ ND_PRINT("FRF.15, seq 0x%03x, Flags [%s],%s Fragmentation, length %u",
+ sequence_num,
+ bittok2str(frf_flag_values,"none",flags),
+ GET_U_1(p)&FR_FRF15_FRAGTYPE ? "Interface" : "End-to-End",
+ length);
+
+/* TODO:
+ * depending on all permutations of the B, E and C bit
+ * dig as deep as we can - e.g. on the first (B) fragment
+ * there is enough payload to print the IP header
+ * on non (B) fragments it depends if the fragmentation
+ * model is end-to-end or interface based wether we want to print
+ * another Q.922 header
+ */
+ return;
+
+trunc:
+ nd_print_trunc(ndo);