ZigBee: Add APS conversations and extended counter

The APS counter is only 8-bit, which causes trouble for the
reassembly of fragments because packet counters are reused.

With this change the counter is extended to 32-bit to avoid
packet counter clashes.

Inspiration is taken from the RTP dissector.

Bug: 15021
Change-Id: Ibc61f40dd12b7a1bfd69b24ed5200d31229b69cb
Reviewed-on: https://code.wireshark.org/review/35072
Petri-Dish: Alexis La Goutte <alexis.lagoutte@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
Kenneth Soerensen 2019-11-12 15:08:38 +01:00 committed by Anders Broman
parent a924de1e3e
commit 90e4da60bc
2 changed files with 97 additions and 11 deletions

View File

@ -19,6 +19,7 @@
#include <epan/expert.h>
#include <epan/reassemble.h>
#include <epan/proto_data.h>
#include <epan/conversation.h>
#include "packet-zbee.h"
#include "packet-zbee-nwk.h"
@ -691,6 +692,62 @@ const value_string zbee_aps_t2_btres_status_names[] = {
#define ZBEE_APS_FRAG_BLOCK7_ACK 0x40
#define ZBEE_APS_FRAG_BLOCK8_ACK 0x80
/* calculate the extended counter - top 24 bits of the previous counter,
* plus our own; then correct for wrapping */
static guint32
zbee_aps_calculate_extended_counter(guint32 previous_counter, guint8 raw_counter)
{
guint32 counter = (previous_counter & 0xffffff00) | raw_counter;
if ((counter + 0x40) < previous_counter) {
counter += 0x100;
} else if ((previous_counter + 0x40) < counter) {
/* we got an out-of-order packet which happened to go backwards over the
* wrap boundary */
counter -= 0x100;
}
return counter;
}
static struct zbee_aps_conversation_packet_info*
zbee_aps_conversation_packet_info(packet_info *pinfo, const zbee_nwk_packet *nwk, const zbee_aps_packet *packet)
{
struct zbee_aps_conversation_packet_info *conv_data_packet;
conv_data_packet = (struct zbee_aps_conversation_packet_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_zbee_aps, ZBEE_APS_CONVERSATION_PROTO_DATA);
if (conv_data_packet == NULL) {
conversation_t *conv;
struct zbee_aps_conversation_info *conv_data;
guint32 counter;
conv = find_or_create_conversation(pinfo);
conv_data = (struct zbee_aps_conversation_info *)conversation_get_proto_data(conv, proto_zbee_aps);
if (conv_data == NULL) {
conv_data = wmem_new0(wmem_file_scope(), struct zbee_aps_conversation_info);
conv_data->a.extended_counter = 0x100;
conv_data->a.address = nwk->src;
conv_data->b.extended_counter = 0x100;
conv_data->b.address = nwk->dst;
conversation_add_proto_data(conv, proto_zbee_aps, conv_data);
}
conv_data_packet = wmem_new(wmem_file_scope(), struct zbee_aps_conversation_packet_info);
p_add_proto_data(wmem_file_scope(), pinfo, proto_zbee_aps, ZBEE_APS_CONVERSATION_PROTO_DATA, conv_data_packet);
if (((nwk->src == conv_data->a.address) && (packet->type != ZBEE_APS_FCF_ACK)) ||
((nwk->dst == conv_data->a.address) && (packet->type == ZBEE_APS_FCF_ACK))) {
counter = zbee_aps_calculate_extended_counter(conv_data->a.extended_counter, packet->counter);
conv_data->a.extended_counter = counter;
}
else {
counter = zbee_aps_calculate_extended_counter(conv_data->b.extended_counter, packet->counter);
conv_data->b.extended_counter = counter;
}
conv_data_packet->extended_counter = counter;
}
return conv_data_packet;
}
/**
*ZigBee Application Support Sublayer dissector for wireshark.
*
@ -701,19 +758,21 @@ const value_string zbee_aps_t2_btres_status_names[] = {
static int
dissect_zbee_aps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
{
tvbuff_t *payload_tvb = NULL;
dissector_handle_t profile_handle = NULL;
dissector_handle_t zcl_handle = NULL;
tvbuff_t *payload_tvb = NULL;
dissector_handle_t profile_handle = NULL;
dissector_handle_t zcl_handle = NULL;
proto_tree *aps_tree;
proto_tree *field_tree;
proto_item *proto_root;
proto_tree *aps_tree;
proto_tree *field_tree;
proto_item *proto_root;
zbee_aps_packet packet;
zbee_nwk_packet *nwk;
zbee_aps_packet packet;
zbee_nwk_packet *nwk;
guint8 fcf;
guint8 offset = 0;
struct zbee_aps_conversation_packet_info *conv_data_packet;
guint8 fcf;
guint8 offset = 0;
static const int * frag_ack_flags[] = {
&hf_zbee_aps_block_ack1,
@ -943,6 +1002,8 @@ dissect_zbee_aps_no_endpt:
offset += 1;
}
conv_data_packet = zbee_aps_conversation_packet_info(pinfo, nwk, &packet);
/* Get and display the extended header, if present. */
if (packet.ext_header) {
fcf = tvb_get_guint8(tvb, offset);
@ -1002,7 +1063,7 @@ dissect_zbee_aps_no_endpt:
* for each message (fragmented or not). Hash these two together to
* create the message id for the fragmentation handler.
*/
msg_id = ((nwk->src)<<8) + packet.counter;
msg_id = ((nwk->src)<<16) + (conv_data_packet->extended_counter & 0xffff);
/* If this is the first block of a fragmented message, than the block
* number field is the maximum number of blocks in the message. Otherwise

View File

@ -268,6 +268,8 @@
#define ZBEE_APP_STATUS_UNSECURED 0xaf /*An ASDU was received without any security.*/
#define ZBEE_APP_STATUS_UNSUPPORTED_ATTRIBUTE 0xb0 /*An APSME-GET.request or APSME-SET.request has been issued with an unknown attribute identifier.*/
#define ZBEE_APS_CONVERSATION_PROTO_DATA 0
/* Structure to contain the APS frame information */
typedef struct{
gboolean indirect_mode; /* ZigBee 2004 and Earlier */
@ -294,6 +296,29 @@ typedef struct{
gboolean src_present;
} zbee_aps_packet;
/* Structure to contain APS conversation endpoint information */
struct zbee_aps_conversation_endpoint {
guint32 extended_counter; /**> the counter, extended to a 32-bit
* int to guarantee it increasing monotonically
*/
guint16 address;
};
/* Structure to contain APS conversation information */
struct zbee_aps_conversation_info
{
struct zbee_aps_conversation_endpoint a;
struct zbee_aps_conversation_endpoint b;
};
/* Structure to contain APS conversation information for a packet */
struct zbee_aps_conversation_packet_info
{
guint32 extended_counter; /**> the counter, extended to a 32-bit
* int to guarantee it increasing monotonically
*/
};
/* ZigBee Smart Energy version used for preferences */
extern gint gPREF_zbee_se_protocol_version;