/* packet-packetbb.c * Routines for parsing packetbb rfc 5444 * Parser created by Henning Rogge of Fraunhover * TLV values decoding by Francois Schneider * * http://tools.ietf.org/html/rfc5444 * http://tools.ietf.org/html/rfc5498 * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "config.h" #include #include #include void proto_reg_handoff_packetbb(void); void proto_register_packetbb(void); #define PACKET_HEADER_HASSEQNR 0x08 #define PACKET_HEADER_HASTLV 0x04 #define MSG_HEADER_HASORIG 0x80 #define MSG_HEADER_HASHOPLIMIT 0x40 #define MSG_HEADER_HASHOPCOUNT 0x20 #define MSG_HEADER_HASSEQNR 0x10 #define ADDR_HASHEAD 0x80 #define ADDR_HASFULLTAIL 0x40 #define ADDR_HASZEROTAIL 0x20 #define ADDR_HASSINGLEPRELEN 0x10 #define ADDR_HASMULTIPRELEN 0x08 #define TLV_HAS_TYPEEXT 0x80 #define TLV_HAS_SINGLEINDEX 0x40 #define TLV_HAS_MULTIINDEX 0x20 #define TLV_HAS_VALUE 0x10 #define TLV_HAS_EXTLEN 0x08 #define TLV_HAS_MULTIVALUE 0x04 #define MAX_ADDR_SIZE 16 #define PACKETBB_MSG_TLV_LENGTH (G_MAXUINT8 + 1) #define TLV_CAT_PACKET 0 #define TLV_CAT_MESSAGE 1 #define TLV_CAT_ADDRESS 2 /* Generic address TLV defined by IANA in RFC5497 (timetlv) */ enum rfc5497_tlv_iana { RFC5497_TLV_INTERVAL_TIME = 0, RFC5497_TLV_VALIDITY_TIME = 1 }; /* Generic address TLV defined by IANA in RFC6130 (NHDP) */ enum rfc6130_addrtlv_iana { RFC6130_ADDRTLV_LOCAL_IF = 2, RFC6130_ADDRTLV_LINK_STATUS = 3, RFC6130_ADDRTLV_OTHER_NEIGH = 4 }; /* Generic address TLVs defined by IANA in RFC7182 (rfc5444-sec) */ enum rfc7182_tlv_iana { RFC7182_TLV_ICV = 5, RFC7182_TLV_TIMESTAMP = 6 }; /* Generic address TLV defined by IANA in RFC7181 (OLSRv2) */ enum rfc7181_addrtlv_iana { RFC7181_ADDRTLV_LINK_METRIC = 7, RFC7181_ADDRTLV_MPR = 8, RFC7181_ADDRTLV_NBR_ADDR_TYPE = 9, RFC7181_ADDRTLV_GATEWAY = 10 }; /* Generic message TLV defined by IANA in RFC7181 (OLSRv2) */ enum rfc7181_msgtlvs_iana { RFC7181_MSGTLV_MPR_WILLING = 7, RFC7181_MSGTLV_CONT_SEQ_NUM = 8 }; /* Bit-flags for LINK_METRIC address TLV */ enum rfc7181_linkmetric_flags { RFC7181_LINKMETRIC_INCOMING_LINK = 1<<15, RFC7181_LINKMETRIC_OUTGOING_LINK = 1<<14, RFC7181_LINKMETRIC_INCOMING_NEIGH = 1<<13, RFC7181_LINKMETRIC_OUTGOING_NEIGH = 1<<12 }; /* Bit-flags for MPR address TLV */ enum rfc7181_mpr_bitmask { RFC7181_MPR_FLOODING = 1, RFC7181_MPR_ROUTING = 2, RFC7181_MPR_FLOOD_ROUTE = 3 }; /* Message types defined by IANA in RFC5444 */ const value_string msgheader_type_vals[] = { { 0, "HELLO (NHDP)" }, { 1, "TC (OLSRv2)" }, { 0, NULL }}; /* Packet TLV types defined by IANA in RFC7182 */ const value_string pkttlv_type_vals[] = { { RFC7182_TLV_ICV , "Integrity Check Value" }, { RFC7182_TLV_TIMESTAMP , "Timestamp" }, { 0 , NULL }}; /* Message TLV types defined by IANA in RFC5497,7181,7182 */ const value_string msgtlv_type_vals[] = { { RFC5497_TLV_INTERVAL_TIME , "Signaling message interval" }, { RFC5497_TLV_VALIDITY_TIME , "Message validity time" }, { RFC7182_TLV_ICV , "Integrity Check Value" }, { RFC7182_TLV_TIMESTAMP , "Timestamp" }, { RFC7181_MSGTLV_MPR_WILLING , "MPR willingness" }, { RFC7181_MSGTLV_CONT_SEQ_NUM , "Content sequence number" }, { 0 , NULL }}; /* Address TLV types defined by IANA in RFC5497,6130,7181,7182 */ const value_string addrtlv_type_vals[] = { { RFC5497_TLV_INTERVAL_TIME , "Signaling message interval" }, { RFC5497_TLV_VALIDITY_TIME , "Message validity time" }, { RFC6130_ADDRTLV_LOCAL_IF , "Local interface status" }, { RFC6130_ADDRTLV_LINK_STATUS , "Link status" }, { RFC6130_ADDRTLV_OTHER_NEIGH , "Other neighbor status" }, { RFC7182_TLV_ICV , "Integrity Check Value" }, { RFC7182_TLV_TIMESTAMP , "Timestamp" }, { RFC7181_ADDRTLV_LINK_METRIC , "Link metric" }, { RFC7181_ADDRTLV_MPR , "Multipoint Relay" }, { RFC7181_ADDRTLV_NBR_ADDR_TYPE, "Neighbor address type" }, { RFC7181_ADDRTLV_GATEWAY , "Gateway" }, { 0 , NULL }}; /* Values of LOCALIF TLV of RFC6130 */ const value_string localif_vals[] = { { 0, "THIS_IF" }, { 1, "OTHER_IF" }, { 0, NULL }}; /* Values of LINKSTATUS TLV of RFC6130 */ const value_string linkstatus_vals[] = { { 0, "LOST" }, { 1, "SYMMETRIC" }, { 2, "HEARD" }, { 0, NULL }}; /* Values of OTHERNEIGH TLV of RFC6130 */ const value_string otherneigh_vals[] = { { 0, "LOST" }, { 1, "SYMMETRIC" }, { 0, NULL }}; /* Values of MPR TLV of RFC7181 */ const value_string mpr_vals[] = { { 1, "FLOODING" }, { 2, "ROUTING" }, { 3, "FLOOD_ROUTE" }, { 0, NULL }}; /* Values of NBRADDRTYPE TLV of RFC7181 */ const value_string nbraddrtype_vals[] = { { 1, "ORIGINATOR" }, { 2, "ROUTABLE" }, { 3, "ROUTABLE_ORIG" }, { 0, NULL }}; static int proto_packetbb = -1; #define PACKETBB_PORT 269 /* Not IANA registered */ static int hf_packetbb_header = -1; static int hf_packetbb_version = -1; static int hf_packetbb_header_flags = -1; static int hf_packetbb_header_flags_phasseqnum = -1; static int hf_packetbb_header_flags_phastlv = -1; static int hf_packetbb_seqnr = -1; static int hf_packetbb_msg = -1; static int hf_packetbb_msgheader = -1; static int hf_packetbb_msgheader_type = -1; static int hf_packetbb_msgheader_flags = -1; static int hf_packetbb_msgheader_flags_mhasorig = -1; static int hf_packetbb_msgheader_flags_mhashoplimit = -1; static int hf_packetbb_msgheader_flags_mhashopcount = -1; static int hf_packetbb_msgheader_flags_mhasseqnr = -1; static int hf_packetbb_msgheader_addresssize = -1; static int hf_packetbb_msgheader_size = -1; static int hf_packetbb_msgheader_origaddripv4 = -1; static int hf_packetbb_msgheader_origaddripv6 = -1; static int hf_packetbb_msgheader_origaddrmac = -1; static int hf_packetbb_msgheader_origaddrcustom = -1; static int hf_packetbb_msgheader_hoplimit = -1; static int hf_packetbb_msgheader_hopcount = -1; static int hf_packetbb_msgheader_seqnr = -1; static int hf_packetbb_addr = -1; static int hf_packetbb_addr_num = -1; static int hf_packetbb_addr_flags = -1; static int hf_packetbb_addr_flags_hashead = -1; static int hf_packetbb_addr_flags_hasfulltail = -1; static int hf_packetbb_addr_flags_haszerotail = -1; static int hf_packetbb_addr_flags_hassingleprelen = -1; static int hf_packetbb_addr_flags_hasmultiprelen = -1; static int hf_packetbb_addr_head = -1; static int hf_packetbb_addr_tail = -1; static int hf_packetbb_addr_value[4] = { -1, -1, -1, -1 }; static int hf_packetbb_addr_value_mid = -1; static int hf_packetbb_addr_value_prefix = -1; static int hf_packetbb_tlvblock = -1; static int hf_packetbb_tlvblock_length = -1; static int hf_packetbb_tlv = -1; static int hf_packetbb_pkttlv_type = -1; static int hf_packetbb_msgtlv_type = -1; static int hf_packetbb_addrtlv_type = -1; static int hf_packetbb_tlv_flags = -1; static int hf_packetbb_tlv_flags_hastypext = -1; static int hf_packetbb_tlv_flags_hassingleindex = -1; static int hf_packetbb_tlv_flags_hasmultiindex = -1; static int hf_packetbb_tlv_flags_hasvalue = -1; static int hf_packetbb_tlv_flags_hasextlen = -1; static int hf_packetbb_tlv_flags_hasmultivalue = -1; static int hf_packetbb_tlv_typeext = -1; static int hf_packetbb_tlv_indexstart = -1; static int hf_packetbb_tlv_indexend = -1; static int hf_packetbb_tlv_length = -1; static int hf_packetbb_tlv_value = -1; static int hf_packetbb_tlv_multivalue = -1; static int hf_packetbb_tlv_intervaltime = -1; static int hf_packetbb_tlv_validitytime = -1; static int hf_packetbb_tlv_localifs = -1; static int hf_packetbb_tlv_linkstatus = -1; static int hf_packetbb_tlv_otherneigh = -1; static int hf_packetbb_tlv_icv = -1; static int hf_packetbb_tlv_timestamp = -1; static int hf_packetbb_tlv_linkmetric_flags_linkin = -1; static int hf_packetbb_tlv_linkmetric_flags_linkout = -1; static int hf_packetbb_tlv_linkmetric_flags_neighin = -1; static int hf_packetbb_tlv_linkmetric_flags_neighout = -1; static int hf_packetbb_tlv_linkmetric_value = -1; static int hf_packetbb_tlv_mpr = -1; static int hf_packetbb_tlv_nbraddrtype = -1; static int hf_packetbb_tlv_gateway = -1; static int hf_packetbb_tlv_mprwillingness = -1; static int hf_packetbb_tlv_mprwillingness_flooding = -1; static int hf_packetbb_tlv_mprwillingness_routing = -1; static int hf_packetbb_tlv_contseqnum = -1; static gint ett_packetbb = -1; static gint ett_packetbb_header = -1; static gint ett_packetbb_header_flags = -1; static gint ett_packetbb_msg[PACKETBB_MSG_TLV_LENGTH]; static gint ett_packetbb_msgheader = -1; static gint ett_packetbb_msgheader_flags = -1; static gint ett_packetbb_addr = -1; static gint ett_packetbb_addr_flags = -1; static gint ett_packetbb_addr_value = -1; static gint ett_packetbb_tlvblock = -1; static gint ett_packetbb_tlv[PACKETBB_MSG_TLV_LENGTH]; static gint ett_packetbb_tlv_flags = -1; static gint ett_packetbb_tlv_value = -1; static gint ett_packetbb_tlv_mprwillingness = -1; static gint ett_packetbb_tlv_linkmetric = -1; static expert_field ei_packetbb_error = EI_INIT; /* Link metric of RFC7181 */ static guint32 uncompress_metric(guint16 val16) { guint8 exp = (val16 >> 8) & 0xf; return (guint32)((((guint16)257U + (val16 & 0xff)) << exp) - 256); } /* Time metric of RFC5497 */ static guint32 uncompress_time(guint8 val8) { guint8 exp = val8 >> 3; gfloat mant = (gfloat)(val8 & 0x07); return (guint32)((1.00 + mant / 8) * (1U << exp)); } static proto_item* dissect_pbb_tlvvalue(tvbuff_t *tvb, proto_tree *tlvTree, guint offset, guint len, guint tlvCat, guint tlvType) { proto_tree *tlv_decoded_value_tree = NULL; proto_tree *tlv_decoded_value_item = NULL; static const int *mprwillingness_values[] = { &hf_packetbb_tlv_mprwillingness_flooding, &hf_packetbb_tlv_mprwillingness_routing, NULL }; switch (tlvCat) { case TLV_CAT_MESSAGE: if (tlvType == RFC7181_MSGTLV_MPR_WILLING) { tlv_decoded_value_item = proto_tree_add_bitmask(tlvTree, tvb, offset, hf_packetbb_tlv_mprwillingness, ett_packetbb_tlv_mprwillingness, mprwillingness_values, ENC_BIG_ENDIAN); break; } else if (tlvType == RFC7181_MSGTLV_CONT_SEQ_NUM) { tlv_decoded_value_item = proto_tree_add_item(tlvTree, hf_packetbb_tlv_contseqnum, tvb, offset, len, ENC_NA); break; } /* other tlvTypes are common with categories PACKET and ADDRESS, do not break. */ /* FALL THROUGH */ case TLV_CAT_PACKET: case TLV_CAT_ADDRESS: switch (tlvType) { case RFC5497_TLV_INTERVAL_TIME: tlv_decoded_value_item = proto_tree_add_item(tlvTree, hf_packetbb_tlv_intervaltime, tvb, offset, len, ENC_NA); proto_item_append_text(tlv_decoded_value_item, " (%d)", uncompress_time(tvb_get_guint8(tvb, offset))); break; case RFC5497_TLV_VALIDITY_TIME: tlv_decoded_value_item = proto_tree_add_item(tlvTree, hf_packetbb_tlv_validitytime, tvb, offset, len, ENC_NA); proto_item_append_text(tlv_decoded_value_item, " (%d)", uncompress_time(tvb_get_guint8(tvb, offset))); break; case RFC6130_ADDRTLV_LOCAL_IF: tlv_decoded_value_item = proto_tree_add_item(tlvTree, hf_packetbb_tlv_localifs, tvb, offset, 1, ENC_NA); break; case RFC6130_ADDRTLV_LINK_STATUS: tlv_decoded_value_item = proto_tree_add_item(tlvTree, hf_packetbb_tlv_linkstatus, tvb, offset, 1, ENC_NA); break; case RFC6130_ADDRTLV_OTHER_NEIGH: tlv_decoded_value_item = proto_tree_add_item(tlvTree, hf_packetbb_tlv_otherneigh, tvb, offset, 1, ENC_NA); break; case RFC7182_TLV_ICV: tlv_decoded_value_item = proto_tree_add_item(tlvTree, hf_packetbb_tlv_icv, tvb, offset, len, ENC_NA); break; case RFC7182_TLV_TIMESTAMP: tlv_decoded_value_item = proto_tree_add_item(tlvTree, hf_packetbb_tlv_timestamp, tvb, offset, len, ENC_NA); break; case RFC7181_ADDRTLV_LINK_METRIC: tlv_decoded_value_tree = proto_tree_add_subtree(tlvTree, tvb, offset, len, ett_packetbb_tlv_linkmetric, NULL, "Link metric"); proto_tree_add_item(tlv_decoded_value_tree, hf_packetbb_tlv_linkmetric_flags_linkin, tvb, offset, 2, ENC_NA); proto_tree_add_item(tlv_decoded_value_tree, hf_packetbb_tlv_linkmetric_flags_linkout, tvb, offset, 2, ENC_NA); proto_tree_add_item(tlv_decoded_value_tree, hf_packetbb_tlv_linkmetric_flags_neighin, tvb, offset, 2, ENC_NA); proto_tree_add_item(tlv_decoded_value_tree, hf_packetbb_tlv_linkmetric_flags_neighout, tvb, offset, 2, ENC_NA); tlv_decoded_value_item = proto_tree_add_item(tlv_decoded_value_tree, hf_packetbb_tlv_linkmetric_value, tvb, offset, 2, ENC_NA); proto_item_append_text(tlv_decoded_value_item, " (%d)", uncompress_metric(tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN))); break; case RFC7181_ADDRTLV_MPR: tlv_decoded_value_item = proto_tree_add_item(tlvTree, hf_packetbb_tlv_mpr, tvb, offset, len, ENC_NA); break; case RFC7181_ADDRTLV_NBR_ADDR_TYPE: tlv_decoded_value_item = proto_tree_add_item(tlvTree, hf_packetbb_tlv_nbraddrtype, tvb, offset, len, ENC_NA); break; case RFC7181_ADDRTLV_GATEWAY: tlv_decoded_value_item = proto_tree_add_item(tlvTree, hf_packetbb_tlv_gateway, tvb, offset, len, ENC_NA); break; } } return tlv_decoded_value_item; } static int dissect_pbb_tlvblock(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint maxoffset, gint8 addrCount, guint tlvCat) { guint16 tlvblockLength; guint tlvblockEnd; proto_tree *tlvblock_tree, *tlv_tree, *tlvValue_tree; proto_item *tlvBlock_item, *tlv_item, *tlvValue_item; int tlvCount = 0; static const int *flags[] = { &hf_packetbb_tlv_flags_hastypext, &hf_packetbb_tlv_flags_hassingleindex, &hf_packetbb_tlv_flags_hasmultiindex, &hf_packetbb_tlv_flags_hasvalue, &hf_packetbb_tlv_flags_hasextlen, &hf_packetbb_tlv_flags_hasmultivalue, NULL }; if (maxoffset < offset + 2) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "Not enough octets for minimal tlvblock"); return maxoffset; } tlvblockLength = tvb_get_ntohs(tvb, offset); tlvblockEnd = offset + 2 + tlvblockLength; if (maxoffset < tlvblockEnd) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "Not enough octets for tlvblock"); return maxoffset; } tlvBlock_item = proto_tree_add_item(tree, hf_packetbb_tlvblock, tvb, offset, tlvblockEnd - offset, ENC_NA); tlvblock_tree = proto_item_add_subtree(tlvBlock_item, ett_packetbb_tlvblock); proto_tree_add_item(tlvblock_tree, hf_packetbb_tlvblock_length, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; while (offset < tlvblockEnd) { guint tlvStart, tlvLength; guint8 tlvType, tlvFlags, /*tlvExtType, */indexStart, indexEnd; guint16 length = 0; int hf_packetbb_tlv_type = 0; const value_string *tlv_type_vals; tlvStart = offset; tlvType = tvb_get_guint8(tvb, offset++); tlvFlags = tvb_get_guint8(tvb, offset++); indexStart = 0; indexEnd = addrCount ? (addrCount - 1) : 0; if ((tlvFlags & TLV_HAS_SINGLEINDEX) != 0) { indexStart = indexEnd = tvb_get_guint8(tvb, offset++); } else if ((tlvFlags & TLV_HAS_MULTIINDEX) != 0) { indexStart = tvb_get_guint8(tvb, offset++); indexEnd = tvb_get_guint8(tvb, offset++); } if ((tlvFlags & TLV_HAS_VALUE) != 0) { if ((tlvFlags & TLV_HAS_EXTLEN) != 0) { length = tvb_get_ntohs(tvb, offset++); } else { length = tvb_get_guint8(tvb, offset++); } } tlvLength = offset - tlvStart + length; offset = tlvStart; tlv_item = proto_tree_add_item(tlvBlock_item, hf_packetbb_tlv, tvb, tlvStart, tlvLength, ENC_NA); tlv_tree = proto_item_add_subtree(tlv_item, ett_packetbb_tlv[tlvType]); /* select possible strings for tlvType */ if (tlvCat == TLV_CAT_PACKET) { hf_packetbb_tlv_type = hf_packetbb_pkttlv_type; tlv_type_vals = pkttlv_type_vals; } else if (tlvCat == TLV_CAT_MESSAGE) { hf_packetbb_tlv_type = hf_packetbb_msgtlv_type; tlv_type_vals = msgtlv_type_vals; } else { /* assume TLV_CAT_ADDRESS */ hf_packetbb_tlv_type = hf_packetbb_addrtlv_type; tlv_type_vals = addrtlv_type_vals; } /* add type */ proto_tree_add_item(tlv_tree, hf_packetbb_tlv_type, tvb, offset++, 1, ENC_BIG_ENDIAN); /* add flags */ proto_tree_add_bitmask(tlv_tree, tvb, offset, hf_packetbb_tlv_flags, ett_packetbb_tlv_flags, flags, ENC_BIG_ENDIAN); offset++; if ((tlvFlags & TLV_HAS_TYPEEXT) != 0) { /* add ext-type */ proto_tree_add_item(tlv_tree, hf_packetbb_tlv_typeext, tvb, offset++, 1, ENC_BIG_ENDIAN); } if (addrCount > 0) { /* add index values */ if ((tlvFlags & TLV_HAS_SINGLEINDEX) != 0) { proto_tree_add_uint(tlv_tree, hf_packetbb_tlv_indexstart, tvb, offset++, 1, indexStart); proto_tree_add_uint_format_value(tlv_tree, hf_packetbb_tlv_indexend, tvb, offset, 0, indexEnd, "%d (implicit)", indexEnd); } else if ((tlvFlags & TLV_HAS_MULTIINDEX) != 0) { proto_tree_add_uint(tlv_tree, hf_packetbb_tlv_indexstart, tvb, offset++, 1, indexStart); proto_tree_add_uint(tlv_tree, hf_packetbb_tlv_indexend, tvb, offset++, 1, indexEnd); } else { proto_tree_add_uint_format_value(tlv_tree, hf_packetbb_tlv_indexstart, tvb, offset, 0, indexStart, "%d (implicit)", indexStart); proto_tree_add_uint_format_value(tlv_tree, hf_packetbb_tlv_indexend, tvb, offset, 0, indexEnd, "%d (implicit)", indexEnd); } } /* add length */ if ((tlvFlags & TLV_HAS_VALUE) != 0) { if ((tlvFlags & TLV_HAS_EXTLEN) != 0) { proto_tree_add_uint(tlv_tree, hf_packetbb_tlv_length, tvb, offset, 2, length); offset += 2; } else { proto_tree_add_uint(tlv_tree, hf_packetbb_tlv_length, tvb, offset++, 1, length); } } else { proto_tree_add_uint_format_value(tlv_tree, hf_packetbb_tlv_length, tvb, offset, 0, 0, "0 (implicit)"); } /* add value */ if (length > 0) { tlvValue_item = proto_tree_add_item(tlv_tree, hf_packetbb_tlv_value, tvb, offset, length, ENC_NA); if ((tlvFlags & TLV_HAS_MULTIVALUE) == 0) { /* single value */ dissect_pbb_tlvvalue(tvb, tlv_tree, offset, length, tlvCat, tlvType); offset += length; } else { /* multiple values */ int i; guint c = indexEnd - indexStart + 1; if (c > 0) { tlvValue_tree = proto_item_add_subtree(tlvValue_item, ett_packetbb_tlv_value); for (i=indexStart; i<=indexEnd; i++) { proto_tree_add_item(tlvValue_tree, hf_packetbb_tlv_multivalue, tvb, offset, length/c, ENC_NA); offset += (length/c); } } } } if (tlv_item) { proto_item_append_text(tlv_item, " (t=%d,l=%d): %s", tlvType, length, val_to_str(tlvType, tlv_type_vals, "Unknown Type (%d)") ); } tlvCount++; } proto_item_append_text(tlvBlock_item, " (%d TLVs)", tlvCount); return offset; } static int dissect_pbb_addressblock(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint maxoffset, guint8 addressType, guint8 addressSize) { guint8 addr[MAX_ADDR_SIZE]; guint8 numAddr; guint8 address_flags; guint8 head_length = 0, tail_length = 0; guint block_length = 0, midSize = 0; guint block_index = 0, head_index = 0, tail_index = 0, mid_index = 0, prefix_index = 0; proto_tree *addr_tree = NULL; proto_tree *addrValue_tree = NULL; proto_item *addr_item = NULL; proto_item *addrValue_item = NULL; int i = 0; static const int *flags[] = { &hf_packetbb_addr_flags_hashead, &hf_packetbb_addr_flags_hasfulltail, &hf_packetbb_addr_flags_haszerotail, &hf_packetbb_addr_flags_hassingleprelen, &hf_packetbb_addr_flags_hasmultiprelen, NULL }; if (maxoffset - offset < 2) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "Not enough octets for minimal addressblock header"); return tvb_reported_length(tvb); } DISSECTOR_ASSERT(addressSize <= MAX_ADDR_SIZE); memset(addr, 0, addressSize); block_length = 2; block_index = offset; midSize = addressSize; numAddr = tvb_get_guint8(tvb, offset++); address_flags = tvb_get_guint8(tvb, offset++); if ((address_flags & ADDR_HASHEAD) != 0) { head_index = offset; if (maxoffset - offset <= 0) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "Not enough octets for addressblock head"); return tvb_reported_length(tvb); } head_length = tvb_get_guint8(tvb, offset++); if (head_length > addressSize-1) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "address head length is too long"); return tvb_reported_length(tvb); } if (maxoffset - offset < head_length) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "Not enough octets for addressblock head"); return tvb_reported_length(tvb); } tvb_memcpy(tvb, addr, offset, head_length); midSize -= head_length; block_length += (head_length+1); offset += head_length; } if ((address_flags & ADDR_HASZEROTAIL) != 0) { tail_index = offset; if (maxoffset - offset <= 0) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "Not enough octets for addressblock tail"); return tvb_reported_length(tvb); } tail_length = tvb_get_guint8(tvb, offset++); if (tail_length > addressSize-1-head_length) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "address tail length is too long"); return tvb_reported_length(tvb); } midSize -= tail_length; block_length++; } else if ((address_flags & ADDR_HASFULLTAIL) != 0) { tail_index = offset; if (maxoffset - offset <= 0) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "Not enough octets for addressblock tail"); return tvb_reported_length(tvb); } tail_length = tvb_get_guint8(tvb, offset++); if (tail_length > addressSize-1-head_length) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "address tail length is too long"); return tvb_reported_length(tvb); } if (maxoffset - offset < tail_length) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "Not enough octets for addressblock tail"); return tvb_reported_length(tvb); } tvb_memcpy(tvb, &addr[addressSize - tail_length], offset, tail_length); midSize -= tail_length; block_length += (tail_length+1); offset += tail_length; } mid_index = offset; block_length += numAddr * midSize; offset += numAddr * midSize; if ((address_flags & ADDR_HASSINGLEPRELEN) != 0) { prefix_index = offset; block_length++; } else if ((address_flags & ADDR_HASMULTIPRELEN) != 0) { prefix_index = offset; block_length += numAddr; } if (maxoffset < block_index + block_length) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, maxoffset - offset, "Not enough octets for address block"); return maxoffset; } /* add address tree */ addr_item = proto_tree_add_item(tree, hf_packetbb_addr, tvb, block_index, block_length, ENC_NA); addr_tree = proto_item_add_subtree(addr_item, ett_packetbb_addr); proto_item_append_text(addr_item, " (%d addresses)", numAddr); /* add num-addr */ proto_tree_add_item(addr_tree, hf_packetbb_addr_num, tvb, block_index, 1, ENC_BIG_ENDIAN); /* add flags */ proto_tree_add_bitmask(addr_tree, tvb, block_index+1, hf_packetbb_addr_flags, ett_packetbb_addr_flags, flags, ENC_BIG_ENDIAN); if ((address_flags & ADDR_HASHEAD) != 0) { /* add head */ proto_tree_add_item(addr_tree, hf_packetbb_addr_head, tvb, head_index, head_length+1, ENC_NA); } if ((address_flags & ADDR_HASFULLTAIL) != 0) { /* add full tail */ proto_tree_add_item(addr_tree, hf_packetbb_addr_tail, tvb, tail_index, tail_length+1, ENC_NA); } else if ((address_flags & ADDR_HASZEROTAIL) != 0) { /* add zero tail */ proto_tree_add_item(addr_tree, hf_packetbb_addr_tail, tvb, tail_index, 1, ENC_NA); } for (i=0; i= messageEnd) { /* this is an error, tlv block is mandatory */ return tvb_reported_length(tvb); } offset = dissect_pbb_tlvblock(tvb, pinfo, message_tree, offset, messageEnd, 0, TLV_CAT_MESSAGE); while (offset < messageEnd) { offset = dissect_pbb_addressblock(tvb, pinfo, message_tree, offset, messageEnd, addressType, addressSize); } return offset; } static int dissect_pbb_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint headerLength, guint tlvIndex) { proto_tree *header_tree; proto_item *header_item; guint8 packet_flags = tvb_get_guint8(tvb, 0); static const int *flags[] = { &hf_packetbb_header_flags_phasseqnum, &hf_packetbb_header_flags_phastlv, NULL }; header_item = proto_tree_add_item(tree, hf_packetbb_header, tvb, 0, headerLength, ENC_NA); header_tree = proto_item_add_subtree(header_item, ett_packetbb_header); /* version */ proto_tree_add_item(header_tree, hf_packetbb_version, tvb, 0, 1, ENC_BIG_ENDIAN); /* flags */ proto_tree_add_bitmask(header_tree, tvb, 0, hf_packetbb_header_flags, ett_packetbb_header_flags, flags, ENC_BIG_ENDIAN); /* sequence number */ if ((packet_flags & PACKET_HEADER_HASSEQNR) != 0) { proto_tree_add_item(header_tree, hf_packetbb_seqnr, tvb, 1, 2, ENC_BIG_ENDIAN); } if ((packet_flags & PACKET_HEADER_HASTLV) != 0) { return dissect_pbb_tlvblock(tvb, pinfo, tree, tlvIndex, tvb_reported_length(tvb), 0, TLV_CAT_PACKET); } return headerLength; } static int dissect_packetbb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) { proto_item *ti; proto_tree *packetbb_tree; guint offset; guint8 packet_flags; guint headerLength = 1; guint tlvIndex = 0; /* Make sure it's a PacketBB packet */ /* calculate header length */ packet_flags = tvb_get_guint8(tvb, 0); if ((packet_flags & PACKET_HEADER_HASSEQNR) != 0) { headerLength += 2; } if ((packet_flags & PACKET_HEADER_HASTLV) != 0) { tlvIndex = headerLength; headerLength += 2; } if (tvb_reported_length(tvb) < headerLength) { return 0; } if ((packet_flags & PACKET_HEADER_HASTLV) != 0) { headerLength += tvb_get_ntohs(tvb, tlvIndex); } if (tvb_reported_length(tvb) < headerLength) { return 0; } /* Reasonably certain it's a PacketBB packet */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "packetbb"); col_clear(pinfo->cinfo, COL_INFO); ti = proto_tree_add_item(tree, proto_packetbb, tvb, 0, -1, ENC_NA); packetbb_tree = proto_item_add_subtree(ti, ett_packetbb); offset = dissect_pbb_header(tvb, pinfo, packetbb_tree, headerLength, tlvIndex); while (offset < tvb_reported_length(tvb)) { offset = dissect_pbb_message(tvb, pinfo, packetbb_tree, offset); } return tvb_captured_length(tvb); } void proto_reg_handoff_packetbb(void) { dissector_handle_t packetbb_handle; packetbb_handle = create_dissector_handle(dissect_packetbb, proto_packetbb); dissector_add_uint_with_preference("udp.port", PACKETBB_PORT, packetbb_handle); } void proto_register_packetbb(void) { /* Setup list of header fields See Section 1.6.1 for details*/ static hf_register_info hf[] = { { &hf_packetbb_header, { "Packet header", "packetbb.header", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_packetbb_version, { "Version", "packetbb.version", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL } }, { &hf_packetbb_header_flags, { "Flags", "packetbb.flags", FT_UINT8, BASE_HEX, NULL, 0x0F, NULL, HFILL } }, { &hf_packetbb_header_flags_phasseqnum, { "Has sequence number", "packetbb.flags.phasseqnum", FT_BOOLEAN, 8, TFS(&tfs_true_false), PACKET_HEADER_HASSEQNR, NULL, HFILL } }, { &hf_packetbb_header_flags_phastlv, { "Has tlv block", "packetbb.flags.phastlv", FT_BOOLEAN, 8, TFS(&tfs_true_false), PACKET_HEADER_HASTLV, NULL, HFILL } }, { &hf_packetbb_seqnr, { "Sequence number", "packetbb.seqnr", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_packetbb_msg, { "Message", "packetbb.msg", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_packetbb_msgheader, { "Message header", "packetbb.msg.header", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_packetbb_msgheader_type, { "Type", "packetbb.msg.type", FT_UINT8, BASE_DEC, VALS(msgheader_type_vals), 0, NULL, HFILL } }, { &hf_packetbb_msgheader_flags, { "Flags", "packetbb.msg.flags", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } }, { &hf_packetbb_msgheader_flags_mhasorig, { "Has originator address", "packetbb.msg.flags.mhasorig", FT_BOOLEAN, 8, TFS(&tfs_true_false), MSG_HEADER_HASORIG, NULL, HFILL } }, { &hf_packetbb_msgheader_flags_mhashoplimit, { "Has hoplimit", "packetbb.msg.flags.mhashoplimit", FT_BOOLEAN, 8, TFS(&tfs_true_false), MSG_HEADER_HASHOPLIMIT, NULL, HFILL } }, { &hf_packetbb_msgheader_flags_mhashopcount, { "Has hopcount", "packetbb.msg.flags.mhashopcount", FT_BOOLEAN, 8, TFS(&tfs_true_false), MSG_HEADER_HASHOPCOUNT, NULL, HFILL } }, { &hf_packetbb_msgheader_flags_mhasseqnr, { "Has sequence number", "packetbb.msg.flags.mhasseqnum", FT_BOOLEAN, 8, TFS(&tfs_true_false), MSG_HEADER_HASSEQNR, NULL, HFILL } }, { &hf_packetbb_msgheader_addresssize, { "AddressSize", "packetbb.msg.addrsize", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_packetbb_msgheader_size, { "Size", "packetbb.msg.size", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_packetbb_msgheader_origaddripv4, { "Originator address", "packetbb.msg.origaddr4", FT_IPv4, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_packetbb_msgheader_origaddripv6, { "Originator address", "packetbb.msg.origaddr6", FT_IPv6, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_packetbb_msgheader_origaddrmac, { "Originator address", "packetbb.msg.origaddrmac", FT_ETHER, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_packetbb_msgheader_origaddrcustom, { "Originator address", "packetbb.msg.origaddrcustom", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_packetbb_msgheader_hoplimit, { "Hop limit", "packetbb.msg.hoplimit", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_packetbb_msgheader_hopcount, { "Hop count", "packetbb.msg.hopcount", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_packetbb_msgheader_seqnr, { "Sequence number", "packetbb.msg.seqnum", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_packetbb_addr, { "Address block", "packetbb.msg.addr", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_packetbb_addr_num, { "Count", "packetbb.msg.addr.num", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_packetbb_addr_flags, { "Flags", "packetbb.msg.addr.flags", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } }, { &hf_packetbb_addr_flags_hashead, { "Has head", "packetbb.msg.addr.hashead", FT_BOOLEAN, 8, TFS(&tfs_true_false), ADDR_HASHEAD, NULL, HFILL } }, { &hf_packetbb_addr_flags_hasfulltail, { "Has full tail", "packetbb.msg.addr.hasfulltail", FT_BOOLEAN, 8, TFS(&tfs_true_false), ADDR_HASFULLTAIL, NULL, HFILL } }, { &hf_packetbb_addr_flags_haszerotail, { "Has zero tail", "packetbb.msg.addr.haszerotail", FT_BOOLEAN, 8, TFS(&tfs_true_false), ADDR_HASZEROTAIL, NULL, HFILL } }, { &hf_packetbb_addr_flags_hassingleprelen, { "Has single prelen", "packetbb.msg.addr.hassingleprelen", FT_BOOLEAN, 8, TFS(&tfs_true_false), ADDR_HASSINGLEPRELEN, NULL, HFILL } }, { &hf_packetbb_addr_flags_hasmultiprelen, { "Has multiple prelen", "packetbb.msg.addr.hasmultiprelen", FT_BOOLEAN, 8, TFS(&tfs_true_false), ADDR_HASMULTIPRELEN, NULL, HFILL } }, { &hf_packetbb_addr_head, { "Head", "packetbb.msg.addr.head", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_packetbb_addr_tail, { "Tail", "packetbb.msg.addr.tail", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_packetbb_addr_value[0], { "Address", "packetbb.msg.addr.value4", FT_IPv4, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_packetbb_addr_value[1], { "Address", "packetbb.msg.addr.value6", FT_IPv6, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_packetbb_addr_value[2], { "Address", "packetbb.msg.addr.valuemac", FT_ETHER, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_packetbb_addr_value[3], { "Address", "packetbb.msg.addr.valuecustom", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_packetbb_addr_value_mid, { "Mid", "packetbb.msg.addr.value.mid", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_packetbb_addr_value_prefix, { "Prefix", "packetbb.msg.addr.value.prefix", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_packetbb_tlvblock, { "TLV block", "packetbb.tlvblock", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_packetbb_tlvblock_length, { "Length", "packetbb.tlvblock.length", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_packetbb_tlv, { "TLV", "packetbb.tlv", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_packetbb_pkttlv_type, { "Type", "packetbb.pkttlv.type", FT_UINT8, BASE_DEC, VALS(pkttlv_type_vals), 0, NULL, HFILL } }, { &hf_packetbb_msgtlv_type, { "Type", "packetbb.msgtlv.type", FT_UINT8, BASE_DEC, VALS(msgtlv_type_vals), 0, NULL, HFILL } }, { &hf_packetbb_addrtlv_type, { "Type", "packetbb.addrtlv.type", FT_UINT8, BASE_DEC, VALS(addrtlv_type_vals), 0, NULL, HFILL } }, { &hf_packetbb_tlv_flags, { "Flags", "packetbb.tlv.flags", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } }, { &hf_packetbb_tlv_typeext, { "Extended Type", "packetbb.tlv.typeext", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_packetbb_tlv_flags_hastypext, { "Has type-ext", "packetbb.tlv.hastypeext", FT_BOOLEAN, 8, TFS(&tfs_true_false), TLV_HAS_TYPEEXT, NULL, HFILL } }, { &hf_packetbb_tlv_flags_hassingleindex, { "Has single index", "packetbb.tlv.hassingleindex", FT_BOOLEAN, 8, TFS(&tfs_true_false), TLV_HAS_SINGLEINDEX, NULL, HFILL } }, { &hf_packetbb_tlv_flags_hasmultiindex, { "Has multiple indices", "packetbb.tlv.hasmultiindex", FT_BOOLEAN, 8, TFS(&tfs_true_false), TLV_HAS_MULTIINDEX, NULL, HFILL } }, { &hf_packetbb_tlv_flags_hasvalue, { "Has value", "packetbb.tlv.hasvalue", FT_BOOLEAN, 8, TFS(&tfs_true_false), TLV_HAS_VALUE, NULL, HFILL } }, { &hf_packetbb_tlv_flags_hasextlen, { "Has extended length", "packetbb.tlv.hasextlen", FT_BOOLEAN, 8, TFS(&tfs_true_false), TLV_HAS_EXTLEN, NULL, HFILL } }, { &hf_packetbb_tlv_flags_hasmultivalue, { "Has multiple values", "packetbb.tlv.hasmultivalue", FT_BOOLEAN, 8, TFS(&tfs_true_false), TLV_HAS_MULTIVALUE, NULL, HFILL } }, { &hf_packetbb_tlv_indexstart, { "Index start", "packetbb.tlv.indexstart", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_packetbb_tlv_indexend, { "Index end", "packetbb.tlv.indexend", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_packetbb_tlv_length, { "Length", "packetbb.tlv.length", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_packetbb_tlv_value, { "Value", "packetbb.tlv.value", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_packetbb_tlv_multivalue, { "Multivalue", "packetbb.tlv.multivalue", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_packetbb_tlv_intervaltime, { "Signaling message interval", "packetbb.tlv.intervaltime", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } }, { &hf_packetbb_tlv_validitytime, { "Message validity time", "packetbb.tlv.validitytime", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } }, { &hf_packetbb_tlv_localifs, { "Local interface status", "packetbb.tlv.localifs", FT_UINT8, BASE_DEC, VALS(localif_vals), 0, NULL, HFILL } }, { &hf_packetbb_tlv_linkstatus, { "Link status", "packetbb.tlv.linkstatus", FT_UINT8, BASE_DEC, VALS(linkstatus_vals), 0, NULL, HFILL } }, { &hf_packetbb_tlv_otherneigh, { "Other neighbor status", "packetbb.tlv.otherneigh", FT_UINT8, BASE_DEC, VALS(otherneigh_vals), 0, NULL, HFILL } }, { &hf_packetbb_tlv_icv, { "Integrity Check Value", "packetbb.tlv.icv", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_packetbb_tlv_timestamp, { "Timestamp", "packetbb.tlv.timestamp", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_packetbb_tlv_mprwillingness, { "MPR willingness", "packetbb.tlv.mprwillingness", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } }, { &hf_packetbb_tlv_mprwillingness_flooding, { "Flooding", "packetbb.tlv.mprwillingnessflooding", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL } }, { &hf_packetbb_tlv_mprwillingness_routing, { "Routing", "packetbb.tlv.mprwillingnessrouting", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL } }, { &hf_packetbb_tlv_contseqnum, { "Content sequence number", "packetbb.tlv.contseqnum", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } }, { &hf_packetbb_tlv_linkmetric_flags_linkin, { "Incoming link", "packetbb.tlv.linkmetriclinkin", FT_BOOLEAN, 16, TFS(&tfs_true_false), RFC7181_LINKMETRIC_INCOMING_LINK, NULL, HFILL } }, { &hf_packetbb_tlv_linkmetric_flags_linkout, { "Outgoing link", "packetbb.tlv.linkmetriclinkout", FT_BOOLEAN, 16, TFS(&tfs_true_false), RFC7181_LINKMETRIC_OUTGOING_LINK, NULL, HFILL } }, { &hf_packetbb_tlv_linkmetric_flags_neighin, { "Incoming neighbor", "packetbb.tlv.linkmetricneighin", FT_BOOLEAN, 16, TFS(&tfs_true_false), RFC7181_LINKMETRIC_INCOMING_NEIGH, NULL, HFILL } }, { &hf_packetbb_tlv_linkmetric_flags_neighout, { "Outgoing neighbor", "packetbb.tlv.linkmetricneighout", FT_BOOLEAN, 16, TFS(&tfs_true_false), RFC7181_LINKMETRIC_OUTGOING_NEIGH, NULL, HFILL } }, { &hf_packetbb_tlv_linkmetric_value, { "Link metric", "packetbb.tlv.linkmetricvalue", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } }, { &hf_packetbb_tlv_mpr, { "Multipoint Relay", "packetbb.tlv.mpr", FT_UINT8, BASE_DEC, VALS(mpr_vals), 0, NULL, HFILL } }, { &hf_packetbb_tlv_nbraddrtype, { "Neighbor address type", "packetbb.tlv.nbraddrtype", FT_UINT8, BASE_DEC, VALS(nbraddrtype_vals), 0, NULL, HFILL } }, { &hf_packetbb_tlv_gateway, { "Gateway", "packetbb.tlv.gateway", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, }; /* Setup protocol subtree array */ gint *ett_base[] = { &ett_packetbb, &ett_packetbb_header, &ett_packetbb_header_flags, &ett_packetbb_msgheader, &ett_packetbb_msgheader_flags, &ett_packetbb_addr, &ett_packetbb_addr_flags, &ett_packetbb_addr_value, &ett_packetbb_tlvblock, &ett_packetbb_tlv_flags, &ett_packetbb_tlv_value, &ett_packetbb_tlv_mprwillingness, &ett_packetbb_tlv_linkmetric }; static ei_register_info ei[] = { { &ei_packetbb_error, { "packetbb.error", PI_PROTOCOL, PI_WARN, "ERROR!", EXPFILL }}, }; static gint *ett[array_length(ett_base) + 2*PACKETBB_MSG_TLV_LENGTH]; expert_module_t* expert_packetbb; int i,j; memcpy(ett, ett_base, sizeof(ett_base)); j = array_length(ett_base); for (i=0; i