aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Ko <jck@exegin.com>2019-01-30 11:05:37 -0800
committerAnders Broman <a.broman58@gmail.com>2019-02-27 05:07:45 +0000
commit8ee96f4ccb948d43584dd9a1a5c7edec81f5287d (patch)
tree45e1baf977cdfe120f4e36a0729bd0f72c41177e
parent8f772029433030e151d82c47ba2c8f065f8f1369 (diff)
Add IEEE 802.15.4 ACK tracking
Add flag to protocol configuration to enable ACK tracking. Fix duplicate strings in dissector. Change-Id: I245f2f2c9aad408a8e8429e8ac5ea5dac37a4f69 Reviewed-on: https://code.wireshark.org/review/32140 Petri-Dish: Stig Bjørlykke <stig@bjorlykke.org> Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman <a.broman58@gmail.com>
-rw-r--r--epan/dissectors/packet-ieee802154.c272
1 files changed, 271 insertions, 1 deletions
diff --git a/epan/dissectors/packet-ieee802154.c b/epan/dissectors/packet-ieee802154.c
index df45fb8371..4bd85482a5 100644
--- a/epan/dissectors/packet-ieee802154.c
+++ b/epan/dissectors/packet-ieee802154.c
@@ -1,6 +1,6 @@
/* packet-ieee802154.c
*
- * 4-byte FCS support
+ * 4-byte FCS support and ACK tracking
* By Carl Levesque Imbeault <carl.levesque@trilliant.com>
* Copyright 2018 Trilliant Inc.
* Integrated and added FCS type enum
@@ -63,6 +63,7 @@
#include <epan/expert.h>
#include <epan/addr_resolv.h>
#include <epan/address_types.h>
+#include <epan/conversation.h>
#include <epan/prefs.h>
#include <epan/uat.h>
#include <epan/strutil.h>
@@ -98,6 +99,9 @@ gint ieee802154_fcs_len = IEEE802154_FCS_LEN;
/* boolean value set if the FCS must be ok before payload is dissected */
static gboolean ieee802154_fcs_ok = TRUE;
+/* boolean value set to enable ack tracking */
+static gboolean ieee802154_ack_tracking = FALSE;
+
static const char *ieee802154_user = "User";
static wmem_tree_t* mac_key_hash_handlers;
@@ -537,6 +541,28 @@ static int hf_ieee802154_key_number = -1;
static int hf_ieee802154_sec_frame_counter = -1;
static int hf_ieee802154_sec_key_sequence_counter = -1;
+/* 802.15.4 ack */
+static int hf_ieee802154_no_ack = -1;
+static int hf_ieee802154_no_ack_request = -1;
+static int hf_ieee802154_ack_in = -1;
+static int hf_ieee802154_ack_to = -1;
+static int hf_ieee802154_ack_time = -1;
+
+typedef struct _ieee802154_transaction_t {
+ guint32 rqst_frame;
+ guint32 ack_frame;
+ nstime_t rqst_time;
+ nstime_t ack_time;
+} ieee802154_transaction_t;
+
+typedef struct _ieee802154_conv_info_t {
+ wmem_tree_t *unmatched_pdus;
+ wmem_tree_t *matched_pdus;
+} ieee802154_conv_info_t;
+
+static ieee802154_transaction_t *transaction_start(packet_info *pinfo, proto_tree *tree, const address *src_addr, const address *dst_addr, guint32 *key);
+static ieee802154_transaction_t *transaction_end(packet_info *pinfo, proto_tree *tree, const address *src_addr, const address *dst_addr, guint32 *key);
+
/* Initialize Subtree Pointers */
static gint ett_ieee802154_nonask_phy = -1;
static gint ett_ieee802154_nonask_phy_phr = -1;
@@ -601,6 +627,8 @@ static expert_field ei_ieee802154_src = EI_INIT;
static expert_field ei_ieee802154_frame_ver = EI_INIT;
/* static expert_field ei_ieee802154_frame_type = EI_INIT; */
static expert_field ei_ieee802154_seqno_suppression = EI_INIT;
+static expert_field ei_ieee802154_ack_not_found = EI_INIT;
+static expert_field ei_ieee802154_ack_request_not_found = EI_INIT;
static expert_field ei_ieee802154_time_correction_error = EI_INIT;
static expert_field ei_ieee802154_6top_unsupported_type = EI_INIT;
static expert_field ei_ieee802154_6top_unsupported_return_code = EI_INIT;
@@ -977,6 +1005,181 @@ static int ieee802_15_4_short_address_len(void)
return 2;
}
+/* ======================================================================= */
+static conversation_t *_find_or_create_conversation(packet_info *pinfo, const address *src_addr, const address *dst_addr)
+{
+ conversation_t *conv = NULL;
+
+ /* Have we seen this conversation before? */
+ conv = find_conversation(pinfo->num, src_addr, dst_addr, ENDPOINT_NONE, 0, 0, 0);
+ if (conv == NULL) {
+ /* No, this is a new conversation. */
+ conv = conversation_new(pinfo->num, src_addr, dst_addr, ENDPOINT_NONE, 0, 0, 0);
+ }
+ return conv;
+}
+
+/* ======================================================================= */
+static ieee802154_transaction_t *transaction_start(packet_info *pinfo, proto_tree *tree, const address *src_addr, const address *dst_addr, guint32 *key)
+{
+ conversation_t *conversation;
+ ieee802154_conv_info_t *ieee802154_info;
+ ieee802154_transaction_t *ieee802154_trans;
+ wmem_tree_key_t ieee802154_key[3];
+ proto_item *it;
+
+ /* Handle the conversation tracking */
+ conversation = _find_or_create_conversation(pinfo, src_addr, dst_addr);
+ ieee802154_info = (ieee802154_conv_info_t *)conversation_get_proto_data(conversation, proto_ieee802154);
+ if (ieee802154_info == NULL) {
+ ieee802154_info = wmem_new(wmem_file_scope(), ieee802154_conv_info_t);
+ ieee802154_info->unmatched_pdus = wmem_tree_new(wmem_file_scope());
+ ieee802154_info->matched_pdus = wmem_tree_new(wmem_file_scope());
+ conversation_add_proto_data(conversation, proto_ieee802154, ieee802154_info);
+ }
+
+ if (!PINFO_FD_VISITED(pinfo)) {
+ /*
+ * This is a new request, create a new transaction structure and map it
+ * to the unmatched table.
+ */
+ ieee802154_key[0].length = 2;
+ ieee802154_key[0].key = key;
+ ieee802154_key[1].length = 0;
+ ieee802154_key[1].key = NULL;
+
+ ieee802154_trans = wmem_new(wmem_file_scope(), ieee802154_transaction_t);
+ ieee802154_trans->rqst_frame = pinfo->num;
+ ieee802154_trans->ack_frame = 0;
+ ieee802154_trans->rqst_time = pinfo->abs_ts;
+ nstime_set_zero(&ieee802154_trans->ack_time);
+ wmem_tree_insert32_array(ieee802154_info->unmatched_pdus, ieee802154_key, (void *)ieee802154_trans);
+ } else {
+ /* Already visited this frame */
+ guint32 frame_num = pinfo->num;
+
+ ieee802154_key[0].length = 2;
+ ieee802154_key[0].key = key;
+ ieee802154_key[1].length = 1;
+ ieee802154_key[1].key = &frame_num;
+ ieee802154_key[2].length = 0;
+ ieee802154_key[2].key = NULL;
+
+ ieee802154_trans = (ieee802154_transaction_t *)wmem_tree_lookup32_array(ieee802154_info->matched_pdus, ieee802154_key);
+ }
+
+ if (ieee802154_trans == NULL) {
+ if (PINFO_FD_VISITED(pinfo)) {
+ /* No ACK found - add field and expert info */
+ it = proto_tree_add_item(tree, hf_ieee802154_no_ack, NULL, 0, 0, ENC_NA);
+ PROTO_ITEM_SET_GENERATED(it);
+
+ expert_add_info_format(pinfo, it, &ei_ieee802154_ack_not_found, "No ack found to ack request in frame %u", pinfo->num);
+ }
+
+ return NULL;
+ }
+
+ /* Print state tracking in the tree */
+ if (ieee802154_trans->ack_frame) {
+ it = proto_tree_add_uint(tree, hf_ieee802154_ack_in, NULL, 0, 0, ieee802154_trans->ack_frame);
+ PROTO_ITEM_SET_GENERATED(it);
+ }
+
+ return ieee802154_trans;
+} /* transaction_start() */
+
+static ieee802154_transaction_t *transaction_end(packet_info *pinfo, proto_tree *tree, const address *src_addr, const address *dst_addr, guint32 *key)
+{
+ conversation_t *conversation;
+ ieee802154_conv_info_t *ieee802154_info = NULL;
+ ieee802154_transaction_t *ieee802154_trans = NULL;
+ wmem_tree_key_t ieee802154_key[3];
+ proto_item *it;
+ nstime_t ns;
+ double ack_time;
+
+ conversation = find_conversation(pinfo->num, src_addr, dst_addr, ENDPOINT_NONE, 0, 0, 0);
+ if (conversation) {
+ ieee802154_info = (ieee802154_conv_info_t *)conversation_get_proto_data(conversation, proto_ieee802154);
+ }
+
+ if (!PINFO_FD_VISITED(pinfo)) {
+ guint32 frame_num;
+
+ if (!ieee802154_info) {
+ return NULL;
+ }
+
+ ieee802154_key[0].length = 2;
+ ieee802154_key[0].key = key;
+ ieee802154_key[1].length = 0;
+ ieee802154_key[1].key = NULL;
+
+ ieee802154_trans = (ieee802154_transaction_t *)wmem_tree_lookup32_array(ieee802154_info->unmatched_pdus, ieee802154_key);
+ if (ieee802154_trans == NULL)
+ return NULL;
+
+ /* we have already seen this response, or an identical one */
+ if (ieee802154_trans->ack_frame != 0)
+ return NULL;
+
+ ieee802154_trans->ack_frame = pinfo->num;
+
+ /*
+ * We found a match. Add entries to the matched table for both
+ * request and ack frames
+ */
+ ieee802154_key[0].length = 2;
+ ieee802154_key[0].key = key;
+ ieee802154_key[1].length = 1;
+ ieee802154_key[1].key = &frame_num;
+ ieee802154_key[2].length = 0;
+ ieee802154_key[2].key = NULL;
+
+ frame_num = ieee802154_trans->rqst_frame;
+ wmem_tree_insert32_array(ieee802154_info->matched_pdus, ieee802154_key, (void *)ieee802154_trans);
+
+ frame_num = ieee802154_trans->ack_frame;
+ wmem_tree_insert32_array(ieee802154_info->matched_pdus, ieee802154_key, (void *)ieee802154_trans);
+ } else {
+ /* Already visited this frame */
+ guint32 frame_num = pinfo->num;
+
+ if (ieee802154_info) {
+ ieee802154_key[0].length = 2;
+ ieee802154_key[0].key = key;
+ ieee802154_key[1].length = 1;
+ ieee802154_key[1].key = &frame_num;
+ ieee802154_key[2].length = 0;
+ ieee802154_key[2].key = NULL;
+
+ ieee802154_trans = (ieee802154_transaction_t *)wmem_tree_lookup32_array(ieee802154_info->matched_pdus, ieee802154_key);
+ }
+ if (!ieee802154_trans) {
+ /* No ack request found - add field and expert info */
+ it = proto_tree_add_item(tree, hf_ieee802154_no_ack_request, NULL, 0, 0, ENC_NA);
+ PROTO_ITEM_SET_GENERATED(it);
+
+ expert_add_info_format(pinfo, it, &ei_ieee802154_ack_request_not_found, "No ack request found to ack in frame %u", pinfo->num);
+ return NULL;
+ }
+ }
+
+ /* Print state tracking in the tree */
+ it = proto_tree_add_uint(tree, hf_ieee802154_ack_to, NULL, 0, 0, ieee802154_trans->rqst_frame);
+ PROTO_ITEM_SET_GENERATED(it);
+
+ nstime_delta(&ns, &pinfo->abs_ts, &ieee802154_trans->rqst_time);
+ ieee802154_trans->ack_time = ns;
+ ack_time = nstime_to_msec(&ns);
+ it = proto_tree_add_double_format_value(tree, hf_ieee802154_ack_time, NULL, 0, 0, ack_time, "%.3f ms", ack_time);
+ PROTO_ITEM_SET_GENERATED(it);
+
+ return ieee802154_trans;
+
+} /* transaction_end() */
+
/**
* Dissector helper, parses and displays the frame control field.
*
@@ -1411,6 +1614,45 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g
}
ieee802154_dissect_fcs(tvb, pinfo, ieee802154_tree, options & DISSECT_IEEE802154_OPTION_CC24xx, fcs_ok);
+
+ if (ieee802154_ack_tracking && fcs_ok && (packet->ack_request || packet->frame_type == IEEE802154_FCF_ACK)) {
+ address src_addr;
+ address dst_addr;
+ guint32 key[2] = {0};
+
+ key[0] = packet->seqno;
+ if (pinfo->rec->presence_flags & WTAP_HAS_INTERFACE_ID) {
+ key[1] = pinfo->rec->rec_header.packet_header.interface_id;
+ }
+
+ if (packet->src_addr_mode == IEEE802154_FCF_ADDR_NONE) {
+ set_address(&src_addr, AT_NONE, 0, NULL);
+ }
+ else if (packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT) {
+ set_address(&src_addr, AT_EUI64, 2, &packet->src16);
+ }
+ else {
+ set_address(&src_addr, AT_EUI64, 8, &packet->src64);
+ }
+
+ if (packet->dst_addr_mode == IEEE802154_FCF_ADDR_NONE) {
+ set_address(&dst_addr, AT_NONE, 0, NULL);
+ }
+ else if (packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) {
+ set_address(&dst_addr, AT_EUI64, 2, &packet->dst16);
+ }
+ else {
+ set_address(&dst_addr, AT_EUI64, 8, &packet->dst64);
+ }
+
+ if (packet->ack_request) {
+ transaction_start(pinfo, ieee802154_tree, &src_addr, &dst_addr, key);
+ }
+ else {
+ transaction_end(pinfo, ieee802154_tree, &src_addr, &dst_addr, key);
+ }
+ }
+
}
guint
@@ -5097,6 +5339,26 @@ void proto_register_ieee802154(void)
{ "Key Sequence Counter", "wpan.sec_key_sequence_counter", FT_UINT8, BASE_HEX, NULL, 0x0,
"Key Sequence counter of the originator of the protected frame (802.15.4-2003)", HFILL }},
+ { &hf_ieee802154_no_ack,
+ { "No ack found", "wpan.no_ack", FT_NONE, BASE_NONE, NULL, 0x0,
+ "No corresponding ack frame was found", HFILL }},
+
+ { &hf_ieee802154_no_ack_request,
+ { "No ack request found", "wpan.no_ack_request", FT_NONE, BASE_NONE, NULL, 0x0,
+ "No corresponding ack request frame was found", HFILL }},
+
+ { &hf_ieee802154_ack_in,
+ { "Ack In", "wpan.ack_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ "The ack to this request is in this frame", HFILL }},
+
+ { &hf_ieee802154_ack_to,
+ { "Ack To", "wpan.ack_to", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_ACK), 0x0,
+ "This is the ack to the request in this frame", HFILL }},
+
+ { &hf_ieee802154_ack_time,
+ { "Ack Time", "wpan.ack_time", FT_DOUBLE, BASE_NONE, NULL, 0x0,
+ "The time between the request and the ack, in ms.", HFILL }},
+
/* ZBOSS dump */
{ &hf_zboss_page,
@@ -5193,6 +5455,10 @@ void proto_register_ieee802154(void)
"Decryption error", EXPFILL }},
{ &ei_ieee802154_fcs, { "wpan.fcs.bad", PI_CHECKSUM, PI_WARN,
"Bad FCS", EXPFILL }},
+ { &ei_ieee802154_ack_not_found, { "wpan.ack_not_found", PI_SEQUENCE, PI_NOTE,
+ "Ack not found", EXPFILL }},
+ { &ei_ieee802154_ack_request_not_found, { "wpan.ack_request_not_found", PI_SEQUENCE, PI_NOTE,
+ "Ack request not found", EXPFILL }},
{ &ei_ieee802154_seqno_suppression, { "wpan.seqno_suppression_invalid", PI_MALFORMED, PI_WARN,
"Sequence Number Suppression invalid for 802.15.4-2003 and 2006", EXPFILL }},
{ &ei_ieee802154_6top_unsupported_type, { "wpan.6top_unsupported_type", PI_PROTOCOL, PI_WARN,
@@ -5301,6 +5567,10 @@ void proto_register_ieee802154(void)
"Dissect only good FCS",
"Dissect payload only if FCS is valid.",
&ieee802154_fcs_ok);
+ prefs_register_bool_preference(ieee802154_module, "802154_ack_tracking",
+ "Enable ACK tracking",
+ "Match frames with ACK request to ACK packets",
+ &ieee802154_ack_tracking);
/* Create a UAT for static address mappings. */
static_addr_uat = uat_new("Static Addresses",