static int dissect_pbb_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint headerLength, guint tlvIndex) { proto_tree *header_tree; proto_tree *headerFlags_tree; proto_item *header_item; proto_item *headerFlags_item; guint8 packet_flags = tvb_get_guint8(tvb, 0); 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_uint(header_tree, hf_packetbb_version, tvb, 0, 1, packet_flags >> 4); /* flags */ headerFlags_item = proto_tree_add_item(header_tree, hf_packetbb_header_flags, tvb, 0, 1, ENC_BIG_ENDIAN); headerFlags_tree = proto_item_add_subtree(headerFlags_item, ett_packetbb_header_flags); proto_tree_add_item(headerFlags_tree, hf_packetbb_header_flags_phasseqnum, tvb, 0, 1, ENC_NA); proto_tree_add_item(headerFlags_tree, hf_packetbb_header_flags_phastlv, tvb, 0, 1, ENC_NA); /* 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); } return headerLength; }
static int dissect_pbb_header(tvbuff_t *tvb, proto_tree *tree) { proto_tree *header_tree = NULL; proto_tree *headerFlags_tree = NULL; proto_item *header_item = NULL; proto_item *headerFlags_item = NULL; guint8 packet_flags; guint headerLength = 1; guint tlvIndex = 0; /* 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) { proto_tree_add_bytes_format(tree, hf_packetbb_error, tvb, 0, -1, tvb_get_ptr(tvb, 0, -1), "Not enough octets for packetbb header"); return tvb_reported_length(tvb); } if ((packet_flags & PACKET_HEADER_HASTLV) != 0) { headerLength += tvb_get_ntohs(tvb, tlvIndex); } if (tvb_reported_length(tvb) < headerLength) { proto_tree_add_bytes_format(tree, hf_packetbb_error, tvb, 0, -1, tvb_get_ptr(tvb, 0, -1), "Not enough octets for packetbb tlvblock"); return tvb_reported_length(tvb); } header_item = proto_tree_add_item(tree, hf_packetbb_header, tvb, 0, headerLength, FALSE); header_tree = proto_item_add_subtree(header_item, ett_packetbb_header); /* version */ proto_tree_add_uint(header_tree, hf_packetbb_version, tvb, 0, 1, packet_flags >> 4); /* flags */ headerFlags_item = proto_tree_add_uint(header_tree, hf_packetbb_header_flags, tvb, 0, 1, packet_flags & 0x0f); headerFlags_tree = proto_item_add_subtree(headerFlags_item, ett_packetbb_header_flags); proto_tree_add_boolean(headerFlags_tree, hf_packetbb_header_flags_phasseqnum, tvb, 0, 1, packet_flags); proto_tree_add_boolean(headerFlags_tree, hf_packetbb_header_flags_phastlv, tvb, 0, 1, packet_flags); /* sequence number */ if ((packet_flags & PACKET_HEADER_HASSEQNR) != 0) { proto_tree_add_item(header_tree, hf_packetbb_seqnr, tvb, 1, 2, FALSE); } if ((packet_flags & PACKET_HEADER_HASTLV) != 0) { return dissect_pbb_tlvblock(tvb, tree, tlvIndex, tvb_reported_length(tvb), 0); } return headerLength; }
static int dissect_pbb_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { proto_tree *message_tree = NULL; proto_tree *header_tree = NULL; proto_tree *headerFlags_tree = NULL; proto_item *message_item = NULL; proto_item *header_item = NULL; proto_item *headerFlags_item = NULL; guint8 messageType; guint8 messageFlags; guint16 messageLength, headerLength, messageEnd; guint8 addressSize, addressType; if (tvb_reported_length(tvb) - offset < 6) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, -1, "Not enough octets for minimal message header"); return tvb_reported_length(tvb); } messageType = tvb_get_guint8(tvb, offset); messageFlags = tvb_get_guint8(tvb, offset+1); messageLength = tvb_get_ntohs(tvb, offset+2); addressSize = (messageFlags & 0x0f) + 1; switch (addressSize) { case 4: addressType = 0; break; case 16: addressType = 1; break; case 6: addressType = 2; break; default: addressType = 3; break; } messageEnd = offset + messageLength; headerLength = 4; /* calculate header size */ if ((messageFlags & MSG_HEADER_HASORIG) != 0) { headerLength += addressSize; } if ((messageFlags & MSG_HEADER_HASHOPLIMIT) != 0) { headerLength ++; } if ((messageFlags & MSG_HEADER_HASHOPCOUNT) != 0) { headerLength ++; } if ((messageFlags & MSG_HEADER_HASSEQNR) != 0) { headerLength += 2; } /* test length for message size */ if (tvb_reported_length(tvb) - offset < messageLength) { proto_tree_add_expert_format(tree, pinfo, &ei_packetbb_error, tvb, offset, -1, "Not enough octets for message"); return tvb_reported_length(tvb); } message_item = proto_tree_add_item(tree, hf_packetbb_msg, tvb, offset, messageLength, ENC_NA); message_tree = proto_item_add_subtree(message_item, ett_packetbb_msg[messageType]); proto_item_append_text(message_item, " (type %d)", messageType); header_item = proto_tree_add_item(message_tree, hf_packetbb_msgheader, tvb, offset, headerLength, ENC_NA); header_tree = proto_item_add_subtree(header_item, ett_packetbb_msgheader); /* type */ proto_tree_add_item(header_tree, hf_packetbb_msgheader_type, tvb, offset, 1, ENC_BIG_ENDIAN); /* flags */ headerFlags_item = proto_tree_add_uint(header_tree, hf_packetbb_msgheader_flags, tvb, offset+1, 1, messageFlags & 0xf8); headerFlags_tree = proto_item_add_subtree(headerFlags_item, ett_packetbb_msgheader_flags); proto_tree_add_boolean(headerFlags_tree, hf_packetbb_msgheader_flags_mhasorig, tvb, offset+1, 1, messageFlags); proto_tree_add_boolean(headerFlags_tree, hf_packetbb_msgheader_flags_mhashoplimit, tvb, offset+1, 1, messageFlags); proto_tree_add_boolean(headerFlags_tree, hf_packetbb_msgheader_flags_mhashopcount, tvb, offset+1, 1, messageFlags); proto_tree_add_boolean(headerFlags_tree, hf_packetbb_msgheader_flags_mhasseqnr, tvb, offset+1, 1, messageFlags); proto_tree_add_uint(header_tree, hf_packetbb_msgheader_addresssize, tvb, offset + 1, 1, (messageFlags & 0x0f) + 1); /* size */ proto_tree_add_item(header_tree, hf_packetbb_msgheader_size, tvb, offset+2, 2, ENC_BIG_ENDIAN); offset += 4; /* originator address */ if ((messageFlags & MSG_HEADER_HASORIG) != 0) { switch (addressSize) { case 4: /* IPv4 */ proto_tree_add_item(header_tree, hf_packetbb_msgheader_origaddripv4, tvb, offset, addressSize, ENC_BIG_ENDIAN); break; case 16: /* IPv6 */ proto_tree_add_item(header_tree, hf_packetbb_msgheader_origaddripv6, tvb, offset, addressSize, ENC_NA); break; case 6: /* MAC */ proto_tree_add_item(header_tree, hf_packetbb_msgheader_origaddrmac, tvb, offset, addressSize, ENC_NA); break; default: /* Unknown */ proto_tree_add_item(header_tree, hf_packetbb_msgheader_origaddrcustom, tvb, offset, addressSize, ENC_NA); break; } offset += addressSize; } /* hop limit */ if ((messageFlags & MSG_HEADER_HASHOPLIMIT) != 0) { proto_tree_add_item(header_tree, hf_packetbb_msgheader_hoplimit, tvb, offset++, 1, ENC_BIG_ENDIAN); } /* hop count */ if ((messageFlags & MSG_HEADER_HASHOPCOUNT) != 0) { proto_tree_add_item(header_tree, hf_packetbb_msgheader_hopcount, tvb, offset++, 1, ENC_BIG_ENDIAN); } /* sequence number */ if ((messageFlags & MSG_HEADER_HASSEQNR) != 0) { proto_tree_add_item(header_tree, hf_packetbb_msgheader_seqnr, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; } if (offset >= 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); while (offset < messageEnd) { offset = dissect_pbb_addressblock(tvb, pinfo, message_tree, offset, messageEnd, addressType, addressSize); } 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 *addrFlags_tree = NULL; proto_tree *addrValue_tree = NULL; proto_item *addr_item = NULL; proto_item *addrFlags_item = NULL; proto_item *addrValue_item = NULL; int i = 0; 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 */ addrFlags_item = proto_tree_add_item(addr_tree, hf_packetbb_addr_flags, tvb, block_index+1, 1, ENC_BIG_ENDIAN); addrFlags_tree = proto_item_add_subtree(addrFlags_item, ett_packetbb_addr_flags); proto_tree_add_item(addrFlags_tree, hf_packetbb_addr_flags_hashead, tvb, block_index+1, 1, ENC_BIG_ENDIAN); proto_tree_add_item(addrFlags_tree, hf_packetbb_addr_flags_hasfulltail, tvb, block_index+1, 1, ENC_BIG_ENDIAN); proto_tree_add_item(addrFlags_tree, hf_packetbb_addr_flags_haszerotail, tvb, block_index+1, 1, ENC_BIG_ENDIAN); proto_tree_add_item(addrFlags_tree, hf_packetbb_addr_flags_hassingleprelen, tvb, block_index+1, 1, ENC_BIG_ENDIAN); proto_tree_add_item(addrFlags_tree, hf_packetbb_addr_flags_hasmultiprelen, tvb, block_index+1, 1, 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<numAddr; i++) { guint32 ipv4 = 0; guint8 prefix = addressSize * 8; tvb_memcpy(tvb, &addr[head_length], mid_index + midSize*i, midSize); ipv4 = (addr[3] << 24) + (addr[2] << 16) + (addr[1] << 8) + addr[0]; switch (addressType) { case 0: addrValue_item = proto_tree_add_ipv4(addr_tree, hf_packetbb_addr_value[addressType], tvb, mid_index, block_index + block_length - mid_index, ipv4); break; case 1: addrValue_item = proto_tree_add_ipv6(addr_tree, hf_packetbb_addr_value[addressType], tvb, mid_index, block_index + block_length - mid_index, (struct e_in6_addr *)addr); break; case 2: addrValue_item = proto_tree_add_ether(addr_tree, hf_packetbb_addr_value[addressType], tvb, mid_index, block_index + block_length - mid_index, addr); break; case 3: addrValue_item = proto_tree_add_bytes(addr_tree, hf_packetbb_addr_value[addressType], tvb, mid_index, block_index + block_length - mid_index, addr); break; default: break; } addrValue_tree = proto_item_add_subtree(addrValue_item, ett_packetbb_addr_value); proto_tree_add_item(addrValue_tree, hf_packetbb_addr_value_mid, tvb, mid_index + midSize*i, midSize, ENC_NA); if ((address_flags & ADDR_HASSINGLEPRELEN) != 0) { prefix = tvb_get_guint8(tvb, prefix_index); proto_tree_add_item(addrValue_tree, hf_packetbb_addr_value_prefix, tvb, prefix_index, 1, ENC_BIG_ENDIAN); } else if ((address_flags & ADDR_HASMULTIPRELEN) != 0) { prefix = tvb_get_guint8(tvb, prefix_index + i); proto_tree_add_item(addrValue_tree, hf_packetbb_addr_value_prefix, tvb, prefix_index + i, 1, ENC_BIG_ENDIAN); } proto_item_append_text(addrValue_item, "/%d", prefix); } offset = dissect_pbb_tlvblock(tvb, pinfo, addr_tree, block_index + block_length, maxoffset, numAddr); return offset; }