wireshark/epan/dissectors/packet-ieee802154.c

4586 lines
198 KiB
C

/* packet-ieee802154.c
*
* Auxiliary Security Header support and
* option to force TI CC24xx FCS format
* By Jean-Francois Wauthy <jfw@info.fundp.ac.be>
* Copyright 2009 The University of Namur, Belgium
*
* IEEE 802.15.4 Dissectors for Wireshark
* By Owen Kirby <osk@exegin.com>
* Copyright 2007 Exegin Technologies Limited
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*------------------------------------------------------------
*
* In IEEE 802.15.4 packets, all fields are little endian. And
* Each byte is transmitted least significant bit first (reflected
* bit ordering).
*------------------------------------------------------------
*
* IEEE 802.15.4 Packets have the following format:
* | FCF |Seq No| Addressing | Data | FCS |
* |2 bytes|1 byte|0 to 20 bytes|Length-(Overhead) bytes|2 Bytes|
*------------------------------------------------------------
*
* CRC16 is calculated using the x^16 + x^12 + x^5 + 1 polynomial
* as specified by ITU-T, and is calculated over the IEEE 802.15.4
* packet (excluding the FCS) as transmitted over the air. Note,
* that because the least significan bits are transmitted first, this
* will require reversing the bit-order in each byte. Also, unlike
* most CRC algorithms, IEEE 802.15.4 uses an initial and final value
* of 0x0000, instead of 0xffff (which is used by the CCITT).
*------------------------------------------------------------
*
* This dissector supports both link-layer IEEE 802.15.4 captures
* and IEEE 802.15.4 packets encapsulated within other layers.
* Additionally, support has been provided for various formats
* of the frame check sequence:
* - IEEE 802.15.4 compliant FCS.
* - ChipCon/Texas Instruments CC24xx style FCS.
*------------------------------------------------------------
*/
/* Include files */
#include "config.h"
#include <epan/packet.h>
#include <epan/decode_as.h>
#include <epan/exceptions.h>
#include <epan/crc16-tvb.h>
#include <epan/expert.h>
#include <epan/addr_resolv.h>
#include <epan/address_types.h>
#include <epan/prefs.h>
#include <epan/uat.h>
#include <epan/strutil.h>
#include <epan/to_str.h>
#include <epan/show_exception.h>
#include <epan/proto_data.h>
#include <wsutil/pint.h>
/* Use libgcrypt for cipher libraries. */
#include <wsutil/wsgcrypt.h>
#include "packet-ieee802154.h"
#include "packet-sll.h"
void proto_register_ieee802154(void);
void proto_reg_handoff_ieee802154(void);
/* Dissection Options for dissect_ieee802154_common */
#define DISSECT_IEEE802154_OPTION_CC24xx 0x00000001 /* FCS field contains a TI CC24xx style FCS. */
#define DISSECT_IEEE802154_OPTION_LINUX 0x00000002 /* Addressing fields are padded DLT_IEEE802_15_4_LINUX, not implemented. */
#define DISSECT_IEEE802154_OPTION_ZBOSS 0x00000004 /* ZBOSS traffic dump */
/* ethertype for 802.15.4 tag - encapsulating an Ethernet packet */
static unsigned int ieee802154_ethertype = 0x809A;
/* boolean value set if the FCS field is using the TI CC24xx format */
static gboolean ieee802154_cc24xx = FALSE;
/* boolean value set if the FCS must be ok before payload is dissected */
static gboolean ieee802154_fcs_ok = TRUE;
static const char *ieee802154_user = "User";
static wmem_tree_t* mac_key_hash_handlers;
/*
* Address Hash Tables
*
*/
ieee802154_map_tab_t ieee802154_map = { NULL, NULL };
/*
* Static Address Mapping UAT
*
*/
/* UAT entry structure. */
typedef struct {
guchar *eui64;
guint eui64_len;
guint addr16;
guint pan;
} static_addr_t;
/* UAT variables */
static uat_t *static_addr_uat = NULL;
static static_addr_t *static_addrs = NULL;
static guint num_static_addrs = 0;
/* Sanity-checks a UAT record. */
static gboolean
addr_uat_update_cb(void *r, char **err)
{
static_addr_t *map = (static_addr_t *)r;
/* Ensure a valid short address */
if (map->addr16 >= IEEE802154_NO_ADDR16) {
*err = g_strdup("Invalid short address");
return FALSE;
}
/* Ensure a valid PAN identifier. */
if (map->pan >= IEEE802154_BCAST_PAN) {
*err = g_strdup("Invalid PAN identifier");
return FALSE;
}
/* Ensure a valid EUI-64 length */
if (map->eui64_len != sizeof(guint64)) {
*err = g_strdup("Invalid EUI-64 length");
return FALSE;
}
return TRUE;
} /* ieee802154_addr_uat_update_cb */
/* Field callbacks. */
UAT_HEX_CB_DEF(addr_uat, addr16, static_addr_t)
UAT_HEX_CB_DEF(addr_uat, pan, static_addr_t)
UAT_BUFFER_CB_DEF(addr_uat, eui64, static_addr_t, eui64, eui64_len)
/*
* Key Decryption UAT
*
*/
/* UAT variables */
static uat_t *ieee802154_key_uat = NULL;
static ieee802154_key_t *ieee802154_keys = NULL;
static guint num_ieee802154_keys = 0;
static void ieee802154_key_post_update_cb(void)
{
guint i;
GByteArray *bytes;
for (i = 0; i < num_ieee802154_keys; i++)
{
switch (ieee802154_keys[i].hash_type) {
case KEY_HASH_NONE:
case KEY_HASH_ZIP:
/* Get the IEEE 802.15.4 decryption key. */
bytes = g_byte_array_new();
if (hex_str_to_bytes(ieee802154_keys[i].pref_key, bytes, FALSE))
{
if (ieee802154_keys[i].hash_type == KEY_HASH_ZIP) {
char digest[32];
if (!ws_hmac_buffer(GCRY_MD_SHA256, digest, "ZigBeeIP", 8, bytes->data, IEEE802154_CIPHER_SIZE)) {
/* Copy upper hashed bytes to the key */
memcpy(ieee802154_keys[i].key, &digest[IEEE802154_CIPHER_SIZE], IEEE802154_CIPHER_SIZE);
/* Copy lower hashed bytes to the MLE key */
memcpy(ieee802154_keys[i].mle_key, digest, IEEE802154_CIPHER_SIZE);
} else {
/* Just copy the keys verbatim */
memcpy(ieee802154_keys[i].key, bytes->data, IEEE802154_CIPHER_SIZE);
memcpy(ieee802154_keys[i].mle_key, bytes->data, IEEE802154_CIPHER_SIZE);
}
} else {
/* Just copy the keys verbatim */
memcpy(ieee802154_keys[i].key, bytes->data, IEEE802154_CIPHER_SIZE);
memcpy(ieee802154_keys[i].mle_key, bytes->data, IEEE802154_CIPHER_SIZE);
}
}
g_byte_array_free(bytes, TRUE);
break;
case KEY_HASH_THREAD:
/* XXX - TODO? */
break;
}
}
}
static gboolean ieee802154_key_update_cb(void *r, char **err)
{
ieee802154_key_t* rec = (ieee802154_key_t*)r;
GByteArray *bytes;
switch (rec->hash_type) {
case KEY_HASH_NONE:
case KEY_HASH_ZIP:
bytes = g_byte_array_new();
if (hex_str_to_bytes(rec->pref_key, bytes, FALSE) == FALSE)
{
*err = g_strdup("Invalid key");
g_byte_array_free(bytes, TRUE);
return FALSE;
}
if (bytes->len < IEEE802154_CIPHER_SIZE)
{
*err = g_strdup_printf("Key must be at least %d bytes", IEEE802154_CIPHER_SIZE);
g_byte_array_free(bytes, TRUE);
return FALSE;
}
g_byte_array_free(bytes, TRUE);
break;
case KEY_HASH_THREAD:
/* XXX - TODO? */
break;
}
return TRUE;
}
static void* ieee802154_key_copy_cb(void* n, const void* o, size_t siz _U_) {
ieee802154_key_t* new_record = (ieee802154_key_t*)n;
const ieee802154_key_t* old_record = (const ieee802154_key_t*)o;
new_record->pref_key = g_strdup(old_record->pref_key);
new_record->key_index = old_record->key_index;
new_record->hash_type = old_record->hash_type;
return new_record;
}
static void ieee802154_key_free_cb(void*r) {
ieee802154_key_t* rec = (ieee802154_key_t *)r;
g_free(rec->pref_key);
}
/* Field callbacks. */
UAT_CSTRING_CB_DEF(key_uat, pref_key, ieee802154_key_t)
UAT_DEC_CB_DEF(key_uat, key_index, ieee802154_key_t)
UAT_VS_DEF(key_uat, hash_type, ieee802154_key_t, ieee802154_key_hash, KEY_HASH_NONE, "No hash")
/*-------------------------------------
* Dissector Function Prototypes
*-------------------------------------
*/
/* Dissection Routines. */
static int dissect_ieee802154_nonask_phy (tvbuff_t *, packet_info *, proto_tree *, void *);
static int dissect_ieee802154 (tvbuff_t *, packet_info *, proto_tree *, void *);
static int dissect_ieee802154_nofcs (tvbuff_t *, packet_info *, proto_tree *, void *);
static int dissect_ieee802154_cc24xx (tvbuff_t *, packet_info *, proto_tree *, void *);
static tvbuff_t *dissect_zboss_specific (tvbuff_t *, packet_info *, proto_tree *);
/*static void dissect_ieee802154_linux (tvbuff_t *, packet_info *, proto_tree *); TODO: Implement Me. */
static void dissect_ieee802154_common (tvbuff_t *, packet_info *, proto_tree *, guint);
/* Information Elements */
static void dissect_ieee802154_header_ie (tvbuff_t *, packet_info *, proto_tree *, guint *, ieee802154_packet *);
static int dissect_ieee802154_payload_mlme_sub_ie(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset);
static int dissect_ieee802154_payload_ie (tvbuff_t *, packet_info *, proto_tree *, int offset);
static int dissect_ieee802154_vendor_ie (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, gint offset, gint pie_length);
static void dissect_802154_h_ie_time_correction(tvbuff_t *, proto_tree *, guint *, packet_info *pinfo);
static void dissect_802154_tsch_time_sync(tvbuff_t *, proto_tree *, guint *);
static void dissect_802154_p_ie_sh_mlme_tsch_slotframe_link (tvbuff_t *, proto_tree *, guint16, guint *);
static void dissect_802154_tsch_channel_hopping(tvbuff_t *, proto_tree *, guint16, guint *);
static int dissect_ieee802154_6top (tvbuff_t *tvb, packet_info *pinfo, proto_tree *p_inf_elem_tree, guint offset, gint pie_length);
/* Sub-dissector helpers. */
static void dissect_ieee802154_fcf (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *, guint *);
static void dissect_ieee802154_command (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *);
static void dissect_ieee802154_assoc_req (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *);
static void dissect_ieee802154_assoc_rsp (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *);
static void dissect_ieee802154_disassoc (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *);
static void dissect_ieee802154_realign (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *);
static void dissect_ieee802154_gtsreq (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *);
/* Decryption helpers. */
static tvbuff_t *dissect_ieee802154_decrypt(tvbuff_t *, guint, packet_info *, ieee802154_packet *, ieee802154_payload_info_t*);
static gboolean ieee802154_set_mac_key(ieee802154_packet *packet, unsigned char *key, unsigned char *alt_key, ieee802154_key_t* uat_key);
/* Initialize Protocol and Registered fields */
static int proto_ieee802154_nonask_phy = -1;
static int hf_ieee802154_nonask_phy_preamble = -1;
static int hf_ieee802154_nonask_phy_sfd = -1;
static int hf_ieee802154_nonask_phy_length = -1;
static int hf_ieee802154_nonask_phr = -1;
static int proto_ieee802154 = -1;
static int hf_ieee802154_frame_length = -1;
static int hf_ieee802154_fcf = -1;
static int hf_ieee802154_frame_type = -1;
static int hf_ieee802154_security = -1;
static int hf_ieee802154_pending = -1;
static int hf_ieee802154_ack_request = -1;
static int hf_ieee802154_pan_id_compression = -1;
static int hf_ieee802154_seqno_suppression = -1;
static int hf_ieee802154_ie_present = -1;
static int hf_ieee802154_src_addr_mode = -1;
static int hf_ieee802154_version = -1;
static int hf_ieee802154_dst_addr_mode = -1;
static int hf_ieee802154_header_ie = -1;
static int hf_ieee802154_header_ie_type = -1;
static int hf_ieee802154_header_ie_id = -1;
static int hf_ieee802154_header_ie_length = -1;
static int hf_ieee802154_header_ie_data = -1;
static int hf_ieee802154_time_correction = -1;
static int hf_ieee802154_nack = -1;
static int hf_ieee802154_time_correction_value = -1;
static int hf_ieee802154_payload_ie = -1;
static int hf_ieee802154_payload_ie_type = -1;
static int hf_ieee802154_payload_ie_id = -1;
static int hf_ieee802154_payload_ie_length = -1;
static int hf_ieee802154_payload_ie_data = -1;
static int hf_ieee802154_payload_ie_vendor_oui = -1;
static int hf_ieee802154_mlme_ie_data = -1;
static int hf_ieee802154_psie_short = -1;
static int hf_ieee802154_psie_type_short = -1;
static int hf_ieee802154_psie_id_short = -1;
static int hf_ieee802154_psie_length_short = -1;
static int hf_ieee802154_psie_long = -1;
static int hf_ieee802154_psie_type_long = -1;
static int hf_ieee802154_psie_id_long = -1;
static int hf_ieee802154_psie_length_long = -1;
static int hf_ieee802154_tsch_sync = -1;
static int hf_ieee802154_tsch_asn = -1;
static int hf_ieee802154_tsch_join_metric = -1;
static int hf_ieee802154_tsch_slotf_link_nb_slotf = -1;
static int hf_ieee802154_tsch_slotf_link_slotf_handle= -1;
static int hf_ieee802154_tsch_slotf_size = -1;
static int hf_ieee802154_tsch_slotf_link_nb_links = -1;
static int hf_ieee802154_tsch_slotf_link_timeslot = -1;
static int hf_ieee802154_tsch_slotf_link_channel_offset = -1;
static int hf_ieee802154_tsch_slotf_link_options = -1;
static int hf_ieee802154_tsch_channel_hopping = -1;
static int hf_ieee802154_tsch_hopping_sequence_id = -1;
static int hf_ieee802154_psie_eb_filter = -1;
static int hf_ieee802154_psie_eb_filter_pjoin = -1;
static int hf_ieee802154_psie_eb_filter_lqi = -1;
static int hf_ieee802154_psie_eb_filter_lqi_min = -1;
static int hf_ieee802154_psie_eb_filter_percent = -1;
static int hf_ieee802154_psie_eb_filter_percent_prob = -1;
static int hf_ieee802154_psie_eb_filter_attr_id = -1;
static int hf_ieee802154_psie_eb_filter_attr_id_bitmap = -1;
static int hf_ieee802154_p_ie_ietf_sub_id = -1;
static int hf_ieee802154_6top_version = -1;
static int hf_ieee802154_6top_type = -1;
static int hf_ieee802154_6top_flags_reserved = -1;
static int hf_ieee802154_6top_code = -1;
static int hf_ieee802154_6top_sfid = -1;
static int hf_ieee802154_6top_seqnum = -1;
static int hf_ieee802154_6top_gab = -1;
static int hf_ieee802154_6top_gba = -1;
static int hf_ieee802154_6top_metadata = -1;
static int hf_ieee802154_6top_cell_options = -1;
static int hf_ieee802154_6top_cell_option_tx = -1;
static int hf_ieee802154_6top_cell_option_rx = -1;
static int hf_ieee802154_6top_cell_option_shared = -1;
static int hf_ieee802154_6top_cell_option_reserved = -1;
static int hf_ieee802154_6top_num_cells = -1;
static int hf_ieee802154_6top_reserved = -1;
static int hf_ieee802154_6top_offset = -1;
static int hf_ieee802154_6top_max_num_cells = -1;
static int hf_ieee802154_6top_slot_offset = -1;
static int hf_ieee802154_6top_channel_offset = -1;
static int proto_zboss = -1;
static int zboss_direction = -1;
static int zboss_channel = -1;
static int zboss_trace_number = -1;
static int hf_ieee802154_seqno = -1;
static int hf_ieee802154_dst_panID = -1;
static int hf_ieee802154_dst16 = -1;
static int hf_ieee802154_dst64 = -1;
static int hf_ieee802154_src_panID = -1;
static int hf_ieee802154_src16 = -1;
static int hf_ieee802154_src64 = -1;
static int hf_ieee802154_src64_origin = -1;
static int hf_ieee802154_fcs = -1;
static int hf_ieee802154_rssi = -1;
static int hf_ieee802154_fcs_ok = -1;
static int hf_ieee802154_correlation = -1;
/* Registered fields for Command Packets */
static int hf_ieee802154_cmd_id = -1;
static int hf_ieee802154_cinfo_alt_coord = -1;
static int hf_ieee802154_cinfo_device_type = -1;
static int hf_ieee802154_cinfo_power_src = -1;
static int hf_ieee802154_cinfo_idle_rx = -1;
static int hf_ieee802154_cinfo_sec_capable = -1;
static int hf_ieee802154_cinfo_alloc_addr = -1;
static int hf_ieee802154_assoc_addr = -1;
static int hf_ieee802154_assoc_status = -1;
static int hf_ieee802154_disassoc_reason = -1;
static int hf_ieee802154_realign_pan = -1;
static int hf_ieee802154_realign_caddr = -1;
static int hf_ieee802154_realign_channel = -1;
static int hf_ieee802154_realign_addr = -1;
static int hf_ieee802154_realign_channel_page = -1;
static int hf_ieee802154_gtsreq_len = -1;
static int hf_ieee802154_gtsreq_dir = -1;
static int hf_ieee802154_gtsreq_type = -1;
/* Registered fields for Beacon Packets */
static int hf_ieee802154_beacon_order = -1;
static int hf_ieee802154_superframe_order = -1;
static int hf_ieee802154_cap = -1;
static int hf_ieee802154_superframe_battery_ext = -1;
static int hf_ieee802154_superframe_coord = -1;
static int hf_ieee802154_assoc_permit = -1;
static int hf_ieee802154_gts_count = -1;
static int hf_ieee802154_gts_permit = -1;
static int hf_ieee802154_gts_direction = -1;
static int hf_ieee802154_gts_address = -1;
static int hf_ieee802154_pending16 = -1;
static int hf_ieee802154_pending64 = -1;
/* Registered fields for Auxiliary Security Header */
static int hf_ieee802154_aux_security_header = -1;
static int hf_ieee802154_security_control_field = -1;
static int hf_ieee802154_security_level = -1;
static int hf_ieee802154_key_id_mode = -1;
static int hf_ieee802154_aux_sec_reserved = -1;
static int hf_ieee802154_aux_sec_frame_counter = -1;
static int hf_ieee802154_aux_sec_key_source = -1;
static int hf_ieee802154_aux_sec_key_source_bytes = -1;
static int hf_ieee802154_aux_sec_key_index = -1;
static int hf_ieee802154_mic = -1;
static int hf_ieee802154_key_number = -1;
/* 802.15.4-2003 security */
static int hf_ieee802154_sec_frame_counter = -1;
static int hf_ieee802154_sec_key_sequence_counter = -1;
/* Initialize Subtree Pointers */
static gint ett_ieee802154_nonask_phy = -1;
static gint ett_ieee802154_nonask_phy_phr = -1;
static gint ett_ieee802154 = -1;
static gint ett_ieee802154_fcf = -1;
static gint ett_ieee802154_auxiliary_security = -1;
static gint ett_ieee802154_aux_sec_control = -1;
static gint ett_ieee802154_aux_sec_key_id = -1;
static gint ett_ieee802154_fcs = -1;
static gint ett_ieee802154_cmd = -1;
static gint ett_ieee802154_superframe = -1;
static gint ett_ieee802154_gts = -1;
static gint ett_ieee802154_gts_direction = -1;
static gint ett_ieee802154_gts_descriptors = -1;
static gint ett_ieee802154_pendaddr = -1;
static gint ett_ieee802154_header = -1;
static gint ett_ieee802154_header_ie = -1;
static gint ett_ieee802154_h_ie_payload = -1;
static gint ett_ieee802154_payload = -1;
static gint ett_ieee802154_payload_ie = -1;
static gint ett_ieee802154_mlme_payload = -1;
static gint ett_ieee802154_mlme_payload_data = -1;
static gint ett_ieee802154_psie_short = -1;
static gint ett_ieee802154_psie_short_bitmap= -1;
static gint ett_ieee802154_psie_long = -1;
static gint ett_ieee802154_psie_long_bitmap = -1;
static gint ett_ieee802154_psie_enh_beacon_flt = -1;
static gint ett_ieee802154_psie_enh_beacon_flt_bitmap = -1;
static gint ett_ieee802154_psie_slotframe_link_slotframes = -1;
static gint ett_ieee802154_zigbee = -1;
static gint ett_ieee802154_zboss = -1;
static gint ett_ieee802154_p_ie_6top = -1;
static gint ett_ieee802154_p_ie_6top_version_type = -1;
static gint ett_ieee802154_p_ie_6top_seqnum_gab_gba = -1;
static gint ett_ieee802154_p_ie_6top_cell_options = -1;
static gint ett_ieee802154_p_ie_6top_cell_list = -1;
static gint ett_ieee802154_p_ie_6top_cell = -1;
static expert_field ei_ieee802154_invalid_addressing = EI_INIT;
/* static expert_field ei_ieee802154_invalid_panid_compression = EI_INIT; */
static expert_field ei_ieee802154_invalid_panid_compression2 = EI_INIT;
static expert_field ei_ieee802154_fcs = EI_INIT;
static expert_field ei_ieee802154_decrypt_error = EI_INIT;
static expert_field ei_ieee802154_dst = EI_INIT;
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_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;
static expert_field ei_ieee802154_6top_unsupported_command = EI_INIT;
static int ieee802_15_4_short_address_type = -1;
/*
* Dissector handles
* - beacon dissection is always heuristic.
* - the PANID table is for stateful dissectors only (ie: Decode-As)
* - otherwise, data dissectors fall back to the heuristic dissectors.
*/
static dissector_table_t panid_dissector_table;
static heur_dissector_list_t ieee802154_beacon_subdissector_list;
static heur_dissector_list_t ieee802154_heur_subdissector_list;
static dissector_handle_t zigbee_beacon_handle;
static dissector_handle_t zigbee_ie_handle;
static dissector_handle_t zigbee_nwk_handle;
static dissector_handle_t ieee802154_handle;
static dissector_handle_t ieee802154_nonask_phy_handle;
static dissector_handle_t ieee802154_nofcs_handle;
/* Versions */
static const value_string ieee802154_frame_versions[] = {
{ IEEE802154_VERSION_2003, "IEEE Std 802.15.4-2003" },
{ IEEE802154_VERSION_2006, "IEEE Std 802.15.4-2006" },
{ IEEE802154_VERSION_2015, "IEEE Std 802.15.4-2015" },
{ IEEE802154_VERSION_RESERVED, "Reserved" },
{ 0, NULL }
};
/* Name Strings */
static const value_string ieee802154_frame_types[] = {
{ IEEE802154_FCF_BEACON, "Beacon" },
{ IEEE802154_FCF_DATA, "Data" },
{ IEEE802154_FCF_ACK, "Ack" },
{ IEEE802154_FCF_CMD, "Command" },
{ IEEE802154_FCF_RESERVED, "Reserved" },
{ IEEE802154_FCF_MULTIPURPOSE, "Multipurpose" },
{ IEEE802154_FCF_FRAGMENT, "Fragment or Frak" },
{ IEEE802154_FCF_EXTENDED, "Extended" },
{ 0, NULL }
};
static const value_string ieee802154_addr_modes[] = {
{ IEEE802154_FCF_ADDR_NONE, "None" },
{ IEEE802154_FCF_ADDR_RESERVED, "Reserved" },
{ IEEE802154_FCF_ADDR_SHORT, "Short/16-bit" },
{ IEEE802154_FCF_ADDR_EXT, "Long/64-bit" },
{ 0, NULL }
};
static const value_string ieee802154_cmd_names[] = {
{ IEEE802154_CMD_ASSOC_REQ, "Association Request" },
{ IEEE802154_CMD_ASSOC_RSP, "Association Response" },
{ IEEE802154_CMD_DISASSOC_NOTIFY, "Disassociation Notification" },
{ IEEE802154_CMD_DATA_RQ, "Data Request" },
{ IEEE802154_CMD_PANID_CONFLICT, "PAN ID Conflict" },
{ IEEE802154_CMD_ORPHAN_NOTIFY, "Orphan Notification" },
{ IEEE802154_CMD_BEACON_REQ, "Beacon Request" },
{ IEEE802154_CMD_COORD_REALIGN, "Coordinator Realignment" },
{ IEEE802154_CMD_GTS_REQ, "GTS Request" },
{ IEEE802154_CMD_TRLE_MGMT_REQ, "TRLE Management Request"},
{ IEEE802154_CMD_TRLE_MGMT_RSP, "TRLE Management Response"},
{ IEEE802154_CMD_DSME_ASSOC_REQ, "DSME Association Request"},
{ IEEE802154_CMD_DSME_ASSOC_RSP, "DSME Association Response"},
{ IEEE802154_CMD_DSME_GTS_REQ, "DSME GTS Request"},
{ IEEE802154_CMD_DSME_GTS_RSP, "DSME GTS Response"},
{ IEEE802154_CMD_DSME_GTS_NOTIFY, "DSME GTS Notify"},
{ IEEE802154_CMD_DSME_INFO_REQ, "DSME Information Request"},
{ IEEE802154_CMD_DSME_INFO_RSP, "DSME Information Response"},
{ IEEE802154_CMD_DSME_BEACON_ALLOC_NOTIFY, "DSME Beacon Allocation Notification"},
{ IEEE802154_CMD_DSME_BEACON_COLL_NOTIFY, "DSME Beacon Collision Notification"},
{ IEEE802154_CMD_DSME_LINK_REPORT, "DSME Link Report"},
{ IEEE802154_CMD_RIT_DATA_REQ, "RIT Data Request"},
{ IEEE802154_CMD_DBS_REQ, "DBS Request"},
{ IEEE802154_CMD_DBS_RSP, "DBS Response"},
{ 0, NULL }
};
static const value_string ieee802154_sec_level_names[] = {
{ SECURITY_LEVEL_NONE, "No Security" },
{ SECURITY_LEVEL_MIC_32, "32-bit Message Integrity Code" },
{ SECURITY_LEVEL_MIC_64, "64-bit Message Integrity Code" },
{ SECURITY_LEVEL_MIC_128, "128-bit Message Integrity Code" },
{ SECURITY_LEVEL_ENC, "Encryption" },
{ SECURITY_LEVEL_ENC_MIC_32, "Encryption with 32-bit Message Integrity Code" },
{ SECURITY_LEVEL_ENC_MIC_64, "Encryption with 64-bit Message Integrity Code" },
{ SECURITY_LEVEL_ENC_MIC_128, "Encryption with 128-bit Message Integrity Code" },
{ 0, NULL }
};
static const value_string ieee802154_key_id_mode_names[] = {
{ KEY_ID_MODE_IMPLICIT, "Implicit Key" },
{ KEY_ID_MODE_KEY_INDEX, "Indexed Key using the Default Key Source" },
{ KEY_ID_MODE_KEY_EXPLICIT_4, "Explicit Key with 4-octet Key Source" },
{ KEY_ID_MODE_KEY_EXPLICIT_8, "Explicit Key with 8-octet Key Source" },
{ 0, NULL }
};
static const true_false_string ieee802154_gts_direction_tfs = {
"Receive Only",
"Transmit Only"
};
/* The 802.15.4-2003 security suites for the security preferences (only AES-CCM suites are supported). */
/* NOTE: The equivalent 2006 security level identifier enumerations are used to simplify 2003 & 2006 integration! */
static const enum_val_t ieee802154_2003_sec_suite_enums[] = {
{ "AES-CCM-128", "AES-128 Encryption, 128-bit Integrity Protection", SECURITY_LEVEL_ENC_MIC_128 },
{ "AES-CCM-64", "AES-128 Encryption, 64-bit Integrity Protection", SECURITY_LEVEL_ENC_MIC_64 },
{ "AES-CCM-32", "AES-128 Encryption, 32-bit Integrity Protection", SECURITY_LEVEL_ENC_MIC_32 },
{ NULL, NULL, 0 }
};
/* Enumeration for key generation */
static const value_string ieee802154_key_hash_vals[] = {
{ KEY_HASH_NONE, "No hash"},
{ KEY_HASH_ZIP, "ZigBee IP hash" },
{ KEY_HASH_THREAD, "Thread hash" },
{ 0, NULL }
};
static const value_string ieee802154_ie_types[] = {
{ 0, "Header" },
{ 1, "Payload" },
{ 0, NULL }
};
static const value_string ieee802154_psie_types[] = {
{ 0, "Short" },
{ 1, "Long" },
{ 0, NULL }
};
static const value_string ieee802154_header_ie_names[] = {
{ IEEE802154_HEADER_VENDOR_SPECIFIC, "Vendor Specific IE" },
{ IEEE802154_HEADER_IE_CSL, "CSL IE" },
{ IEEE802154_HEADER_IE_RIT, "RIT IE" },
{ IEEE802154_HEADER_IE_DSME_PAN, "DSME PAN descriptor IE" },
{ IEEE802154_HEADER_IE_RENDEZVOUS, "Rendezvous Time IE" },
{ IEEE802154_HEADER_IE_TIME_CORR, "Time Correction IE" },
{ IEEE802154_HEADER_IE_EXT_DSME_PAN, "Extended DSME PAN descriptor IE" },
{ IEEE802154_HEADER_IE_FSCD, "Fragment Sequence Context Description (FSCD) IE" },
{ IEEE802154_HEADER_IE_SMPL_SUPER_FRM, "Simplified Superframe Specification IE" },
{ IEEE802154_HEADER_IE_SMPL_GTS, "Simplified GTS Specification IE" },
{ IEEE802154_HEADER_IE_LECIM, "LECIM Capabilities IE" },
{ IEEE802154_HEADER_IE_TRLE, "TRLE Descriptor" },
{ IEEE802154_HEADER_IE_RCC_CAP, "RCC Capabilities IE" },
{ IEEE802154_HEADER_IE_RCCN, "RCCN Descriptor IE" },
{ IEEE802154_HEADER_IE_GLOBAL_TIME, "Global Time IE" },
{ IEEE802154_HEADER_IE_DA_IE, "DA IE" },
{ IEEE802154_HEADER_IE_EID_TERM1, "Header Termination 1" },
{ IEEE802154_HEADER_IE_EID_TERM2, "Header Termination 2" },
{ 0, NULL }
};
static const value_string ieee802154_payload_ie_names[] = {
{ IEEE802154_PAYLOAD_IE_ESDU, "ESDU IE" },
{ IEEE802154_PAYLOAD_IE_MLME, "MLME IE" },
{ IEEE802154_PAYLOAD_IE_VENDOR, "Vendor Specific IE" },
{ IEEE802154_PAYLOAD_IE_IETF, "IETF IE" },
{ IEEE802154_PAYLOAD_IE_GID_TERM, "Payload Termination IE" },
{ 0, NULL }
};
static const value_string ieee802154_vendor_oui_names[] = {
{ IEEE802154_VENDOR_OUI_ZIGBEE, "ZigBee" },
{ 0, NULL }
};
static const value_string ieee802154_psie_names[] = {
{ IEEE802154_MLME_SUBIE_CHANNEL_HOPPING, "Channel Hopping IE" },
{ IEEE802154_MLME_SUBIE_TSCH_SYNCH, "TSCH Synchronization IE" },
{ IEEE802154_MLME_SUBIE_TSCH_SLOTFR_LINK, "TSCH Slotframe and Link IE" },
{ IEEE802154_MLME_SUBIE_TSCH_TIMESLOT, "TSCH Timeslot IE" },
{ IEEE802154_MLME_SUBIE_HOPPING_TIMING, "Hopping Timing IE" },
{ IEEE802154_MLME_SUBIE_ENHANCED_BEACON_FILTER, "Enhanced Beacon Filter IE" },
{ IEEE802154_MLME_SUBIE_MAC_METRICS, "MAC Metrics IE" },
{ IEEE802154_MLME_SUBIE_ALL_MAC_METRICS, "All MAC Metrics IE" },
{ IEEE802154_MLME_SUBIE_COEXISTENCE_SPEC, "Coexistence Specification IE" },
{ IEEE802154_MLME_SUBIE_SUN_DEVICE_CAPABILITIES, "SUN Device Capabilities IE" },
{ IEEE802154_MLME_SUBIE_SUN_FSK_GEN_PHY, "SUN FSK Generic PHY IE" },
{ IEEE802154_MLME_SUBIE_MODE_SWITCH_PARAMETER, "Mode Switch Parameter IE" },
{ IEEE802154_MLME_SUBIE_PHY_PARAMETER_CHANGE, "PHY Parameter Change IE" },
{ IEEE802154_MLME_SUBIE_O_QPSK_PHY_MODE, "O-QPSY PHY Mode IE" },
{ IEEE802154_MLME_SUBIE_PCA_ALLOCATION, "PCA Allocation IE" },
{ IEEE802154_MLME_SUBIE_DSSS_OPER_MODE, "LECIM DSSS Operating Mode IE"},
{ IEEE802154_MLME_SUBIE_FSK_OPER_MODE, "LECIM FSK Operating Mode IE" },
{ IEEE802154_MLME_SUBIE_TVWS_PHY_OPE_MODE, "TVWS PHY Operating Mode Description IE" },
{ IEEE802154_MLME_SUBIE_TVWS_DEVICE_CAPAB, "TVWS Device Capabilities IE" },
{ IEEE802154_MLME_SUBIE_TVWS_DEVICE_CATEG, "TVWS Device Category IE" },
{ IEEE802154_MLME_SUBIE_TVWS_DEVICE_IDENTIF, "TVWS Device Identification IE" },
{ IEEE802154_MLME_SUBIE_TVWS_DEVICE_LOCATION, "TVWS Device Location IE" },
{ IEEE802154_MLME_SUBIE_TVWS_CH_INFOR_QUERY, "TVWS Channel Information Query IE" },
{ IEEE802154_MLME_SUBIE_TVWS_CH_INFOR_SOURCE, "TVWS Channel Information Source IE" },
{ IEEE802154_MLME_SUBIE_CTM, "CTM IE" },
{ IEEE802154_MLME_SUBIE_TIMESTAMP, "Timestamp IE" },
{ IEEE802154_MLME_SUBIE_TIMESTAMP_DIFF, "Timestamp Difference IE"},
{ IEEE802154_MLME_SUBIE_TMCP_SPECIFICATION, "TMCTP Specification IE" },
{ IEEE802154_MLME_SUBIE_RCC_PHY_OPER_MODE, "RCC PHY Operating Mode IE" },
{ IEEE802154_IETF_SUBIE_6TOP, "6top IE" },
{ 0, NULL }
};
static const value_string zboss_direction_names[] = {
{ 0, "IN" },
{ 1, "OUT" },
{ 0, NULL }
};
static const value_string ietf_6top_types[] = {
{ IETF_6TOP_TYPE_REQUEST, "Request" },
{ IETF_6TOP_TYPE_RESPONSE, "Response" },
{ IETF_6TOP_TYPE_CONFIRMATION, "Confirmation" },
{ 0, NULL }
};
static const value_string ietf_6top_command_identifiers[] = {
{ IETF_6TOP_CMD_ADD, "Add" },
{ IETF_6TOP_CMD_DELETE, "Delete" },
{ IETF_6TOP_CMD_STATUS, "Status" },
{ IETF_6TOP_CMD_LIST, "List" },
{ IETF_6TOP_CMD_CLEAR, "Clear" },
{ 0, NULL }
};
static const value_string ietf_6top_return_codes[] = {
{ IETF_6TOP_RC_SUCCESS, "SUCCESS" },
{ IETF_6TOP_RC_ERR_VER, "ERR_VER" },
{ IETF_6TOP_RC_ERR_SFID, "ERR_SFID" },
{ IETF_6TOP_RC_ERR_GEN, "ERR_GEN" },
{ IETF_6TOP_RC_ERR_BUSY, "ERR_BUSY" },
{ IETF_6TOP_RC_ERR_NORES, "ERR_NORES" },
{ IETF_6TOP_RC_ERR_RESET, "ERR_RESET" },
{ IETF_6TOP_RC_ERR, "ERR" },
{ 0, NULL }
};
static const value_string ietf_6top_generation_numbers[] = {
{ 0, "clean" },
{ 1, "counter" },
{ 2, "counter" },
{ 3, "reserved" },
{ 0, NULL}
};
static const value_string ietf_6top_cell_options[] = {
{ 0, "ALL" },
{ 1, "TX" },
{ 2, "RX" },
{ 3, "TX|RX" },
{ 4, "SHARED" },
{ 5, "TX|SHARED" },
{ 6, "RX|SHARED" },
{ 7, "TX|RX|SHARED" },
{ 0, NULL}
};
/* Preferences for 2003 security */
static gint ieee802154_sec_suite = SECURITY_LEVEL_ENC_MIC_64;
static gboolean ieee802154_extend_auth = TRUE;
/* Macro to check addressing, and throw a warning flag if incorrect. */
#define IEEE802154_CMD_ADDR_CHECK(_pinfo_, _item_, _cmdid_, _x_) \
if (!(_x_)) \
expert_add_info_format(_pinfo_, _item_, &ei_ieee802154_invalid_addressing, \
"Invalid Addressing for %s", \
val_to_str_const(_cmdid_, ieee802154_cmd_names, "Unknown Command"))
/* CRC definitions. IEEE 802.15.4 CRCs vary from CCITT by using an initial value of
* 0x0000, and no XOR out. IEEE802154_CRC_XOR is defined as 0xFFFF in order to un-XOR
* the output from the CCITT CRC routines in Wireshark.
*/
#define IEEE802154_CRC_SEED 0x0000
#define IEEE802154_CRC_XOROUT 0xFFFF
#define ieee802154_crc_tvb(tvb, offset) (crc16_ccitt_tvb_seed(tvb, offset, IEEE802154_CRC_SEED) ^ IEEE802154_CRC_XOROUT)
static int ieee802_15_4_short_address_to_str(const address* addr, gchar *buf, int buf_len)
{
guint16 ieee_802_15_4_short_addr = pletoh16(addr->data);
if (ieee_802_15_4_short_addr == 0xffff)
{
g_strlcpy(buf, "Broadcast", buf_len);
return 10;
}
*buf++ = '0';
*buf++ = 'x';
buf = word_to_hex(buf, ieee_802_15_4_short_addr);
*buf = '\0'; /* NULL terminate */
return 7;
}
static int ieee802_15_4_short_address_str_len(const address* addr _U_)
{
return 11;
}
static int ieee802_15_4_short_address_len(void)
{
return 2;
}
/**
* Dissector helper, parses and displays the frame control field.
*
*@param tvb pointer to buffer containing raw packet.
*@param pinfo pointer to packet information fields
*@param tree pointer to data tree wireshark uses to display packet.
*@param packet IEEE 802.15.4 packet information.
*@param offset offset into the tvb to find the FCF.
*
*/
static void
dissect_ieee802154_fcf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet, guint *offset)
{
guint16 fcf;
static const int * fields[] = {
&hf_ieee802154_frame_type,
&hf_ieee802154_security,
&hf_ieee802154_pending,
&hf_ieee802154_ack_request,
&hf_ieee802154_pan_id_compression,
&hf_ieee802154_seqno_suppression,
&hf_ieee802154_ie_present,
&hf_ieee802154_dst_addr_mode,
&hf_ieee802154_version,
&hf_ieee802154_src_addr_mode,
NULL
};
/* Get the FCF field. */
fcf = tvb_get_letohs(tvb, *offset);
/* Parse FCF Flags. */
packet->frame_type = (fcf & IEEE802154_FCF_TYPE_MASK);
packet->security_enable = (fcf & IEEE802154_FCF_SEC_EN) >> 3;
packet->frame_pending = (fcf & IEEE802154_FCF_FRAME_PND) >> 4;
packet->ack_request = (fcf & IEEE802154_FCF_ACK_REQ) >> 5;
packet->pan_id_compression = (fcf & IEEE802154_FCF_PAN_ID_COMPRESSION) >> 6;
/* bit 7 reserved */
packet->seqno_suppression = (fcf & IEEE802154_FCF_SEQNO_SUPPRESSION) >> 8;
packet->ie_present = (fcf & IEEE802154_FCF_IE_PRESENT) >> 9;
packet->dst_addr_mode = (fcf & IEEE802154_FCF_DADDR_MASK) >> 10;
packet->version = (fcf & IEEE802154_FCF_VERSION) >> 12;
packet->src_addr_mode = (fcf & IEEE802154_FCF_SADDR_MASK) >> 14;
if ((packet->version == IEEE802154_VERSION_2015) && (packet->frame_type == IEEE802154_FCF_BEACON)) {
proto_item_append_text(tree, " Enhanced Beacon");
col_set_str(pinfo->cinfo, COL_INFO, "Enhanced Beacon");
}
else {
proto_item_append_text(tree, " %s", val_to_str_const(packet->frame_type, ieee802154_frame_types, "Reserved"));
col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(packet->frame_type, ieee802154_frame_types, "Reserved"));
}
proto_tree_add_bitmask(tree, tvb, *offset, hf_ieee802154_fcf,
ett_ieee802154_fcf, fields, ENC_LITTLE_ENDIAN);
*offset += 2;
} /* dissect_ieee802154_fcf */
void register_ieee802154_mac_key_hash_handler(guint hash_identifier, ieee802154_set_mac_key_func key_func)
{
/* Ensure no duplication */
DISSECTOR_ASSERT(wmem_tree_lookup32(mac_key_hash_handlers, hash_identifier) == NULL);
wmem_tree_insert32(mac_key_hash_handlers, hash_identifier, (void*)key_func);
}
void dissect_ieee802154_aux_sec_header_and_key(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, ieee802154_packet *packet, guint *offset)
{
proto_tree *field_tree, *header_tree;
proto_item *ti, *hidden_item;
guint8 security_control;
guint aux_length = 5; /* Minimum length of the auxiliary header. */
static const int * security_fields[] = {
&hf_ieee802154_security_level,
&hf_ieee802154_key_id_mode,
&hf_ieee802154_aux_sec_reserved,
NULL
};
/* Parse the security control field. */
security_control = tvb_get_guint8(tvb, *offset);
packet->security_level = (ieee802154_security_level)(security_control & IEEE802154_AUX_SEC_LEVEL_MASK);
packet->key_id_mode = (ieee802154_key_id_mode)((security_control & IEEE802154_AUX_KEY_ID_MODE_MASK) >> IEEE802154_AUX_KEY_ID_MODE_SHIFT);
/* Compute the length of the auxiliary header and create a subtree. */
if (packet->key_id_mode != KEY_ID_MODE_IMPLICIT) aux_length++;
if (packet->key_id_mode == KEY_ID_MODE_KEY_EXPLICIT_4) aux_length += 4;
if (packet->key_id_mode == KEY_ID_MODE_KEY_EXPLICIT_8) aux_length += 8;
ti = proto_tree_add_item(tree, hf_ieee802154_aux_security_header, tvb, *offset, aux_length, ENC_NA);
header_tree = proto_item_add_subtree(ti, ett_ieee802154_auxiliary_security);
/* Security Control Field */
proto_tree_add_bitmask(header_tree, tvb, *offset, hf_ieee802154_security_control_field, ett_ieee802154_aux_sec_control, security_fields, ENC_NA);
(*offset)++;
/* Frame Counter Field */
proto_tree_add_item_ret_uint(header_tree, hf_ieee802154_aux_sec_frame_counter, tvb, *offset, 4, ENC_LITTLE_ENDIAN, &packet->frame_counter);
(*offset) +=4;
/* Key identifier field(s). */
if (packet->key_id_mode != KEY_ID_MODE_IMPLICIT) {
/* Create a subtree. */
field_tree = proto_tree_add_subtree(header_tree, tvb, *offset, 1,
ett_ieee802154_aux_sec_key_id, &ti, "Key Identifier Field"); /* Will fix length later. */
/* Add key source, if it exists. */
if (packet->key_id_mode == KEY_ID_MODE_KEY_EXPLICIT_4) {
packet->key_source.addr32 = tvb_get_ntohl(tvb, *offset);
proto_tree_add_uint64(field_tree, hf_ieee802154_aux_sec_key_source, tvb, *offset, 4, packet->key_source.addr32);
hidden_item = proto_tree_add_item(field_tree, hf_ieee802154_aux_sec_key_source_bytes, tvb, *offset, 4, ENC_NA);
PROTO_ITEM_SET_HIDDEN(hidden_item);
proto_item_set_len(ti, 1 + 4);
(*offset) += 4;
}
if (packet->key_id_mode == KEY_ID_MODE_KEY_EXPLICIT_8) {
packet->key_source.addr64 = tvb_get_ntoh64(tvb, *offset);
proto_tree_add_uint64(field_tree, hf_ieee802154_aux_sec_key_source, tvb, *offset, 8, packet->key_source.addr64);
hidden_item = proto_tree_add_item(field_tree, hf_ieee802154_aux_sec_key_source_bytes, tvb, *offset, 8, ENC_NA);
PROTO_ITEM_SET_HIDDEN(hidden_item);
proto_item_set_len(ti, 1 + 8);
(*offset) += 8;
}
/* Add key identifier. */
packet->key_index = tvb_get_guint8(tvb, *offset);
proto_tree_add_uint(field_tree, hf_ieee802154_aux_sec_key_index, tvb, *offset,1, packet->key_index);
(*offset)++;
}
}
tvbuff_t *dissect_ieee802154_payload(tvbuff_t * tvb, guint offset, packet_info * pinfo, proto_tree* key_tree,
ieee802154_packet * packet, ieee802154_payload_info_t* payload_info,
ieee802154_set_key_func set_key_func, ieee802154_payload_func payload_func)
{
proto_item* ti;
unsigned char key[IEEE802154_CIPHER_SIZE];
unsigned char alt_key[IEEE802154_CIPHER_SIZE];
tvbuff_t * payload_tvb = NULL;
/* Lookup the key. */
for (payload_info->key_number = 0; payload_info->key_number < num_ieee802154_keys; payload_info->key_number++) {
if (set_key_func(packet, key, alt_key, &ieee802154_keys[payload_info->key_number])) {
/* Try with the initial key */
payload_info->key = key;
payload_tvb = payload_func(tvb, offset, pinfo, packet, payload_info);
if (!((*payload_info->status == DECRYPT_PACKET_MIC_CHECK_FAILED) || (*payload_info->status == DECRYPT_PACKET_DECRYPT_FAILED))) {
break;
}
/* Try with the alternate key */
payload_info->key = alt_key;
payload_tvb = payload_func(tvb, offset, pinfo, packet, payload_info);
if (!((*payload_info->status == DECRYPT_PACKET_MIC_CHECK_FAILED) || (*payload_info->status == DECRYPT_PACKET_DECRYPT_FAILED))) {
break;
}
}
}
if (payload_info->key_number == num_ieee802154_keys) {
/* None of the stored keys seemed to work */
*payload_info->status = DECRYPT_PACKET_NO_KEY;
}
/* Store the key number used for retrieval */
ti = proto_tree_add_uint(key_tree, hf_ieee802154_key_number, tvb, 0, 0, payload_info->key_number);
PROTO_ITEM_SET_HIDDEN(ti);
return payload_tvb;
}
/*
*Dissector for IEEE 802.15.4 non-ASK PHY packet with an FCS containing a 16-bit CRC value.
*
*@param tvb pointer to buffer containing raw packet.
*@param pinfo pointer to packet information fields
*@param tree pointer to data tree wireshark uses to display packet.
*/
static int
dissect_ieee802154_nonask_phy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
proto_tree *ieee802154_tree = NULL;
proto_item *proto_root = NULL;
guint offset = 0;
guint8 phr;
tvbuff_t* mac;
/* Create the protocol tree. */
if (tree) {
proto_root = proto_tree_add_protocol_format(tree, proto_ieee802154_nonask_phy, tvb, 0, tvb_captured_length(tvb), "IEEE 802.15.4 non-ASK PHY");
ieee802154_tree = proto_item_add_subtree(proto_root, ett_ieee802154_nonask_phy);
}
/* Add the protocol name. */
col_set_str(pinfo->cinfo, COL_PROTOCOL, "IEEE 802.15.4 non-ASK PHY");
phr=tvb_get_guint8(tvb,offset+4+1);
if(tree) {
guint loffset=offset;
static const int * phr_fields[] = {
&hf_ieee802154_nonask_phy_length,
NULL
};
proto_tree_add_item(ieee802154_tree, hf_ieee802154_nonask_phy_preamble, tvb, loffset, 4, ENC_LITTLE_ENDIAN);
loffset+=4;
proto_tree_add_item(ieee802154_tree, hf_ieee802154_nonask_phy_sfd, tvb, loffset, 1, ENC_LITTLE_ENDIAN);
loffset+=1;
proto_tree_add_bitmask(ieee802154_tree, tvb, loffset, hf_ieee802154_nonask_phr, ett_ieee802154_nonask_phy_phr,
phr_fields, ENC_NA);
}
offset+=4+2*1;
mac=tvb_new_subset_length_caplen(tvb,offset,-1, phr & IEEE802154_PHY_LENGTH_MASK);
/* Call the common dissector. */
dissect_ieee802154(mac, pinfo, ieee802154_tree, NULL);
return tvb_captured_length(tvb);
} /* dissect_ieee802154_nonask_phy */
/**
*Dissector for IEEE 802.15.4 packet with an FCS containing a 16-bit CRC value.
*
*@param tvb pointer to buffer containing raw packet.
*@param pinfo pointer to packet information fields.
*@param tree pointer to data tree wireshark uses to display packet.
*/
static int
dissect_ieee802154(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
tvbuff_t *new_tvb = dissect_zboss_specific(tvb, pinfo, tree);
guint options = 0;
if (ieee802154_cc24xx)
{
options = DISSECT_IEEE802154_OPTION_CC24xx;
}
if (new_tvb != tvb)
{
/* ZBOSS traffic dump: always TI FCS, always ZigBee */
options = (DISSECT_IEEE802154_OPTION_CC24xx | DISSECT_IEEE802154_OPTION_ZBOSS);
}
/* Call the common dissector. */
dissect_ieee802154_common(new_tvb, pinfo, tree, options);
return tvb_captured_length(tvb);
} /* dissect_ieee802154 */
/**
* Dissector for IEEE 802.15.4 packet with no FCS present.
*
*@param tvb pointer to buffer containing raw packet.
*@param pinfo pointer to packet information fields
*@param tree pointer to data tree wireshark uses to display packet.
*@return captured length.
*/
static int
dissect_ieee802154_nofcs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void * data _U_)
{
tvbuff_t *new_tvb;
/* If there is no FCS present in the reported packet, then the length of
* the true IEEE 802.15.4 packet is actually 2 bytes longer. Re-create
* the buffer with an extended reported length so that the packet will
* be handled as though the FCS were truncated.
*
* Note, we can't just call tvb_set_reported_length(), because it includes
* checks to ensure that the new reported length is not longer than the old
* reported length (why?), and will throw an exception.
*/
new_tvb = tvb_new_subset_length_caplen(tvb, 0, -1, tvb_reported_length(tvb)+IEEE802154_FCS_LEN);
/* Call the common dissector. */
dissect_ieee802154_common(new_tvb, pinfo, tree, 0);
return tvb_captured_length(tvb);
} /* dissect_ieee802154_nofcs */
/**
* Dissector for IEEE 802.15.4 packet dump produced by ZBOSS
*
*@param tvb pointer to buffer containing raw packet.
*@param pinfo pointer to packet information fields
*@param tree pointer to data tree wireshark uses to display packet.
*@return new tvb subset if this is really ZBOSS dump, else oririnal tvb.
*/
static tvbuff_t *
dissect_zboss_specific(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
if (tvb_captured_length(tvb) > 5)
{
guint off = 0;
if (tvb_get_guint8(tvb, off++) == 'Z'
&& tvb_get_guint8(tvb, off++) == 'B'
&& tvb_get_guint8(tvb, off++) == 'O'
&& tvb_get_guint8(tvb, off++) == 'S'
&& tvb_get_guint8(tvb, off++) == 'S')
{
proto_tree *zboss_tree = NULL;
proto_item *proto_root = NULL;
/* Create the protocol tree. */
if (tree) {
proto_root = proto_tree_add_protocol_format(tree, proto_zboss, tvb, 0, tvb_captured_length(tvb), "ZBOSS dump");
zboss_tree = proto_item_add_subtree(proto_root, ett_ieee802154_zboss);
}
proto_tree_add_item(zboss_tree, zboss_direction, tvb, off, 1, ENC_NA);
proto_item_append_text(proto_root, ", %s", tvb_get_guint8(tvb, off) ? "OUT" : "IN");
off++;
proto_tree_add_item(zboss_tree, zboss_channel, tvb, off, 1, ENC_NA);
proto_item_append_text(proto_root, ", channel %u", tvb_get_guint8(tvb, off));
off++;
proto_tree_add_item(zboss_tree, zboss_trace_number, tvb, off, 4, ENC_LITTLE_ENDIAN);
off += 4;
return tvb_new_subset_length_caplen(tvb, off, tvb_captured_length(tvb) - off, tvb_captured_length(tvb) - off);
}
}
return tvb;
} /* dissect_zboss_heur */
/**
*Dissector for IEEE 802.15.4 packet with a ChipCon/Texas
*Instruments compatible FCS. This is typically called by
*layers encapsulating an IEEE 802.15.4 packet.
*
*@param tvb pointer to buffer containing raw packet.
*@param pinfo pointer to packet information fields
*@param tree pointer to data tree wireshark uses to display packet.
*/
static int
dissect_ieee802154_cc24xx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void * data _U_)
{
/* Call the common dissector. */
dissect_ieee802154_common(tvb, pinfo, tree, DISSECT_IEEE802154_OPTION_CC24xx);
return tvb_captured_length(tvb);
} /* dissect_ieee802154_cc24xx */
/**
*IEEE 802.15.4 packet dissection routine for Wireshark.
*
*This function extracts all the information first before displaying.
*If payload exists, that portion will be passed into another dissector
*for further processing.
*
*This is called after the individual dissect_ieee802154* functions
*have been called to determine what sort of FCS is present.
*The dissect_ieee802154* functions will set the parameters
*in the ieee802154_packet structure, and pass it to this one
*through the data parameter.
*
*@param tvb pointer to buffer containing raw packet.
*@param pinfo pointer to packet information fields
*@param tree pointer to data tree wireshark uses to display packet.
*@param options bitwise or of dissector options (see DISSECT_IEEE802154_OPTION_xxx).
*/
static void
dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint options)
{
tvbuff_t *volatile payload_tvb = NULL;
proto_tree *volatile ieee802154_tree = NULL;
proto_item *volatile proto_root = NULL;
proto_item *hidden_item;
proto_item *ti;
proto_item *mic_item = NULL;
proto_tree *header_tree = NULL;
guint offset = 0;
volatile gboolean fcs_ok = TRUE;
const char *saved_proto;
ws_decrypt_status status;
gboolean dstPanPresent = FALSE;
gboolean srcPanPresent = FALSE;
unsigned char rx_mic[IEEE802154_CIPHER_SIZE];
guint rx_mic_len = 0;
ieee802154_packet *packet = wmem_new0(wmem_packet_scope(), ieee802154_packet);
ieee802154_short_addr addr16;
ieee802154_hints_t *ieee_hints;
heur_dtbl_entry_t *hdtbl_entry;
packet->short_table = ieee802154_map.short_table;
/* Allocate frame data with hints for upper layers */
if(!pinfo->fd->flags.visited){
ieee_hints = wmem_new0(wmem_file_scope(), ieee802154_hints_t);
p_add_proto_data(wmem_file_scope(), pinfo, proto_ieee802154, 0, ieee_hints);
} else {
ieee_hints = (ieee802154_hints_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_ieee802154, 0);
}
/* Save a pointer to the whole packet */
ieee_hints->packet = packet;
/* Create the protocol tree. */
if (tree) {
proto_root = proto_tree_add_protocol_format(tree, proto_ieee802154, tvb, 0, tvb_captured_length(tvb), "IEEE 802.15.4");
ieee802154_tree = proto_item_add_subtree(proto_root, ett_ieee802154);
}
/* Add the protocol name. */
col_set_str(pinfo->cinfo, COL_PROTOCOL, "IEEE 802.15.4");
/* Add the packet length to the filter field */
hidden_item = proto_tree_add_uint(ieee802154_tree, hf_ieee802154_frame_length, NULL, 0, 0, tvb_reported_length(tvb));
PROTO_ITEM_SET_HIDDEN(hidden_item);
/* Frame Control Field */
dissect_ieee802154_fcf(tvb, pinfo, ieee802154_tree, packet, &offset);
/* Sequence Number */
if (packet->seqno_suppression) {
if (packet->version != IEEE802154_VERSION_2015) {
expert_add_info(pinfo, proto_root, &ei_ieee802154_seqno_suppression);
}
} else { /* IEEE 802.15.4 Sequence Number Suppression */
packet->seqno = tvb_get_guint8(tvb, offset);
if (tree) {
proto_tree_add_uint(ieee802154_tree, hf_ieee802154_seqno, tvb, offset, 1, packet->seqno);
/* For Ack packets display this in the root. */
if (packet->frame_type == IEEE802154_FCF_ACK) {
proto_item_append_text(proto_root, ", Sequence Number: %u", packet->seqno);
}
}
offset += 1;
}
/*
* ADDRESSING FIELDS
*/
/* Clear out the addressing strings. */
clear_address(&pinfo->net_dst);
clear_address(&pinfo->dl_dst);
clear_address(&pinfo->dst);
clear_address(&pinfo->net_src);
clear_address(&pinfo->dl_src);
clear_address(&pinfo->src);
if (packet->dst_addr_mode == IEEE802154_FCF_ADDR_RESERVED) {
/* Invalid Destination Address Mode. Abort Dissection. */
expert_add_info(pinfo, proto_root, &ei_ieee802154_dst);
return;
}
if (packet->src_addr_mode == IEEE802154_FCF_ADDR_RESERVED) {
/* Invalid Source Address Mode. Abort Dissection. */
expert_add_info(pinfo, proto_root, &ei_ieee802154_src);
return;
}
if (packet->version == IEEE802154_VERSION_RESERVED) {
/* Unknown Frame Version. Abort Dissection. */
expert_add_info(pinfo, proto_root, &ei_ieee802154_frame_ver);
return;
}
else if ((packet->version == IEEE802154_VERSION_2003) || /* For Frame Version 0b00 and */
(packet->version == IEEE802154_VERSION_2006)) { /* 0b01 effect defined in section 7.2.1.5 */
if ((packet->dst_addr_mode != IEEE802154_FCF_ADDR_NONE) && /* if both destination and source */
(packet->src_addr_mode != IEEE802154_FCF_ADDR_NONE)) { /* addressing information is present */
if (packet->pan_id_compression == 1) { /* PAN IDs are identical */
dstPanPresent = TRUE;
srcPanPresent = FALSE; /* source PAN ID is omitted */
}
else { /* PAN IDs are different, both shall be included in the frame */
dstPanPresent = TRUE;
srcPanPresent = TRUE;
}
}
else {
if (packet->pan_id_compression == 1) { /* all remaining cases pan_id_compression must be zero */
expert_add_info(pinfo, proto_root, &ei_ieee802154_invalid_addressing);
return;
}
else {
/* only either the destination or the source addressing information is present */
if ((packet->dst_addr_mode != IEEE802154_FCF_ADDR_NONE) && /* Present */
(packet->src_addr_mode == IEEE802154_FCF_ADDR_NONE)) { /* Not Present */
dstPanPresent = TRUE;
srcPanPresent = FALSE;
}
else if ((packet->dst_addr_mode == IEEE802154_FCF_ADDR_NONE) && /* Not Present */
(packet->src_addr_mode != IEEE802154_FCF_ADDR_NONE)) { /* Present */
dstPanPresent = FALSE;
srcPanPresent = TRUE;
}
else if ((packet->dst_addr_mode == IEEE802154_FCF_ADDR_NONE) && /* Not Present */
(packet->src_addr_mode == IEEE802154_FCF_ADDR_NONE)) { /* Not Present */
dstPanPresent = FALSE;
srcPanPresent = FALSE;
}
else {
expert_add_info(pinfo, proto_root, &ei_ieee802154_invalid_addressing);
return;
}
}
}
}
else if (packet->version == IEEE802154_VERSION_2015) {
/* for Frame Version 0b10 PAN Id Compression only applies to these frame types */
if ((packet->frame_type == IEEE802154_FCF_BEACON) ||
(packet->frame_type == IEEE802154_FCF_DATA) ||
(packet->frame_type == IEEE802154_FCF_ACK) ||
(packet->frame_type == IEEE802154_FCF_CMD) ) {
/* Implements Table 7-6 of IEEE 802.15.4-2015
*
* Destination Address Source Address Destination PAN ID Source PAN ID PAN ID Compression
*-------------------------------------------------------------------------------------------------
* 1. Not Present Not Present Not Present Not Present 0
* 2. Not Present Not Present Present Not Present 1
* 3. Present Not Present Present Not Present 0
* 4. Present Not Present Not Present Not Present 1
*
* 5. Not Present Present Not Present Present 0
* 6. Not Present Present Not Present Not Present 1
*
* 7. Extended Extended Present Not Present 0
* 8. Extended Extended Not Present Not Present 1
*
* 9. Short Short Present Present 0
* 10. Short Extended Present Present 0
* 11. Extended Short Present Present 0
*
* 12. Short Extended Present Not Present 1
* 13. Extended Short Present Not Present 1
* 14. Short Short Present Not Present 1
*/
/* Row 1 */
if ((packet->dst_addr_mode == IEEE802154_FCF_ADDR_NONE) && /* Not Present */
(packet->src_addr_mode == IEEE802154_FCF_ADDR_NONE) && /* Not Present */
(packet->pan_id_compression == 0)) {
dstPanPresent = FALSE;
srcPanPresent = FALSE;
}
/* Row 2 */
else if ((packet->dst_addr_mode == IEEE802154_FCF_ADDR_NONE) && /* Not Present */
(packet->src_addr_mode == IEEE802154_FCF_ADDR_NONE) && /* Not Present */
(packet->pan_id_compression == 1)) {
dstPanPresent = TRUE;
srcPanPresent = FALSE;
}
/* Row 3 */
else if ((packet->dst_addr_mode != IEEE802154_FCF_ADDR_NONE) && /* Present */
(packet->src_addr_mode == IEEE802154_FCF_ADDR_NONE) && /* Not Present */
(packet->pan_id_compression == 0)) {
dstPanPresent = TRUE;
srcPanPresent = FALSE;
}
/* Row 4 */
else if ((packet->dst_addr_mode != IEEE802154_FCF_ADDR_NONE) && /* Present */
(packet->src_addr_mode == IEEE802154_FCF_ADDR_NONE) && /* Not Present */
(packet->pan_id_compression == 1)) {
dstPanPresent = FALSE;
srcPanPresent = FALSE;
}
/* Row 5 */
else if ((packet->dst_addr_mode == IEEE802154_FCF_ADDR_NONE) && /* Not Present */
(packet->src_addr_mode != IEEE802154_FCF_ADDR_NONE) && /* Present */
(packet->pan_id_compression == 0)) {
dstPanPresent = FALSE;
srcPanPresent = TRUE;
}
/* Row 6 */
else if ((packet->dst_addr_mode == IEEE802154_FCF_ADDR_NONE) && /* Not Present */
(packet->src_addr_mode != IEEE802154_FCF_ADDR_NONE) && /* Present */
(packet->pan_id_compression == 1)) {
dstPanPresent = FALSE;
srcPanPresent = FALSE;
}
/* Row 7 */
else if ((packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT) && /* Extended */
(packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) && /* Extended */
(packet->pan_id_compression == 0)) {
dstPanPresent = TRUE;
srcPanPresent = FALSE;
}
/* Row 8 */
else if ((packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT) && /* Extended */
(packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) && /* Extended */
(packet->pan_id_compression == 1)) {
dstPanPresent = FALSE;
srcPanPresent = FALSE;
}
/* Row 9 */
else if ((packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) && /* Short */
(packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT) && /* Short */
(packet->pan_id_compression == 0)) {
dstPanPresent = TRUE;
srcPanPresent = TRUE;
}
/* Row 10 */
else if ((packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) && /* Short */
(packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) && /* Extended */
(packet->pan_id_compression == 0)) {
dstPanPresent = TRUE;
srcPanPresent = TRUE;
}
/* Row 11 */
else if ((packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT) && /* Extended */
(packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT) && /* Short */
(packet->pan_id_compression == 0)) {
dstPanPresent = TRUE;
srcPanPresent = TRUE;
}
/* Row 12 */
else if ((packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) && /* Short */
(packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) && /* Extended */
(packet->pan_id_compression == 1)) {
dstPanPresent = TRUE;
srcPanPresent = FALSE;
}
/* Row 13 */
else if ((packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT) && /* Extended */
(packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT) && /* Short */
(packet->pan_id_compression == 1)) {
dstPanPresent = TRUE;
srcPanPresent = FALSE;
}
/* Row 14 */
else if ((packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) && /* Short */
(packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT) && /* Short */
(packet->pan_id_compression == 1)) {
dstPanPresent = TRUE;
srcPanPresent = FALSE;
}
else {
expert_add_info(pinfo, proto_root, &ei_ieee802154_invalid_panid_compression2);
return;
}
}
else { /* Frame Type is neither Beacon, Data, Ack, nor Command: PAN ID Compression is not used */
dstPanPresent = FALSE; /* no PAN ID will */
srcPanPresent = FALSE; /* be present */
}
}
else {
/* Unknown Frame Version. Abort Dissection. */
expert_add_info(pinfo, proto_root, &ei_ieee802154_frame_ver);
return;
}
/*
* Addressing Fields
*/
/* Destination PAN Id */
if (dstPanPresent) {
packet->dst_pan = tvb_get_letohs(tvb, offset);
if (ieee802154_tree) {
proto_tree_add_uint(ieee802154_tree, hf_ieee802154_dst_panID, tvb, offset, 2, packet->dst_pan);
}
offset += 2;
}
/* Destination Address */
if (packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) {
gchar* dst_addr;
/* Get the address. */
packet->dst16 = tvb_get_letohs(tvb, offset);
/* Provide address hints to higher layers that need it. */
if (ieee_hints) {
ieee_hints->dst16 = packet->dst16;
}
set_address_tvb(&pinfo->dl_dst, ieee802_15_4_short_address_type, 2, tvb, offset);
copy_address_shallow(&pinfo->dst, &pinfo->dl_dst);
dst_addr = address_to_str(wmem_packet_scope(), &pinfo->dst);
proto_tree_add_uint(ieee802154_tree, hf_ieee802154_dst16, tvb, offset, 2, packet->dst16);
proto_item_append_text(proto_root, ", Dst: %s", dst_addr);
col_append_fstr(pinfo->cinfo, COL_INFO, ", Dst: %s", dst_addr);
offset += 2;
}
else if (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT) {
guint64 *p_addr = (guint64 *)wmem_new(pinfo->pool, guint64);
/* Get the address */
packet->dst64 = tvb_get_letoh64(tvb, offset);
/* Copy and convert the address to network byte order. */
*p_addr = pntoh64(&(packet->dst64));
/* Display the destination address. */
/* XXX - OUI resolution doesn't happen when displaying resolved
* EUI64 addresses; that should probably be fixed in
* epan/addr_resolv.c.
*/
set_address(&pinfo->dl_dst, AT_EUI64, 8, p_addr);
copy_address_shallow(&pinfo->dst, &pinfo->dl_dst);
if (tree) {
proto_tree_add_item(ieee802154_tree, hf_ieee802154_dst64, tvb, offset, 8, ENC_LITTLE_ENDIAN);
proto_item_append_text(proto_root, ", Dst: %s", eui64_to_display(wmem_packet_scope(), packet->dst64));
}
col_append_fstr(pinfo->cinfo, COL_INFO, ", Dst: %s", eui64_to_display(wmem_packet_scope(), packet->dst64));
offset += 8;
}
/* Source PAN Id */
if (srcPanPresent) {
packet->src_pan = tvb_get_letohs(tvb, offset);
proto_tree_add_uint(ieee802154_tree, hf_ieee802154_src_panID, tvb, offset, 2, packet->src_pan);
offset += 2;
}
else {
if (dstPanPresent) {
packet->src_pan = packet->dst_pan;
}
else {
packet->src_pan = IEEE802154_BCAST_PAN;
}
}
if (ieee_hints) {
ieee_hints->src_pan = packet->src_pan;
}
/* Source Address */
if (packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT) {
gchar* src_addr;
/* Get the address. */
packet->src16 = tvb_get_letohs(tvb, offset);
if (!pinfo->fd->flags.visited) {
/* If we know our extended source address from previous packets,
* provide a pointer to it in a hint for upper layers */
addr16.addr = packet->src16;
addr16.pan = packet->src_pan;
if (ieee_hints) {
ieee_hints->src16 = packet->src16;
ieee_hints->map_rec = (ieee802154_map_rec *)
g_hash_table_lookup(ieee802154_map.short_table, &addr16);
}
}
set_address_tvb(&pinfo->dl_src, ieee802_15_4_short_address_type, 2, tvb, offset);
copy_address_shallow(&pinfo->src, &pinfo->dl_src);
src_addr = address_to_str(wmem_packet_scope(), &pinfo->src);
/* Add the addressing info to the tree. */
if (tree) {
proto_tree_add_uint(ieee802154_tree, hf_ieee802154_src16, tvb, offset, 2, packet->src16);
proto_item_append_text(proto_root, ", Src: %s", src_addr);
if (ieee_hints && ieee_hints->map_rec) {
/* Display inferred source address info */
ti = proto_tree_add_eui64(ieee802154_tree, hf_ieee802154_src64, tvb, offset, 0,
ieee_hints->map_rec->addr64);
PROTO_ITEM_SET_GENERATED(ti);
if ( ieee_hints->map_rec->start_fnum ) {
ti = proto_tree_add_uint(ieee802154_tree, hf_ieee802154_src64_origin, tvb, 0, 0,
ieee_hints->map_rec->start_fnum);
}
else {
ti = proto_tree_add_uint_format_value(ieee802154_tree, hf_ieee802154_src64_origin, tvb, 0, 0,
ieee_hints->map_rec->start_fnum, "Pre-configured");
}
PROTO_ITEM_SET_GENERATED(ti);
}
}
col_append_fstr(pinfo->cinfo, COL_INFO, ", Src: %s", src_addr);
offset += 2;
}
else if (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) {
guint64 *p_addr = (guint64 *)wmem_new(pinfo->pool, guint64);
/* Get the address. */
packet->src64 = tvb_get_letoh64(tvb, offset);
/* Copy and convert the address to network byte order. */
*p_addr = pntoh64(&(packet->src64));
/* Display the source address. */
/* XXX - OUI resolution doesn't happen when displaying resolved
* EUI64 addresses; that should probably be fixed in
* epan/addr_resolv.c.
*/
set_address(&pinfo->dl_src, AT_EUI64, 8, p_addr);
copy_address_shallow(&pinfo->src, &pinfo->dl_src);
if (tree) {
proto_tree_add_item(ieee802154_tree, hf_ieee802154_src64, tvb, offset, 8, ENC_LITTLE_ENDIAN);
proto_item_append_text(proto_root, ", Src: %s", eui64_to_display(wmem_packet_scope(), packet->src64));
}
col_append_fstr(pinfo->cinfo, COL_INFO, ", Src: %s", eui64_to_display(wmem_packet_scope(), packet->src64));
offset += 8;
}
/* Check, but don't display the FCS yet, otherwise the payload dissection
* may be out of place in the tree. But we want to know if the FCS is OK in
* case the CRC is bad (don't want to continue dissection to the NWK layer).
*/
if (tvb_bytes_exist(tvb, tvb_reported_length(tvb)-IEEE802154_FCS_LEN, IEEE802154_FCS_LEN)) {
/* The FCS is in the last two bytes of the packet. */
guint16 fcs = tvb_get_letohs(tvb, tvb_reported_length(tvb)-IEEE802154_FCS_LEN);
/* Check if we are expecting a CC2420-style FCS*/
if (options & DISSECT_IEEE802154_OPTION_CC24xx) {
fcs_ok = (fcs & IEEE802154_CC24xx_CRC_OK);
}
else {
guint16 fcs_calc = ieee802154_crc_tvb(tvb, tvb_reported_length(tvb)-IEEE802154_FCS_LEN);
fcs_ok = (fcs == fcs_calc);
}
}
/* Existance of the Auxiliary Security Header is controlled by the Security Enabled Field */
if ((packet->security_enable) && (packet->version != IEEE802154_VERSION_2003)) {
dissect_ieee802154_aux_sec_header_and_key(tvb, pinfo, ieee802154_tree, packet, &offset);
}
/*
* NONPAYLOAD FIELDS
*
*/
/* All of the beacon fields, except the beacon payload are considered nonpayload. */
if ((packet->version == IEEE802154_VERSION_2003) || (packet->version == IEEE802154_VERSION_2006)) {
if (packet->frame_type == IEEE802154_FCF_BEACON) { /* Regular Beacon. Some are not present in frame version (Enhanced) Beacons */
dissect_ieee802154_superframe(tvb, pinfo, ieee802154_tree, &offset); /* superframe spec */
dissect_ieee802154_gtsinfo(tvb, pinfo, ieee802154_tree, &offset); /* GTS information fields */
dissect_ieee802154_pendaddr(tvb, pinfo, ieee802154_tree, &offset); /* Pending address list */
}
if (packet->frame_type == IEEE802154_FCF_CMD) {
/**
* In IEEE802.15.4-2003 and 2006 the command identifier is considered to be part of the header
* and is thus not encrypted. For IEEE802.15.4-2012e and later the command id is considered to be
* part of the payload, is encrypted, and follows the payload IEs. Thus we only parse the command id
* here for 2006 and earlier frames. */
packet->command_id = tvb_get_guint8(tvb, offset);
if (tree) {
proto_tree_add_uint(ieee802154_tree, hf_ieee802154_cmd_id, tvb, offset, 1, packet->command_id);
}
offset++;
/* Display the command identifier in the info column. */
col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(packet->command_id, ieee802154_cmd_names, "Unknown Command"));
}
}
else {
if (packet->ie_present) {
dissect_ieee802154_header_ie(tvb, pinfo, ieee802154_tree, &offset, packet);
}
}
/* IEEE 802.15.4-2003 may have security information pre-pended to payload */
if (packet->security_enable && (packet->version == IEEE802154_VERSION_2003)) {
/* Store security suite preference in the 2006 security level identifier to simplify 2003 integration! */
packet->security_level = (ieee802154_security_level)ieee802154_sec_suite;
/* Frame Counter and Key Sequence Counter prepended to the payload of an encrypted frame */
if (IEEE802154_IS_ENCRYPTED(packet->security_level)) {
packet->frame_counter = tvb_get_letohl (tvb, offset);
proto_tree_add_uint(ieee802154_tree, hf_ieee802154_sec_frame_counter, tvb, offset, (int)sizeof(guint32), packet->frame_counter);
offset += (int)sizeof(guint32);
packet->key_sequence_counter = tvb_get_guint8 (tvb, offset);
proto_tree_add_uint(ieee802154_tree, hf_ieee802154_sec_key_sequence_counter, tvb, offset, (int)sizeof(guint8), packet->key_sequence_counter);
offset += (int)sizeof(guint8);
}
}
/* Encrypted Payload. */
if (packet->security_enable) {
ieee802154_payload_info_t payload_info;
payload_info.rx_mic = rx_mic;
payload_info.rx_mic_length = &rx_mic_len;
payload_info.status = &status;
payload_info.key = NULL; /* payload function will fill that in */
payload_tvb = dissect_ieee802154_payload(tvb, offset, pinfo, header_tree, packet, &payload_info,
ieee802154_set_mac_key, dissect_ieee802154_decrypt);
/* Get the unencrypted data if decryption failed. */
if (!payload_tvb) {
/* Deal with possible truncation and the FCS field at the end. */
gint reported_len = tvb_reported_length(tvb)-offset-IEEE802154_FCS_LEN;
gint captured_len = tvb_captured_length(tvb)-offset;
if (reported_len < captured_len) captured_len = reported_len;
payload_tvb = tvb_new_subset_length_caplen(tvb, offset, captured_len, reported_len);
}
/* Display the MIC. */
if (rx_mic_len) {
mic_item = proto_tree_add_bytes(header_tree, hf_ieee802154_mic, tvb, 0, rx_mic_len, rx_mic);
PROTO_ITEM_SET_GENERATED(mic_item);
}
/* Display the reason for failure, and abort if the error was fatal. */
switch (status) {
case DECRYPT_PACKET_SUCCEEDED:
case DECRYPT_NOT_ENCRYPTED:
/* No problem */
proto_item_append_text(mic_item, " [correct (key no. %d)]", payload_info.key_number);
break;
case DECRYPT_VERSION_UNSUPPORTED:
/* We don't support decryption with that version of the protocol */
expert_add_info_format(pinfo, proto_root, &ei_ieee802154_decrypt_error, "We don't support decryption with protocol version %u", packet->version);
call_data_dissector(payload_tvb, pinfo, tree);
goto dissect_ieee802154_fcs;
case DECRYPT_PACKET_TOO_SMALL:
expert_add_info_format(pinfo, proto_root, &ei_ieee802154_decrypt_error, "Packet was too small to include the CRC and MIC");
call_data_dissector(payload_tvb, pinfo, tree);
goto dissect_ieee802154_fcs;
case DECRYPT_PACKET_NO_EXT_SRC_ADDR:
expert_add_info_format(pinfo, proto_root, &ei_ieee802154_decrypt_error, "No extended source address - can't decrypt");
call_data_dissector(payload_tvb, pinfo, tree);
goto dissect_ieee802154_fcs;
case DECRYPT_PACKET_NO_KEY:
expert_add_info_format(pinfo, proto_root, &ei_ieee802154_decrypt_error, "No encryption key set - can't decrypt");
call_data_dissector(payload_tvb, pinfo, tree);
goto dissect_ieee802154_fcs;
case DECRYPT_PACKET_DECRYPT_FAILED:
expert_add_info_format(pinfo, proto_root, &ei_ieee802154_decrypt_error, "Decrypt failed");
call_data_dissector(payload_tvb, pinfo, tree);
goto dissect_ieee802154_fcs;
case DECRYPT_PACKET_MIC_CHECK_FAILED:
expert_add_info_format(pinfo, proto_root, &ei_ieee802154_decrypt_error, "MIC check failed");
proto_item_append_text(mic_item, " [incorrect]");
/*
* Abort only if the payload was encrypted, in which case we
* probably didn't decrypt the packet right (eg: wrong key).
*/
if (IEEE802154_IS_ENCRYPTED(packet->security_level)) {
call_data_dissector(payload_tvb, pinfo, tree);
goto dissect_ieee802154_fcs;
}
break;
}
}
/* Plaintext Payload. */
else {
/* Deal with possible truncation and the FCS field at the end. */
gint reported_len = tvb_reported_length(tvb)-offset-IEEE802154_FCS_LEN;
gint captured_len = tvb_captured_length(tvb)-offset;
if (reported_len < captured_len) captured_len = reported_len;
payload_tvb = tvb_new_subset_length_caplen(tvb, offset, captured_len, reported_len);
}
/* presense of Payload IEs is defined by the termination of the Header IEs */
offset = 0;
if (packet->payload_ie_present) {
offset += dissect_ieee802154_payload_ie(payload_tvb, pinfo, ieee802154_tree, offset);
}
if ((packet->version == IEEE802154_VERSION_2015) && (packet->frame_type == IEEE802154_FCF_CMD)) {
/* In 802.15.4e and later the Command Id follows the Payload IEs. */
packet->command_id = tvb_get_guint8(payload_tvb, offset);
if (tree) {
proto_tree_add_uint(ieee802154_tree, hf_ieee802154_cmd_id, payload_tvb, offset, 1, packet->command_id);
}
offset++;
/* Display the command identifier in the info column. */
if ((packet->version == IEEE802154_VERSION_2015) && (packet->command_id == IEEE802154_CMD_BEACON_REQ)) {
col_set_str(pinfo->cinfo, COL_INFO, "Enhanced Beacon Request");
}
else {
col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(packet->command_id, ieee802154_cmd_names, "Unknown Command"));
}
}
if (offset > 0) {
payload_tvb = tvb_new_subset_remaining(payload_tvb, offset);
offset = 0;
}
/* If it is ok to dissect bad FCS, FCS might be absent, so still dissect
* commands like Association request. */
if ((!ieee802154_fcs_ok
/* If either ZBOSS traffic dump or TI CC2{45}xx, FCS must be present. */
&& !(options & (DISSECT_IEEE802154_OPTION_ZBOSS | DISSECT_IEEE802154_OPTION_CC24xx)))
|| tvb_captured_length(payload_tvb) > 0) {
/*
* Wrap the sub-dissection in a try/catch block in case the payload is
* broken. First we store the current protocol so we can fix it if an
* exception is thrown by the subdissectors.
*/
saved_proto = pinfo->current_proto;
/* Try to dissect the payload. */
TRY {
switch (packet->frame_type) {
case IEEE802154_FCF_BEACON:
if (!dissector_try_heuristic(ieee802154_beacon_subdissector_list, payload_tvb, pinfo, tree, &hdtbl_entry, packet)) {
/* Could not subdissect, call the data dissector instead. */
call_data_dissector(payload_tvb, pinfo, tree);
}
break;
case IEEE802154_FCF_CMD:
dissect_ieee802154_command(payload_tvb, pinfo, ieee802154_tree, packet);
break;
case IEEE802154_FCF_DATA:
/* Sanity-check. */
if ((!fcs_ok && ieee802154_fcs_ok) || !tvb_reported_length(payload_tvb)) {
call_data_dissector(payload_tvb, pinfo, tree);
break;
}
if (options & DISSECT_IEEE802154_OPTION_ZBOSS) {
call_dissector_with_data(zigbee_nwk_handle, payload_tvb, pinfo, tree, packet);
break;
}
/* Try the PANID dissector table for stateful dissection. */
if (dissector_try_uint_new(panid_dissector_table, packet->src_pan, payload_tvb, pinfo, tree, TRUE, packet)) {
break;
}
/* Try again with the destination PANID (if different) */
if (((packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) ||
(packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT)) &&
(packet->dst_pan != packet->src_pan) &&
dissector_try_uint_new(panid_dissector_table, packet->src_pan, payload_tvb, pinfo, tree, TRUE, packet)) {
break;
}
/* Try heuristic dissection. */
if (dissector_try_heuristic(ieee802154_heur_subdissector_list, payload_tvb, pinfo, tree, &hdtbl_entry, packet)) break;
/* Fall-through to dump undissectable payloads. */
/* FALL THROUGH */
default:
/* Could not subdissect, call the data dissector instead. */
call_data_dissector(payload_tvb, pinfo, tree);
} /* switch */
}
CATCH_ALL {
/*
* Someone encountered an error while dissecting the payload. But
* we haven't yet finished processing all of our layer. Catch and
* display the exception, then fall-through to finish displaying
* the FCS (which we display last so the frame is ordered correctly
* in the tree).
*/
show_exception(payload_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
pinfo->current_proto = saved_proto;
}
ENDTRY;
}
/*
* Frame Check Sequence (FCS)
*
*/
dissect_ieee802154_fcs:
/* The FCS should be the last bytes of the reported packet. */
offset = tvb_reported_length(tvb)-IEEE802154_FCS_LEN;
/* Dissect the FCS only if it exists (captures which don't or can't get the
* FCS will simply truncate the packet to omit it, but should still set the
* reported length to cover the original packet length), so if the snapshot
* is too short for an FCS don't make a fuss.
*/
if (tvb_bytes_exist(tvb, offset, IEEE802154_FCS_LEN) && (tree)) {
proto_tree *field_tree;
guint16 fcs = tvb_get_letohs(tvb, offset);
/* Display the FCS depending on expected FCS format */
if ((options & DISSECT_IEEE802154_OPTION_CC24xx)) {
/* Create a subtree for the FCS. */
field_tree = proto_tree_add_subtree_format(ieee802154_tree, tvb, offset, 2, ett_ieee802154_fcs, NULL,
"Frame Check Sequence (TI CC24xx format): FCS %s", (fcs_ok) ? "OK" : "Bad");
/* Display FCS contents. */
proto_tree_add_int(field_tree, hf_ieee802154_rssi, tvb, offset++, 1, (gint8) (fcs & IEEE802154_CC24xx_RSSI));
proto_tree_add_boolean(field_tree, hf_ieee802154_fcs_ok, tvb, offset, 1, (gboolean) (fcs & IEEE802154_CC24xx_CRC_OK));
proto_tree_add_uint(field_tree, hf_ieee802154_correlation, tvb, offset, 1, (guint8) ((fcs & IEEE802154_CC24xx_CORRELATION) >> 8));
}
else {
ti = proto_tree_add_uint(ieee802154_tree, hf_ieee802154_fcs, tvb, offset, 2, fcs);
if (fcs_ok) {
proto_item_append_text(ti, " (Correct)");
}
else {
proto_item_append_text(ti, " (Incorrect, expected FCS=0x%04x)", ieee802154_crc_tvb(tvb, offset));
}
/* To Help with filtering, add the fcs_ok field to the tree. */
ti = proto_tree_add_boolean(ieee802154_tree, hf_ieee802154_fcs_ok, tvb, offset, 2, fcs_ok);
PROTO_ITEM_SET_HIDDEN(ti);
}
}
else if (tree) {
/* Even if the FCS isn't present, add the fcs_ok field to the tree to
* help with filter. Be sure not to make it visible though.
*/
ti = proto_tree_add_boolean_format_value(ieee802154_tree, hf_ieee802154_fcs_ok, tvb, offset, 2, fcs_ok, "Unknown");
PROTO_ITEM_SET_HIDDEN(ti);
}
/* If the CRC is invalid, make a note of it in the info column. */
if (!fcs_ok) {
col_append_str(pinfo->cinfo, COL_INFO, ", Bad FCS");
if (tree) proto_item_append_text(proto_root, ", Bad FCS");
/* Flag packet as having a bad crc. */
expert_add_info(pinfo, proto_root, &ei_ieee802154_fcs);
}
} /* dissect_ieee802154_common */
/**
*Subdissector command for the Header Information Element TSCH Time Correction
*
* This field is constructed by taking a signed 16-bit 2's compliment time
* correction in the range of - 2048 us to 2047 us, AND'ing it with 0xfff, and
* OR'ing again with 0x8000 to indicate a negative acknowledgment.
*
*@param tvb pointer to buffer containing raw packet.
*@param h_inf_elem_tree pointer to data tree wireshark uses to display packet.
*@param offset offset into the tvbuff to begin dissection.
*/
static void
dissect_802154_h_ie_time_correction(tvbuff_t *tvb, proto_tree *h_inf_elem_tree, guint *offset, packet_info *pinfo) {
guint16 raw_data;
proto_tree *time_correction_tree = NULL;
gboolean is_nack;
proto_item *time_correction_item = NULL;
proto_item *boolean_item = NULL;
proto_item *drift_item = NULL;
raw_data = tvb_get_letohs(tvb, *offset);
is_nack = (gboolean) ((raw_data & (guint16)0x8000) ? 1 : 0);
gint16 drift_us = 0;
if(raw_data & 0x0800) { /* Negative integer */
drift_us = (gint16) (raw_data | 0xf000);
} else { /* Positive integer */
drift_us = (gint16) (raw_data & 0x0fff);
}
time_correction_item = proto_tree_add_item(h_inf_elem_tree, hf_ieee802154_time_correction, tvb, *offset, 2, ENC_NA);
time_correction_tree = proto_item_add_subtree(time_correction_item, ett_ieee802154_h_ie_payload);
proto_item_set_text(time_correction_item, "Time correction: %d us | Non-acknowledgement: %s", drift_us, (guint32) is_nack ? "True" : "False");
/* Acknowledge with positive time correction in microseconds */
if(raw_data <= 0x07ff) {
drift_item = proto_tree_add_int(time_correction_tree, hf_ieee802154_time_correction_value, tvb, *offset, 2, drift_us);
boolean_item = proto_tree_add_boolean(time_correction_tree, hf_ieee802154_nack, tvb, *offset, 2, (guint32) is_nack);
}
/* Acknowledge with negative time correction in microseconds */
else if ((0x0800 <= raw_data) && (raw_data <= 0x0fff)){
drift_item = proto_tree_add_int(time_correction_tree, hf_ieee802154_time_correction_value, tvb, *offset, 2, drift_us);
boolean_item = proto_tree_add_boolean(time_correction_tree, hf_ieee802154_nack, tvb, *offset, 2, (guint32) is_nack);
}
/* Negative acknowledgment with positive time correction in microseconds */
else if ((0x8000 <= raw_data) && (raw_data <= 0x87ff)){
drift_item = proto_tree_add_int(time_correction_tree, hf_ieee802154_time_correction_value, tvb, *offset, 2, drift_us);
boolean_item = proto_tree_add_boolean(time_correction_tree, hf_ieee802154_nack, tvb, *offset, 2, (guint32) is_nack);
}
/* Negative acknowledgment with negative time correction in microseconds */
else if ((0x8800 <= raw_data) && (raw_data <= 0x8fff )){
drift_item = proto_tree_add_int(time_correction_tree, hf_ieee802154_time_correction_value, tvb, *offset, 2, drift_us);
boolean_item = proto_tree_add_boolean(time_correction_tree, hf_ieee802154_nack, tvb, *offset, 2, (guint32) is_nack);
}
/* Incorrect value */
else {
expert_add_info(pinfo, time_correction_item, &ei_ieee802154_time_correction_error);
}
PROTO_ITEM_SET_GENERATED(drift_item);
PROTO_ITEM_SET_GENERATED(boolean_item);
*offset += 2;
} /* dissect_802154_h_ie_time_correction */
/**
*Subdissector command for the Payload Information Element MLME TSCH Channel Hopping
*
*@param tvb pointer to buffer containing raw packet.
*@param p_inf_elem_tree_mlme pointer to data tree wireshark uses to display packet.
*@param psie_remaining size of the Information Element.
*@param offset offset into the tvbuff to begin dissection.
*/
static void
dissect_802154_tsch_channel_hopping(tvbuff_t *tvb, proto_tree *p_inf_elem_tree_mlme, guint16 psie_remaining, guint *offset){
proto_item *tsch_channel_hopping_data_item = NULL;
proto_tree *tsch_channel_hopping_data_tree = NULL;
guint8 hopping_sequence_id;
hopping_sequence_id = tvb_get_guint8(tvb, *offset);
tsch_channel_hopping_data_item = proto_tree_add_item(p_inf_elem_tree_mlme, hf_ieee802154_tsch_channel_hopping, tvb, (*offset), 1, ENC_LITTLE_ENDIAN);
tsch_channel_hopping_data_tree = proto_item_add_subtree(tsch_channel_hopping_data_item, ett_ieee802154_mlme_payload);
proto_item_set_text(tsch_channel_hopping_data_item, "Data: Channel Hopping IE (0x%0d)", hopping_sequence_id);
proto_item_set_len(tsch_channel_hopping_data_item, psie_remaining);
proto_tree_add_item(tsch_channel_hopping_data_tree, hf_ieee802154_tsch_hopping_sequence_id, tvb, (*offset), 1, ENC_LITTLE_ENDIAN);
if (psie_remaining > 1){
proto_tree_add_item(tsch_channel_hopping_data_tree, hf_ieee802154_mlme_ie_data, tvb, *offset, psie_remaining, ENC_NA);
}
*offset += psie_remaining;
} /* dissect_802154_tsch_channel_hopping */
/**
*Subdissector command for the Payload Information Element MLME TSCH Synchronization
*
*@param tvb pointer to buffer containing raw packet.
*@param p_inf_elem_tree_mlme pointer to data tree wireshark uses to display packet.
*@param offset offset into the tvbuff to begin dissection.
*/
static void
dissect_802154_tsch_time_sync(tvbuff_t *tvb, proto_tree *p_inf_elem_tree_mlme, guint *offset){
proto_item *tsch_sync_data_item = NULL;
proto_tree *tsch_sync_data_tree = NULL;
tsch_sync_data_item = proto_tree_add_item(p_inf_elem_tree_mlme, hf_ieee802154_tsch_sync, tvb, (*offset), 6, ENC_LITTLE_ENDIAN);
tsch_sync_data_tree = proto_item_add_subtree(tsch_sync_data_item, ett_ieee802154_mlme_payload);
proto_item_set_text(tsch_sync_data_item, "Data: TSCH Synchronization IE");
proto_tree_add_item(tsch_sync_data_tree, hf_ieee802154_tsch_asn, tvb, (*offset), 5, ENC_LITTLE_ENDIAN);
proto_tree_add_item(tsch_sync_data_tree, hf_ieee802154_tsch_join_metric, tvb, (*offset) + 5, 1, ENC_LITTLE_ENDIAN);
*offset += 6;
}/* dissect_802154_tsch_time_sync*/
/**
*Subdissector command for the Payload Information Element MLME TSCH Slotframe and Link
*
*@param tvb pointer to buffer containing raw packet.
*@param p_inf_elem_tree_mlme pointer to data tree wireshark uses to display packet.
*@param psie_remaining size of the Information Element.
*@param offset offset into the tvbuff to begin dissection.
*/
static void
dissect_802154_p_ie_sh_mlme_tsch_slotframe_link(tvbuff_t *tvb, proto_tree *p_inf_elem_tree_mlme, guint16 psie_remaining, guint *offset){
guint8 nb_slotframes;
guint8 nb_slotframes_aux;
guint8 nb_links;
guint8 nb_links_aux;
proto_tree *p_inf_elem_tree_mlme_payload = NULL;
proto_tree *p_inf_elem_tree_mlme_payload_data = NULL;
proto_tree *p_inf_elem_tree_psie_slotframe_link_slotframes = NULL;
guint8 slotframe_index;
nb_slotframes = tvb_get_guint8(tvb, *offset);
nb_slotframes_aux = nb_slotframes;
p_inf_elem_tree_mlme_payload = proto_tree_add_subtree_format(p_inf_elem_tree_mlme, tvb, *offset, psie_remaining, ett_ieee802154_mlme_payload, NULL,
"Data: Slotframe and Link IE");
proto_tree_add_item(p_inf_elem_tree_mlme_payload, hf_ieee802154_tsch_slotf_link_nb_slotf, tvb, (*offset), 1, ENC_LITTLE_ENDIAN);
*offset += 1;
slotframe_index = 1;
while ( nb_slotframes_aux > 0 ){
nb_links = tvb_get_guint8(tvb, *offset+3);
nb_links_aux = nb_links;
p_inf_elem_tree_psie_slotframe_link_slotframes =
proto_tree_add_subtree_format(p_inf_elem_tree_mlme_payload,
tvb, *offset, 4 + 5 * nb_links_aux,
ett_ieee802154_psie_slotframe_link_slotframes,
NULL, "Slotframes [%u]", slotframe_index);
slotframe_index += 1;
proto_tree_add_item(p_inf_elem_tree_psie_slotframe_link_slotframes, hf_ieee802154_tsch_slotf_link_slotf_handle, tvb, (*offset), 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(p_inf_elem_tree_psie_slotframe_link_slotframes, hf_ieee802154_tsch_slotf_size, tvb, (*offset) + 1, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(p_inf_elem_tree_psie_slotframe_link_slotframes, hf_ieee802154_tsch_slotf_link_nb_links, tvb, (*offset) + 3, 1, ENC_LITTLE_ENDIAN);
nb_slotframes_aux -= 1;
*offset += 4;
while (nb_links_aux > 0) {
p_inf_elem_tree_mlme_payload_data = proto_tree_add_subtree_format(p_inf_elem_tree_psie_slotframe_link_slotframes, tvb, *offset, 5, ett_ieee802154_mlme_payload_data, NULL,
"Data: Link Information");
proto_tree_add_item(p_inf_elem_tree_mlme_payload_data, hf_ieee802154_tsch_slotf_link_timeslot, tvb, (*offset), 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(p_inf_elem_tree_mlme_payload_data, hf_ieee802154_tsch_slotf_link_channel_offset, tvb, (*offset) + 2, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(p_inf_elem_tree_mlme_payload_data, hf_ieee802154_tsch_slotf_link_options, tvb, (*offset) + 4, 1, ENC_LITTLE_ENDIAN);
nb_links_aux -= 1;
*offset += 5;
}
}
}/* dissect_802154_p_ie_sh_mlme_tsch_slotframe_link */
/**
*Subdissector command for the 6TOP Protocol contained within the Payload Information Elements.
*
*@param tvb pointer to buffer containing raw packet.
*@param pinfo pointer to packet information fields.
*@param p_inf_elem_tree pointer to data tree wireshark uses to display packet.
*@param offset offset into the tvbuff to begin dissection.
*@param pie_length size of the 6TOP message
*/
static int
dissect_ieee802154_6top(tvbuff_t *tvb, packet_info *pinfo, proto_tree *p_inf_elem_tree, guint offset, gint pie_length)
{
const guint8 supported_6p_version = 1;
guint8 subie;
guint8 version;
guint8 type;
guint8 code;
guint8 seqnum;
guint8 gab;
guint8 gba;
int orig_offset = offset;
gboolean have_cell_list = FALSE;
int i;
proto_tree *sixtop_tree = NULL;
proto_tree *version_type_tree = NULL;
proto_tree *seqnum_gab_gba_tree = NULL;
proto_tree *cell_list_tree = NULL;
proto_tree *cell_tree = NULL;
proto_item *type_item = NULL;
proto_item *code_item = NULL;
const gchar *code_str = NULL;
static const int * cell_options[] = {
&hf_ieee802154_6top_cell_option_tx,
&hf_ieee802154_6top_cell_option_rx,
&hf_ieee802154_6top_cell_option_shared,
&hf_ieee802154_6top_cell_option_reserved,
NULL
};
if (pie_length < 5) {
return pie_length;
}
subie = tvb_get_guint8(tvb, offset);
version = tvb_get_guint8(tvb, offset + 1) & IETF_6TOP_VERSION;
if (subie != IEEE802154_IETF_SUBIE_6TOP || version != supported_6p_version) {
return pie_length;
}
type = (tvb_get_guint8(tvb, offset + 1) & IETF_6TOP_TYPE) >> 4;
code = tvb_get_guint8(tvb, offset + 2);
seqnum = tvb_get_guint8(tvb, offset + 4) & IETF_6TOP_SEQNUM;
gab = (tvb_get_guint8(tvb, offset + 4) & IETF_6TOP_GAB) >> 4;
gba = (tvb_get_guint8(tvb, offset + 4) & IETF_6TOP_GBA) >> 6;
proto_tree_add_item(p_inf_elem_tree, hf_ieee802154_p_ie_ietf_sub_id, tvb, offset, 1, ENC_LITTLE_ENDIAN);
sixtop_tree = proto_tree_add_subtree_format(p_inf_elem_tree, tvb, offset, pie_length, ett_ieee802154_p_ie_6top, NULL, "6top IE Content");
version_type_tree = proto_tree_add_subtree_format(sixtop_tree, tvb, offset + 1, 1, ett_ieee802154_p_ie_6top_version_type, NULL,
"Version: %u, Type: %s", version, val_to_str_const(type, ietf_6top_types,"Unknown"));
proto_tree_add_item(version_type_tree, hf_ieee802154_6top_version, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
type_item = proto_tree_add_item(version_type_tree, hf_ieee802154_6top_type, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(version_type_tree, hf_ieee802154_6top_flags_reserved, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
code_item = proto_tree_add_item(sixtop_tree, hf_ieee802154_6top_code, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(sixtop_tree, hf_ieee802154_6top_sfid, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
seqnum_gab_gba_tree = proto_tree_add_subtree_format(sixtop_tree, tvb, offset + 4, 1, ett_ieee802154_p_ie_6top_seqnum_gab_gba, NULL,
"Seqnum: %u, GAB: %u, GBA: %u", seqnum, gab, gba);
proto_tree_add_item(seqnum_gab_gba_tree, hf_ieee802154_6top_seqnum, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(seqnum_gab_gba_tree, hf_ieee802154_6top_gab, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(seqnum_gab_gba_tree, hf_ieee802154_6top_gba, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
col_set_str(pinfo->cinfo, COL_PROTOCOL, "6top");
if (type == IETF_6TOP_TYPE_REQUEST) {
code_str = val_to_str_const(code, ietf_6top_command_identifiers,"Unknown");
col_add_fstr(pinfo->cinfo, COL_INFO, "6P %s Request", code_str);
} else {
code_str = val_to_str_const(code, ietf_6top_return_codes,"Unknown");
col_add_fstr(pinfo->cinfo, COL_INFO, "6P %s (%s)",
val_to_str_const(type, ietf_6top_types,"Unknown"), code_str);
}
proto_item_append_text(code_item, " (%s)", code_str);
offset += 5;
pie_length -= 5;
if (type == IETF_6TOP_TYPE_REQUEST) {
switch(code) {
case IETF_6TOP_CMD_ADD:
case IETF_6TOP_CMD_DELETE:
if (pie_length < 4) {
break;
}
proto_tree_add_item(sixtop_tree, hf_ieee802154_6top_metadata, tvb, offset, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_bitmask(sixtop_tree, tvb, offset + 2, hf_ieee802154_6top_cell_options, ett_ieee802154_p_ie_6top_cell_options, cell_options, ENC_LITTLE_ENDIAN);
proto_tree_add_item(sixtop_tree, hf_ieee802154_6top_num_cells, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
pie_length -= 4;
offset += 4;
if (pie_length > 0 && (pie_length % 4) == 0) {
have_cell_list = TRUE;
}
break;
case IETF_6TOP_CMD_STATUS:
if (pie_length < 3) {
break;
}
proto_tree_add_item(sixtop_tree, hf_ieee802154_6top_metadata, tvb, offset, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_bitmask(sixtop_tree, tvb, offset + 2, hf_ieee802154_6top_cell_options, ett_ieee802154_p_ie_6top_cell_options, cell_options, ENC_LITTLE_ENDIAN);
pie_length -= 3;
offset += 3;
break;
case IETF_6TOP_CMD_LIST:
if (pie_length != 8) {
break;
}
proto_tree_add_item(sixtop_tree, hf_ieee802154_6top_metadata, tvb, offset, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_bitmask(sixtop_tree, tvb, offset + 2, hf_ieee802154_6top_cell_options, ett_ieee802154_p_ie_6top_cell_options, cell_options, ENC_LITTLE_ENDIAN);
proto_tree_add_item(sixtop_tree, hf_ieee802154_6top_reserved, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(sixtop_tree, hf_ieee802154_6top_offset, tvb, offset + 4, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(sixtop_tree, hf_ieee802154_6top_max_num_cells, tvb, offset + 6, 2, ENC_LITTLE_ENDIAN);
pie_length -= 8;
offset += 8;
break;
case IETF_6TOP_CMD_CLEAR:
if (pie_length < 2) {
break;
}
proto_tree_add_item(sixtop_tree, hf_ieee802154_6top_metadata, tvb, offset, 2, ENC_LITTLE_ENDIAN);
pie_length -= 2;
offset += 2;
break;
default:
/* unsupported command */
expert_add_info(pinfo, code_item, &ei_ieee802154_6top_unsupported_command);
break;
}
} else if (type == IETF_6TOP_TYPE_RESPONSE || type == IETF_6TOP_TYPE_CONFIRMATION) {
switch(code) {
case IETF_6TOP_RC_SUCCESS:
if (pie_length > 0) {
if (pie_length == 1) {
proto_tree_add_item(sixtop_tree, hf_ieee802154_6top_num_cells, tvb, offset, 1, ENC_LITTLE_ENDIAN);
pie_length -= 1;
offset += 1;
} else if ((pie_length % 4) == 0) {
have_cell_list = TRUE;
}
}
break;
case IETF_6TOP_RC_ERR_VER:
case IETF_6TOP_RC_ERR_SFID:
case IETF_6TOP_RC_ERR_GEN:
case IETF_6TOP_RC_ERR_BUSY:
case IETF_6TOP_RC_ERR_NORES:
case IETF_6TOP_RC_ERR_RESET:
case IETF_6TOP_RC_ERR:
/* They have no other field */
break;
default:
/* unsupported return code */
expert_add_info(pinfo, code_item, &ei_ieee802154_6top_unsupported_return_code);
break;
}
} else {
/* unsupported type */
expert_add_info(pinfo, type_item, &ei_ieee802154_6top_unsupported_type);
}
if (have_cell_list) {
cell_list_tree = proto_tree_add_subtree_format(sixtop_tree, tvb, offset, pie_length, ett_ieee802154_p_ie_6top_cell_list, NULL,
"Cell List");
for (i = 0; pie_length > 0; pie_length -= 4, offset += 4, i++){
cell_tree = proto_tree_add_subtree_format(cell_list_tree, tvb, offset, 4, ett_ieee802154_p_ie_6top_cell, NULL,
"Cell [%u]", i);
proto_tree_add_item(cell_tree, hf_ieee802154_6top_slot_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(cell_tree, hf_ieee802154_6top_channel_offset, tvb, offset + 2, 2, ENC_LITTLE_ENDIAN);
}
}
return offset - orig_offset;
} /* dissect_ieee802154_6top */
/**
*Subdissector command for the Superframe specification sub-field within the beacon frame.
*
*@param tvb pointer to buffer containing raw packet.
*@param pinfo pointer to packet information fields (unused).
*@param tree pointer to command subtree.
*@param offset offset into the tvbuff to begin dissection.
*/
void
dissect_ieee802154_superframe(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint *offset)
{
static const int * superframe[] = {
&hf_ieee802154_beacon_order,
&hf_ieee802154_superframe_order,
&hf_ieee802154_cap,
&hf_ieee802154_superframe_battery_ext,
&hf_ieee802154_superframe_coord,
&hf_ieee802154_assoc_permit,
NULL
};
proto_tree_add_bitmask_text(tree, tvb, *offset, 2, "Superframe Specification: ", NULL , ett_ieee802154_superframe, superframe, ENC_LITTLE_ENDIAN, BMT_NO_INT|BMT_NO_TFS);
(*offset) += 2;
} /* dissect_ieee802154_superframe */
/**
*Subdissector command for the GTS information fields within the beacon frame.
*
*@param tvb - pointer to buffer containing raw packet.
*@param pinfo - pointer to packet information fields (unused).
*@param tree - pointer to command subtree.
*@param offset - offset into the tvbuff to begin dissection.
*/
void
dissect_ieee802154_gtsinfo(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint *offset)
{
proto_tree *field_tree = NULL;
proto_tree *subtree = NULL;
proto_item *ti;
guint8 gts_spec;
guint8 gts_count;
/* Get and display the GTS specification field */
gts_spec = tvb_get_guint8(tvb, *offset);
gts_count = gts_spec & IEEE802154_GTS_COUNT_MASK;
if (tree) {
/* Add Subtree for GTS information. */
if (gts_count) {
field_tree = proto_tree_add_subtree(tree, tvb, *offset, 2 + (gts_count * 3), ett_ieee802154_gts, NULL, "GTS");
}
else {
field_tree = proto_tree_add_subtree(tree, tvb, *offset, 1, ett_ieee802154_gts, NULL, "GTS");
}
proto_tree_add_uint(field_tree, hf_ieee802154_gts_count, tvb, *offset, 1, gts_count);
proto_tree_add_boolean(field_tree, hf_ieee802154_gts_permit, tvb, *offset, 1, gts_spec & IEEE802154_GTS_PERMIT_MASK);
}
(*offset) += 1;
/* If the GTS descriptor count is nonzero, then the GTS directions mask and descriptor list are present. */
if (gts_count) {
guint8 gts_directions = tvb_get_guint8(tvb, *offset);
guint gts_rx = 0;
int i;
/* Display the directions mask. */
if (tree) {
proto_tree *dir_tree;
/* Create a subtree. */
dir_tree = proto_tree_add_subtree(field_tree, tvb, *offset, 1, ett_ieee802154_gts_direction, &ti, "GTS Directions");
/* Add the directions to the subtree. */
for (i=0; i<gts_count; i++) {
gboolean dir = gts_directions & IEEE802154_GTS_DIRECTION_SLOT(i);
proto_tree_add_boolean_format(dir_tree, hf_ieee802154_gts_direction, tvb, *offset, 1, dir, "GTS Slot %i: %s", i+1, dir?"Receive Only":"Transmit Only");
if (dir) gts_rx++;
} /* for */
proto_item_append_text(ti, ": %i Receive & %i Transmit", gts_rx, gts_count - gts_rx);
}
(*offset) += 1;
/* Create a subtree for the GTS descriptors. */
subtree = proto_tree_add_subtree(field_tree, tvb, *offset, gts_count * 3, ett_ieee802154_gts_descriptors, NULL, "GTS Descriptors");
/* Get and display the GTS descriptors. */
for (i=0; i<gts_count; i++) {
guint16 gts_addr = tvb_get_letohs(tvb, (*offset));
guint8 gts_slot = tvb_get_guint8(tvb, (*offset)+2);
guint8 gts_length = (gts_slot & IEEE802154_GTS_LENGTH_MASK) >> IEEE802154_GTS_LENGTH_SHIFT;
gts_slot = (gts_slot & IEEE802154_GTS_SLOT_MASK);
if (tree) {
/* Add address, slot, and time length fields. */
ti = proto_tree_add_uint(subtree, hf_ieee802154_gts_address, tvb, (*offset), 3, gts_addr);
proto_item_append_text(ti, ", Slot: %i", gts_slot);
proto_item_append_text(ti, ", Length: %i", gts_length);
}
(*offset) += 3;
} /* for */
}
} /* dissect_ieee802154_gtsinfo */
/**
*Subdissector command for the pending address list fields within the beacon frame.
*
*@param tvb pointer to buffer containing raw packet.
*@param pinfo pointer to packet information fields (unused).
*@param tree pointer to command subtree.
*@offset offset into the tvbuff to begin dissection.
*/
void
dissect_ieee802154_pendaddr(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint *offset)
{
proto_tree *subtree;
guint8 pend_spec;
guint8 pend_num16;
guint8 pend_num64;
int i;
/* Get the Pending Addresses specification fields */
pend_spec = tvb_get_guint8(tvb, *offset);
pend_num16 = pend_spec & IEEE802154_PENDADDR_SHORT_MASK;
pend_num64 = (pend_spec & IEEE802154_PENDADDR_LONG_MASK) >> IEEE802154_PENDADDR_LONG_SHIFT;
/* Add Subtree for the addresses */
subtree = proto_tree_add_subtree_format(tree, tvb, *offset, 1 + 2*pend_num16 + 8*pend_num64,
ett_ieee802154_pendaddr, NULL, "Pending Addresses: %i Short and %i Long", pend_num16, pend_num64);
(*offset) += 1;
for (i=0; i<pend_num16; i++) {
guint16 addr = tvb_get_letohs(tvb, *offset);
proto_tree_add_uint(subtree, hf_ieee802154_pending16, tvb, *offset, 2, addr);
(*offset) += 2;
} /* for */
for (i=0; i<pend_num64; i++) {
proto_tree_add_item(subtree, hf_ieee802154_pending64, tvb, *offset, 8, ENC_LITTLE_ENDIAN);
(*offset) += 8;
} /* for */
} /* dissect_ieee802154_pendaddr */
/**
*Subdissector for Header IEs (Information Elements)
*Since the header is never encrypted and the payload may be encrypted,
*we dissect header and payload IEs separately.
*The termination of the Header IE tells us whether there are any
*payload IEs to follow, so it is always set by the termination.
*
*@param tvb pointer to buffer containing raw packet.
*@param pinfo pointer to packet information fields.
*@param tree pointer to command subtree.
*@param offset offset into the tvbuff to begin dissection.
*@param packet IEEE 802.15.4 packet information.
*/
static void
dissect_ieee802154_header_ie(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint *offset, ieee802154_packet *packet)
{
proto_tree *subtree;
guint16 header_ie;
guint16 id;
guint16 length;
GByteArray *gba = g_byte_array_new();
static const int * fields[] = {
&hf_ieee802154_header_ie_type,
&hf_ieee802154_header_ie_id,
&hf_ieee802154_header_ie_length,
NULL
};
do {
header_ie = tvb_get_letohs(tvb, *offset);
id = (guint16) ((header_ie & IEEE802154_HEADER_IE_ID_MASK) >> 7);
length = (guint16) (header_ie & IEEE802154_HEADER_IE_LENGTH_MASK);
/* Create a subtree for this command frame. */
subtree = proto_tree_add_subtree(tree, tvb, *offset, 2+length, ett_ieee802154_header, NULL, "Header IE");
proto_item_append_text(subtree, ", Element ID: %s, Length: %d", val_to_str_const(id, ieee802154_header_ie_names, "Unknown IE"), length);
proto_tree_add_bitmask(subtree, tvb, *offset, hf_ieee802154_header_ie,
ett_ieee802154_header_ie, fields, ENC_LITTLE_ENDIAN);
*offset += 2;
/* until the Header IEs are finalized, just use the data dissector */
if (length > 0) {
switch(id){
case IEEE802154_HEADER_IE_TIME_CORR:
dissect_802154_h_ie_time_correction(tvb, subtree, offset, pinfo);
break;
case IEEE802154_HEADER_VENDOR_SPECIFIC:
case IEEE802154_HEADER_IE_CSL:
case IEEE802154_HEADER_IE_RIT:
case IEEE802154_HEADER_IE_DSME_PAN:
case IEEE802154_HEADER_IE_RENDEZVOUS:
case IEEE802154_HEADER_IE_EXT_DSME_PAN:
case IEEE802154_HEADER_IE_FSCD:
case IEEE802154_HEADER_IE_SMPL_SUPER_FRM:
case IEEE802154_HEADER_IE_SMPL_GTS:
case IEEE802154_HEADER_IE_LECIM:
case IEEE802154_HEADER_IE_TRLE:
case IEEE802154_HEADER_IE_RCC_CAP:
case IEEE802154_HEADER_IE_RCCN:
case IEEE802154_HEADER_IE_GLOBAL_TIME:
case IEEE802154_HEADER_IE_DA_IE:
default:
proto_tree_add_bytes_item(subtree, hf_ieee802154_header_ie_data, tvb, *offset, length, ENC_NA, gba, NULL, NULL);
*offset += length;
break;
}
}
} while ((tvb_reported_length_remaining(tvb, *offset) - IEEE802154_FCS_LEN > 1) &&
(id != IEEE802154_HEADER_IE_EID_TERM1) &&
(id != IEEE802154_HEADER_IE_EID_TERM2));
/* Presense of Payload IEs is determined by how the Header IEs are terminated */
if (id == IEEE802154_HEADER_IE_EID_TERM1) {
packet->payload_ie_present = TRUE;
}
else {
packet->payload_ie_present = FALSE;
}
} /* dissect_ieee802154_header_ie */
/**
* Subdissector command for MAC Layer Management Entitiy (MLME)
* Payload Sub IEs (Information Elements)
*
*@param tvb pointer to buffer containing raw packet.
*@param pinfo pointer to packet information fields (unused).
*@param tree pointer to command subtree.
*@param offset offset into the tvbuff to begin dissection.
*/
static int
dissect_ieee802154_payload_mlme_sub_ie(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset)
{
proto_tree *subtree;
guint16 psie_ie;
guint16 psie_id;
guint psie_remaining = 0;
int orig_offset = offset;
static const int * fields_short[] = {
&hf_ieee802154_psie_type_short,
&hf_ieee802154_psie_id_short,
&hf_ieee802154_psie_length_short,
NULL
};
static const int * fields_long[] = {
&hf_ieee802154_psie_type_long,
&hf_ieee802154_psie_id_long,
&hf_ieee802154_psie_length_long,
NULL
};
static const int * fields_eb_filter[] = {
&hf_ieee802154_psie_eb_filter_pjoin,
&hf_ieee802154_psie_eb_filter_lqi,
&hf_ieee802154_psie_eb_filter_percent,
&hf_ieee802154_psie_eb_filter_attr_id,
/* reserved 5-7 */
NULL
};
psie_ie = tvb_get_letohs(tvb, offset);
if (psie_ie & IEEE802154_PSIE_TYPE_MASK) { /* long format */
psie_id = (guint16) ((psie_ie & IEEE802154_PSIE_ID_MASK_LONG) >> 11);
psie_remaining = (guint) (psie_ie & IEEE802154_PSIE_LENGTH_MASK_LONG);
//proto_tree_add_item(tree, hf_ieee802154_time_correction, tvb, *offset, 2, ENC_NA);
subtree = proto_tree_add_subtree(tree, tvb, offset, 2+psie_remaining, ett_ieee802154_psie_long, NULL, "Nested Sub IE (long)");
proto_tree_add_bitmask(subtree, tvb, offset, hf_ieee802154_psie_long, ett_ieee802154_psie_long_bitmap, fields_long, ENC_LITTLE_ENDIAN);
}
else { /* short format */
psie_id = (guint16) ((psie_ie & IEEE802154_PSIE_ID_MASK_SHORT) >> 8);
psie_remaining = (guint) (psie_ie & IEEE802154_PSIE_LENGTH_MASK_SHORT);
//proto_tree_add_item(tree, hf_ieee802154_time_correction, tvb, *offset, 2, ENC_NA);
subtree = proto_tree_add_subtree(tree, tvb, offset, 2 + psie_remaining, ett_ieee802154_psie_short, NULL, "Nested Sub IE (short)");
proto_tree_add_bitmask(subtree, tvb, offset, hf_ieee802154_psie_short, ett_ieee802154_psie_short_bitmap, fields_short, ENC_LITTLE_ENDIAN);
}
proto_item_append_text(subtree, ", Sub IE: %s, Length: %d", val_to_str_const(psie_id, ieee802154_psie_names, "Unknown IE"), psie_remaining);
offset += 2;
switch (psie_id) {
case IEEE802154_MLME_SUBIE_ENHANCED_BEACON_FILTER:
{
guint8 filter;
guint8 attr_len;
guint32 attr_bitmap = 0;
filter = tvb_get_guint8(tvb, offset);
proto_tree_add_bitmask(subtree, tvb, offset, hf_ieee802154_psie_eb_filter,
ett_ieee802154_psie_enh_beacon_flt_bitmap, fields_eb_filter,
ENC_NA);
offset += 1;
if (filter & IEEE802154_MLME_PSIE_EB_FLT_LQI) {
proto_tree_add_item(subtree, hf_ieee802154_psie_eb_filter_lqi_min, tvb, offset, 1, ENC_NA);
offset += 1;
}
if (filter & IEEE802154_MLME_PSIE_EB_FLT_PERCENT) {
proto_tree_add_item(subtree, hf_ieee802154_psie_eb_filter_percent_prob, tvb, offset, 1, ENC_NA);
offset += 1;
}
attr_len = (guint8) ((filter & IEEE802154_MLME_PSIE_EB_FLT_ATTR_LEN) >> 3);
if (attr_len) {
switch(attr_len) {
case 1:
attr_bitmap = (guint32)tvb_get_guint8(tvb, offset);
break;
case 2:
attr_bitmap = (guint32)tvb_get_ntohs(tvb, offset);
break;
case 3:
attr_bitmap = tvb_get_ntoh24(tvb, offset);
break;
/* default: not reached, attr len is only 2 bits: 0x18 */
}
/* just display in hex until we know how to decode */
proto_tree_add_uint(subtree, hf_ieee802154_psie_eb_filter_attr_id_bitmap, tvb, offset,
attr_len, attr_bitmap);
offset += attr_len;
}
}
break;
case IEEE802154_MLME_SUBIE_TSCH_SYNCH:
dissect_802154_tsch_time_sync(tvb, subtree, &offset);
break;
case IEEE802154_MLME_SUBIE_TSCH_SLOTFR_LINK:
dissect_802154_p_ie_sh_mlme_tsch_slotframe_link(tvb, subtree, psie_remaining, &offset);
break;
case IEEE802154_MLME_SUBIE_TSCH_TIMESLOT:
if (psie_remaining) {
proto_tree_add_item(subtree, hf_ieee802154_mlme_ie_data, tvb, offset, psie_remaining, ENC_NA);
offset += psie_remaining;
}
break;
case IEEE802154_MLME_SUBIE_CHANNEL_HOPPING:
dissect_802154_tsch_channel_hopping(tvb, subtree, psie_remaining, &offset);
break;
case IEEE802154_MLME_SUBIE_HOPPING_TIMING:
case IEEE802154_MLME_SUBIE_MAC_METRICS:
case IEEE802154_MLME_SUBIE_ALL_MAC_METRICS:
case IEEE802154_MLME_SUBIE_COEXISTENCE_SPEC:
case IEEE802154_MLME_SUBIE_SUN_DEVICE_CAPABILITIES:
case IEEE802154_MLME_SUBIE_SUN_FSK_GEN_PHY:
case IEEE802154_MLME_SUBIE_MODE_SWITCH_PARAMETER:
case IEEE802154_MLME_SUBIE_PHY_PARAMETER_CHANGE:
case IEEE802154_MLME_SUBIE_O_QPSK_PHY_MODE:
case IEEE802154_MLME_SUBIE_PCA_ALLOCATION:
case IEEE802154_MLME_SUBIE_DSSS_OPER_MODE:
case IEEE802154_MLME_SUBIE_FSK_OPER_MODE:
case IEEE802154_MLME_SUBIE_TVWS_PHY_OPE_MODE:
case IEEE802154_MLME_SUBIE_TVWS_DEVICE_CAPAB:
case IEEE802154_MLME_SUBIE_TVWS_DEVICE_CATEG:
case IEEE802154_MLME_SUBIE_TVWS_DEVICE_IDENTIF:
case IEEE802154_MLME_SUBIE_TVWS_DEVICE_LOCATION:
case IEEE802154_MLME_SUBIE_TVWS_CH_INFOR_QUERY:
case IEEE802154_MLME_SUBIE_TVWS_CH_INFOR_SOURCE:
case IEEE802154_MLME_SUBIE_CTM:
case IEEE802154_MLME_SUBIE_TIMESTAMP:
case IEEE802154_MLME_SUBIE_TIMESTAMP_DIFF:
case IEEE802154_MLME_SUBIE_TMCP_SPECIFICATION:
case IEEE802154_MLME_SUBIE_RCC_PHY_OPER_MODE:
default:
/* display bytes */
if (psie_remaining) {
proto_tree_add_item(subtree, hf_ieee802154_mlme_ie_data, tvb, offset, psie_remaining, ENC_NA);
offset += psie_remaining;
}
break;
}
return (offset - orig_offset);
}
/**
*Subdissector command for Vendor Specific IEs (Information Elements)
*
*@param tvb pointer to buffer containing the Vendor Specific IE
*@param pinfo pointer to packet information fields (unused).
*@param tree pointer to command subtree.
*@param offset offset into the tvbuff to begin dissection.
*@param pie_length the length of the Vendor Payload IE
*/
static int
dissect_ieee802154_vendor_ie(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset, gint pie_length)
{
tvbuff_t *next_tvb;
guint32 vendor_oui;
vendor_oui = tvb_get_letoh24(tvb, offset);
proto_item_append_text(tree, ", Vendor OUI: %06X (%s)", vendor_oui,
val_to_str_const(vendor_oui, ieee802154_vendor_oui_names, "unknown"));
proto_tree_add_uint_format_value(tree, hf_ieee802154_payload_ie_vendor_oui, tvb, offset, 3,
vendor_oui, "%06X (%s)", vendor_oui, val_to_str_const(vendor_oui, ieee802154_vendor_oui_names, "unknown"));
offset += 3; /* adjust for vendor OUI */
pie_length -= 3;
next_tvb = tvb_new_subset_length(tvb, offset, pie_length);
switch (vendor_oui) {
case IEEE802154_VENDOR_OUI_ZIGBEE:
call_dissector_with_data(zigbee_ie_handle, next_tvb, pinfo, tree, &pie_length);
break;
default:
call_data_dissector(next_tvb, pinfo, tree);
break;
}
return pie_length + 3;
}
/**
*Subdissector command for Payload IEs (Information Elements)
*
*@param tvb pointer to buffer containing raw packet.
*@param pinfo pointer to packet information fields (unused).
*@param tree pointer to command subtree.
*@param offset offset into the tvbuff to begin dissection.
*/
static int
dissect_ieee802154_payload_ie(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset)
{
proto_tree *subtree;
guint16 payload_ie;
guint16 pie_id;
int pie_length;
int orig_offset;
static const int * fields[] = {
&hf_ieee802154_payload_ie_type,
&hf_ieee802154_payload_ie_id,
&hf_ieee802154_payload_ie_length,
NULL
};
orig_offset = offset;
do {
payload_ie = tvb_get_letohs(tvb, offset);
pie_id = (payload_ie & IEEE802154_PAYLOAD_IE_ID_MASK) >> 11;
pie_length = payload_ie & IEEE802154_PAYLOAD_IE_LENGTH_MASK;
/* Create a subtree for this command frame. */
subtree = proto_tree_add_subtree(tree, tvb, offset, pie_length + 2, ett_ieee802154_payload, NULL, "Payload IE");
proto_item_append_text(subtree, ", %s, Length: %d", val_to_str_const(pie_id, ieee802154_payload_ie_names, "Unknown IE"), pie_length);
proto_tree_add_bitmask(subtree, tvb, offset, hf_ieee802154_payload_ie,
ett_ieee802154_payload_ie, fields, ENC_LITTLE_ENDIAN);
offset += 2;
switch (pie_id) {
case IEEE802154_PAYLOAD_IE_MLME:
while (offset < (orig_offset + pie_length)) {
offset += dissect_ieee802154_payload_mlme_sub_ie(tvb, pinfo, subtree, offset);
}
break;
case IEEE802154_PAYLOAD_IE_VENDOR:
offset += dissect_ieee802154_vendor_ie(tvb, pinfo, subtree, offset, pie_length);
break;
case IEEE802154_PAYLOAD_IE_IETF:
offset += dissect_ieee802154_6top(tvb, pinfo, subtree, offset, pie_length);
break;
default: /* just use the data dissector */
if (pie_length > 0) {
proto_tree_add_item(subtree, hf_ieee802154_payload_ie_data, tvb, offset, pie_length, ENC_NA);
offset += pie_length;
}
}
} while ((tvb_reported_length_remaining(tvb, offset) - IEEE802154_FCS_LEN > 1) && (pie_id != IEEE802154_PAYLOAD_IE_GID_TERM));
return (offset - orig_offset);
}
static const true_false_string tfs_cinfo_device_type = { "FFD", "RFD" };
static const true_false_string tfs_cinfo_power_src = { "AC/Mains Power", "Battery" };
/**
*Command subdissector routine for the Association request command.
*
*@param tvb pointer to buffer containing raw packet.
*@param pinfo pointer to packet information fields.
*@param tree pointer to protocol tree.
*@param packet IEEE 802.15.4 packet information.
*/
static void
dissect_ieee802154_assoc_req(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet)
{
guint8 cap;
proto_tree *subtree;
static const int * capability[] = {
&hf_ieee802154_cinfo_alt_coord,
&hf_ieee802154_cinfo_device_type,
&hf_ieee802154_cinfo_power_src,
&hf_ieee802154_cinfo_idle_rx,
&hf_ieee802154_cinfo_sec_capable,
&hf_ieee802154_cinfo_alloc_addr,
NULL
};
cap = tvb_get_guint8(tvb, 0);
col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", (cap & IEEE802154_CMD_CINFO_DEVICE_TYPE) ? tfs_cinfo_device_type.true_string : tfs_cinfo_device_type.false_string);
/* Create a subtree for this command frame. */
subtree = proto_tree_add_subtree(tree, tvb, 0, 1, ett_ieee802154_cmd, NULL,
val_to_str_const(packet->command_id, ieee802154_cmd_names, "Unknown Command"));
/* Get and display capability info. */
proto_tree_add_bitmask_list(subtree, tvb, 0, 1, capability, ENC_NA);
/* Call the data dissector for any leftover bytes. */
if (tvb_reported_length(tvb) > 1) {
call_data_dissector(tvb_new_subset_remaining(tvb, 1), pinfo, tree);
}
} /* dissect_ieee802154_assoc_req */
/**
*Command subdissector routine for the Association response command.
*
*@param tvb pointer to buffer containing raw packet.
*@param pinfo pointer to packet information fields.
*@param tree pointer to protocol tree.
*@param packet IEEE 802.15.4 packet information.
*/
static void
dissect_ieee802154_assoc_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet)
{
proto_tree *subtree;
proto_item *ti;
guint16 short_addr;
guint8 status;
guint offset = 0;
/* Create a subtree for this command frame. */
subtree = proto_tree_add_subtree(tree, tvb, offset, 3, ett_ieee802154_cmd, NULL,
val_to_str_const(packet->command_id, ieee802154_cmd_names, "Unknown Command"));
/* Get and display the short address. */
short_addr = tvb_get_letohs(tvb, offset);
proto_tree_add_uint(subtree, hf_ieee802154_assoc_addr, tvb, offset, 2, short_addr);
offset += 2;
/* Get and display the status. */
status = tvb_get_guint8(tvb, offset);
if (tree) {
ti = proto_tree_add_uint(subtree, hf_ieee802154_assoc_status, tvb, offset, 1, status);
if (status == IEEE802154_CMD_ASRSP_AS_SUCCESS) proto_item_append_text(ti, " (Association Successful)");
else if (status == IEEE802154_CMD_ASRSP_PAN_FULL) proto_item_append_text(ti, " (PAN Full)");
else if (status == IEEE802154_CMD_ASRSP_PAN_DENIED) proto_item_append_text(ti, " (Association Denied)");
else proto_item_append_text(ti, " (Reserved)");
}
offset += 1;
/* Update the info column. */
if (status == IEEE802154_CMD_ASRSP_AS_SUCCESS) {
/* Association was successful. */
if (packet->src_addr_mode != IEEE802154_FCF_ADDR_SHORT) {
col_append_fstr(pinfo->cinfo, COL_INFO, ", PAN: 0x%04x", packet->dst_pan);
}
if (short_addr != IEEE802154_NO_ADDR16) {
col_append_fstr(pinfo->cinfo, COL_INFO, " Addr: 0x%04x", short_addr);
}
}
else {
/* Association was unsuccessful. */
col_append_str(pinfo->cinfo, COL_INFO, ", Unsuccessful");
}
/* Update the address table. */
if ((status == IEEE802154_CMD_ASRSP_AS_SUCCESS) && (short_addr != IEEE802154_NO_ADDR16)) {
ieee802154_addr_update(&ieee802154_map, short_addr, packet->dst_pan, packet->dst64,
pinfo->current_proto, pinfo->num);
}
/* Call the data dissector for any leftover bytes. */
if (tvb_captured_length(tvb) > offset) {
call_data_dissector(tvb_new_subset_remaining(tvb, offset), pinfo, tree);
}
} /* dissect_ieee802154_assoc_rsp */
/**
* Command subdissector routine for the Disassociate command.
*
*@param tvb pointer to buffer containing raw packet.
*@param pinfo pointer to packet information fields.
*@param tree pointer to protocol tree.
*@param packet IEEE 802.15.4 packet information.
*/
static void
dissect_ieee802154_disassoc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet)
{
proto_tree *subtree;
proto_item *ti;
guint8 reason;
/* Create a subtree for this command frame. */
subtree = proto_tree_add_subtree(tree, tvb, 0, 1, ett_ieee802154_cmd, NULL,
val_to_str_const(packet->command_id, ieee802154_cmd_names, "Unknown Command"));
/* Get and display the disassociation reason. */
reason = tvb_get_guint8(tvb, 0);
if (tree) {
ti = proto_tree_add_uint(subtree, hf_ieee802154_disassoc_reason, tvb, 0, 1, reason);
switch(reason) {
case 0x01:
proto_item_append_text(ti, " (Coordinator requests device to leave)");
break;
case 0x02:
proto_item_append_text(ti, " (Device wishes to leave)");
break;
default:
proto_item_append_text(ti, " (Reserved)");
break;
} /* switch */
}
if (!pinfo->fd->flags.visited) {
/* Update the address tables */
if ( packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT ) {
ieee802154_long_addr_invalidate(packet->dst64, pinfo->num);
} else if ( packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT ) {
ieee802154_short_addr_invalidate(packet->dst16, packet->dst_pan, pinfo->num);
}
}
/* Call the data dissector for any leftover bytes. */
if (tvb_captured_length(tvb) > 1) {
call_data_dissector(tvb_new_subset_remaining(tvb, 1), pinfo, tree);
}
} /* dissect_ieee802154_disassoc */
/**
* Command subdissector routine for the Coordinator Realignment command.
*
*@param tvb pointer to buffer containing raw packet.
*@param pinfo pointer to packet information fields.
*@param tree pointer to protocol tree.
*@param packet IEEE 802.15.4 packet information.
*/
static void
dissect_ieee802154_realign(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet)
{
proto_tree *subtree;
proto_item *subitem;
guint16 pan_id;
guint16 coord_addr;
guint8 channel;
guint16 short_addr;
guint offset = 0;
/* Create a subtree for this command frame. */
subtree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_ieee802154_cmd, &subitem,
val_to_str_const(packet->command_id, ieee802154_cmd_names, "Unknown Command"));
/* Get and display the command PAN ID. */
pan_id = tvb_get_letohs(tvb, offset);
proto_tree_add_uint(subtree, hf_ieee802154_realign_pan, tvb, offset, 2, pan_id);
col_append_fstr(pinfo->cinfo, COL_INFO, ", PAN: 0x%04x", pan_id);
offset += 2;
/* Get and display the coordinator address. */
coord_addr = tvb_get_letohs(tvb, offset);
proto_tree_add_uint(subtree, hf_ieee802154_realign_caddr, tvb, offset, 2, coord_addr);
col_append_fstr(pinfo->cinfo, COL_INFO, ", Coordinator: 0x%04x", coord_addr);
offset += 2;
/* Get and display the channel. */
channel = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(subtree, hf_ieee802154_realign_channel, tvb, offset, 1, channel);
col_append_fstr(pinfo->cinfo, COL_INFO, ", Channel: %u", channel);
offset += 1;
/* Get and display the short address. */
short_addr = tvb_get_letohs(tvb, offset);
if (tree) proto_tree_add_uint(subtree, hf_ieee802154_realign_addr, tvb, offset, 2, short_addr);
if ((packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT)
&& (short_addr != IEEE802154_NO_ADDR16)) {
col_append_fstr(pinfo->cinfo, COL_INFO, ", Addr: 0x%04x", short_addr);
}
offset += 2;
/* Update the address table. */
if ((short_addr != IEEE802154_NO_ADDR16) && (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT)) {
ieee802154_addr_update(&ieee802154_map, short_addr, packet->dst_pan, packet->dst64,
pinfo->current_proto, pinfo->num);
}
/* Get and display the channel page, if it exists. Added in IEEE802.15.4-2006 */
if (tvb_bytes_exist(tvb, offset, 1)) {
guint8 channel_page = tvb_get_guint8(tvb, offset);
if (tree) proto_tree_add_uint(subtree, hf_ieee802154_realign_channel_page, tvb, offset, 1, channel_page);
offset += 1;
}
/* Fix the length of the command subtree. */
if (tree) {
proto_item_set_len(subitem, offset);
}
/* Call the data dissector for any leftover bytes. */
if (tvb_captured_length(tvb) > offset) {
call_data_dissector(tvb_new_subset_remaining(tvb, offset), pinfo, tree);
}
} /* dissect_ieee802154_realign */
static const true_false_string tfs_gtsreq_dir = { "Receive", "Transmit" };
static const true_false_string tfs_gtsreq_type= { "Allocate GTS", "Deallocate GTS" };
/**
*Command subdissector routine for the GTS request command.
*
*Assumes that COL_INFO will be set to the command name,
*command name will already be appended to the command subtree
*and protocol root. In addition, assumes that the command ID
*has already been parsed.
*
*@param tvb pointer to buffer containing raw packet.
*@param pinfo pointer to packet information fields (unused).
*@param tree pointer to protocol tree.
*@param packet IEEE 802.15.4 packet information (unused).
*/
static void
dissect_ieee802154_gtsreq(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet)
{
proto_tree *subtree;
static const int * characteristics[] = {
&hf_ieee802154_gtsreq_len,
&hf_ieee802154_gtsreq_dir,
&hf_ieee802154_gtsreq_type,
NULL
};
/* Create a subtree for this command frame. */
subtree = proto_tree_add_subtree(tree, tvb, 0, 1, ett_ieee802154_cmd, NULL,
val_to_str_const(packet->command_id, ieee802154_cmd_names, "Unknown Command"));
proto_tree_add_bitmask_list(subtree, tvb, 0, 1, characteristics, ENC_NA);
/* Call the data dissector for any leftover bytes. */
if (tvb_reported_length(tvb) > 1) {
call_data_dissector(tvb_new_subset_remaining(tvb, 1), pinfo, tree);
}
} /* dissect_ieee802154_gtsreq */
/**
* Subdissector routine all commands.
*
*@param tvb pointer to buffer containing raw packet.
*@param pinfo pointer to packet information fields (unused).
*@param tree pointer to protocol tree.
*@param packet IEEE 802.15.4 packet information (unused).
*/
static void
dissect_ieee802154_command(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet)
{
switch (packet->command_id) {
case IEEE802154_CMD_ASSOC_REQ:
IEEE802154_CMD_ADDR_CHECK(pinfo, tree, packet->command_id,
(packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) &&
(packet->dst_addr_mode != IEEE802154_FCF_ADDR_NONE));
dissect_ieee802154_assoc_req(tvb, pinfo, tree, packet);
break;
case IEEE802154_CMD_ASSOC_RSP:
IEEE802154_CMD_ADDR_CHECK(pinfo, tree, packet->command_id,
(packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) &&
(packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT));
dissect_ieee802154_assoc_rsp(tvb, pinfo, tree, packet);
break;
case IEEE802154_CMD_DISASSOC_NOTIFY:
IEEE802154_CMD_ADDR_CHECK(pinfo, tree, packet->command_id,
(packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) &&
(packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT));
dissect_ieee802154_disassoc(tvb, pinfo, tree, packet);
return;
case IEEE802154_CMD_DATA_RQ:
IEEE802154_CMD_ADDR_CHECK(pinfo, tree, packet->command_id, packet->src_addr_mode != IEEE802154_FCF_ADDR_NONE);
/* No payload expected. */
break;
case IEEE802154_CMD_PANID_CONFLICT:
IEEE802154_CMD_ADDR_CHECK(pinfo, tree, packet->command_id,
(packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) &&
(packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT));
/* No payload expected. */
break;
case IEEE802154_CMD_ORPHAN_NOTIFY:
IEEE802154_CMD_ADDR_CHECK(pinfo, tree, packet->command_id,
(packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) &&
(packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) &&
(packet->dst16 == IEEE802154_BCAST_ADDR) &&
(packet->src_pan == IEEE802154_BCAST_PAN) &&
(packet->dst_pan == IEEE802154_BCAST_PAN));
/* No payload expected. */
break;
case IEEE802154_CMD_BEACON_REQ:
if ((packet->version == IEEE802154_VERSION_2003) || (packet->version == IEEE802154_VERSION_2006)) {
IEEE802154_CMD_ADDR_CHECK(pinfo, tree, packet->command_id,
(packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) &&
(packet->src_addr_mode == IEEE802154_FCF_ADDR_NONE) &&
(packet->dst16 == IEEE802154_BCAST_ADDR) &&
(packet->dst_pan == IEEE802154_BCAST_PAN));
}
/* No payload expected. */
break;
case IEEE802154_CMD_COORD_REALIGN:
IEEE802154_CMD_ADDR_CHECK(pinfo, tree, packet->command_id,
(packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) &&
(packet->dst_pan == IEEE802154_BCAST_PAN) &&
(packet->dst_addr_mode != IEEE802154_FCF_ADDR_NONE));
if (packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) {
/* If directed to a 16-bit address, check that it is being broadcast. */
IEEE802154_CMD_ADDR_CHECK(pinfo, tree, packet->command_id, packet->dst16 == IEEE802154_BCAST_ADDR);
}
dissect_ieee802154_realign(tvb, pinfo, tree, packet);
return;
case IEEE802154_CMD_GTS_REQ:
/* Check that the addressing is correct for this command type. */
IEEE802154_CMD_ADDR_CHECK(pinfo, tree, packet->command_id,
(packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT) &&
(packet->dst_addr_mode == IEEE802154_FCF_ADDR_NONE) &&
(packet->src16 != IEEE802154_BCAST_ADDR) &&
(packet->src16 != IEEE802154_NO_ADDR16));
dissect_ieee802154_gtsreq(tvb, pinfo, tree, packet);
return;
case IEEE802154_CMD_TRLE_MGMT_REQ:
case IEEE802154_CMD_TRLE_MGMT_RSP:
case IEEE802154_CMD_DSME_ASSOC_REQ:
case IEEE802154_CMD_DSME_ASSOC_RSP:
case IEEE802154_CMD_DSME_GTS_REQ:
case IEEE802154_CMD_DSME_GTS_RSP:
case IEEE802154_CMD_DSME_GTS_NOTIFY:
case IEEE802154_CMD_DSME_INFO_REQ:
case IEEE802154_CMD_DSME_INFO_RSP:
case IEEE802154_CMD_DSME_BEACON_ALLOC_NOTIFY:
case IEEE802154_CMD_DSME_BEACON_COLL_NOTIFY:
case IEEE802154_CMD_DSME_LINK_REPORT:
case IEEE802154_CMD_RIT_DATA_REQ:
case IEEE802154_CMD_DBS_REQ:
case IEEE802154_CMD_DBS_RSP:
/* TODO add support for these commands, for now
* if anything remains other than the FCS, dump it */
if (tvb_captured_length_remaining(tvb, 0) > 2) {
call_data_dissector(tvb, pinfo, tree);
}
return;
} /* switch */
} /* dissect_ieee802154_command */
/**
*IEEE 802.15.4 decryption algorithm. Tries to find the
*appropriate key from the information in the IEEE 802.15.4
*packet structure and dissector config.
*
*This function implements the security proceedures for the
*2006 version of the spec only. IEEE 802.15.4-2003 is
*unsupported.
*@param tvb IEEE 802.15.4 packet.
*@param pinfo Packet info structure.
*@param offset Offset where the ciphertext 'c' starts.
*@param packet IEEE 802.15.4 packet information.
*@return decrypted payload.
*/
static tvbuff_t *
dissect_ieee802154_decrypt(tvbuff_t *tvb,
guint offset,
packet_info *pinfo,
ieee802154_packet *packet,
ieee802154_payload_info_t* payload_info)
{
tvbuff_t *ptext_tvb;
gboolean have_mic = FALSE;
guint64 srcAddr;
unsigned char tmp[IEEE802154_CIPHER_SIZE];
guint M;
gint captured_len;
gint reported_len;
ieee802154_hints_t *ieee_hints;
/*
* Check the version; we only support IEEE 802.15.4-2003 and IEEE 802.15.4-2006.
* We must do this first, as, if this isn't IEEE 802.15.4-2003 or IEEE 802.15.4-2006,
* we don't have the Auxiliary Security Header, and haven't
* filled in the information for it, and none of the stuff
* we do afterwards, which uses that information, is doable.
*/
if ((packet->version != IEEE802154_VERSION_2006) && (packet->version != IEEE802154_VERSION_2003)) {
*payload_info->status = DECRYPT_VERSION_UNSUPPORTED;
return NULL;
}
ieee_hints = (ieee802154_hints_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_ieee802154, 0);
/* Get the captured and on-the-wire length of the payload. */
M = IEEE802154_MIC_LENGTH(packet->security_level);
*payload_info->rx_mic_length = M;
reported_len = tvb_reported_length_remaining(tvb, offset) - IEEE802154_FCS_LEN - M;
if (reported_len < 0) {
*payload_info->status = DECRYPT_PACKET_TOO_SMALL;
return NULL;
}
/* Check of the payload is truncated. */
if (tvb_bytes_exist(tvb, offset, reported_len)) {
captured_len = reported_len;
}
else {
captured_len = tvb_captured_length_remaining(tvb, offset);
}
/* Check if the MIC is present in the captured data. */
have_mic = tvb_bytes_exist(tvb, offset + reported_len, M);
if (have_mic) {
tvb_memcpy(tvb, payload_info->rx_mic, offset + reported_len, M);
}
/*
* Key Lookup - Need to find the appropriate key.
*
*/
if ((packet->key_index == IEEE802154_THR_WELL_KNOWN_KEY_INDEX) &&
(packet->key_source.addr32 == IEEE802154_THR_WELL_KNOWN_KEY_SRC))
{
/* Use the well-known extended address */
srcAddr = IEEE802154_THR_WELL_KNOWN_EXT_ADDR;
} else {
if (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) {
/* The source EUI-64 is included in the headers. */
srcAddr = packet->src64;
}
else if (ieee_hints && ieee_hints->map_rec && ieee_hints->map_rec->addr64) {
/* Use the hint */
srcAddr = ieee_hints->map_rec->addr64;
}
else {
/* Lookup failed. */
*payload_info->status = DECRYPT_PACKET_NO_EXT_SRC_ADDR;
return NULL;
}
}
/*
* CCM* - CTR mode payload encryption
*
*/
/* Create the CCM* initial block for decryption (Adata=0, M=0, counter=0). */
if (packet->version == IEEE802154_VERSION_2003)
ccm_init_block(tmp, FALSE, 0, srcAddr, packet->frame_counter, packet->key_sequence_counter, 0);
else
ccm_init_block(tmp, FALSE, 0, srcAddr, packet->frame_counter, packet->security_level, 0);
/* Decrypt the ciphertext, and place the plaintext in a new tvb. */
if (IEEE802154_IS_ENCRYPTED(packet->security_level) && captured_len) {
guint8 *text;
/*
* Make a copy of the ciphertext in heap memory.
*
* We will decrypt the message in-place and then use the buffer as the
* real data for the new tvb.
*/
text = (guint8 *)tvb_memdup(pinfo->pool, tvb, offset, captured_len);
/* Perform CTR-mode transformation. */
if (!ccm_ctr_encrypt(payload_info->key, tmp, payload_info->rx_mic, text, captured_len)) {
g_free(text);
*payload_info->status = DECRYPT_PACKET_DECRYPT_FAILED;
return NULL;
}
/* Create a tvbuff for the plaintext. */
ptext_tvb = tvb_new_child_real_data(tvb, text, captured_len, reported_len);
add_new_data_source(pinfo, ptext_tvb, "Decrypted IEEE 802.15.4 payload");
*payload_info->status = DECRYPT_PACKET_SUCCEEDED;
}
/* There is no ciphertext. Wrap the plaintext in a new tvb. */
else {
/* Decrypt the MIC (if present). */
if ((have_mic) && (!ccm_ctr_encrypt(payload_info->key, tmp, payload_info->rx_mic, NULL, 0))) {
*payload_info->status = DECRYPT_PACKET_DECRYPT_FAILED;
return NULL;
}
/* Create a tvbuff for the plaintext. This might result in a zero-length tvbuff. */
ptext_tvb = tvb_new_subset_length_caplen(tvb, offset, captured_len, reported_len);
*payload_info->status = DECRYPT_PACKET_SUCCEEDED;
}
/*
* CCM* - CBC-mode message authentication
*
*/
/* We can only verify the message if the MIC wasn't truncated. */
if (have_mic) {
unsigned char dec_mic[16];
guint l_m = captured_len;
guint l_a = offset;
/* Adjust the lengths of the plaintext and additional data if unencrypted. */
if (!IEEE802154_IS_ENCRYPTED(packet->security_level)) {
l_a += l_m;
l_m = 0;
}
else if ((packet->version == IEEE802154_VERSION_2003) && !ieee802154_extend_auth)
l_a -= 5; /* Exclude Frame Counter (4 bytes) and Key Sequence Counter (1 byte) from authentication data */
/* Create the CCM* initial block for authentication (Adata!=0, M!=0, counter=l(m)). */
if (packet->version == IEEE802154_VERSION_2003)
ccm_init_block(tmp, TRUE, M, srcAddr, packet->frame_counter, packet->key_sequence_counter, l_m);
else
ccm_init_block(tmp, TRUE, M, srcAddr, packet->frame_counter, packet->security_level, l_m);
/* Compute CBC-MAC authentication tag. */
/*
* And yes, despite the warning in tvbuff.h, I think tvb_get_ptr is the
* right function here since either A) the payload wasn't encrypted, in
* which case l_m is zero, or B) the payload was encrypted, and the tvb
* already points to contiguous memory, since we just allocated it in
* decryption phase.
*/
if (!ccm_cbc_mac(payload_info->key, tmp, (const gchar *)tvb_memdup(wmem_packet_scope(), tvb, 0, l_a), l_a, tvb_get_ptr(ptext_tvb, 0, l_m), l_m, dec_mic)) {
*payload_info->status = DECRYPT_PACKET_MIC_CHECK_FAILED;
}
/* Compare the received MIC with the one we generated. */
else if (memcmp(payload_info->rx_mic, dec_mic, M) != 0) {
*payload_info->status = DECRYPT_PACKET_MIC_CHECK_FAILED;
}
}
/* Done! */
return ptext_tvb;
} /* dissect_ieee802154_decrypt */
/**
*Creates the CCM* initial block value for IEEE 802.15.4.
*
*@param block Output pointer for the initial block.
*@param adata TRUE if additional auth data is present
*@param M CCM* parameter M.
*@param addr Source extended address.
*@param frame_counter Packet frame counter
*@param level Security level or key_sequence_counter for 802.15.4-2003
*@param ctr_val Value in the last L bytes of the block.
*/
void
ccm_init_block(gchar *block, gboolean adata, gint M, guint64 addr, guint32 frame_counter, guint8 level, gint ctr_val)
{
gint i = 0;
/* Flags: Reserved(0) || Adata || (M-2)/2 || (L-1) */
block[i] = (0x2 - 1); /* (L-1) */
if (M > 0) block[i] |= (((M-2)/2) << 3); /* (M-2)/2 */
if (adata) block[i] |= (1 << 6); /* Adata */
i++;
/* 2003 CCM Nonce: Source Address || Frame Counter || Key Sequence Counter */
/* 2006 CCM* Nonce: Source Address || Frame Counter || Security Level */
block[i++] = (guint8)((addr >> 56) & 0xff);
block[i++] = (guint8)((addr >> 48) & 0xff);
block[i++] = (guint8)((addr >> 40) & 0xff);
block[i++] = (guint8)((addr >> 32) & 0xff);
block[i++] = (guint8)((addr >> 24) & 0xff);
block[i++] = (guint8)((addr >> 16) & 0xff);
block[i++] = (guint8)((addr >> 8) & 0xff);
block[i++] = (guint8)((addr >> 0) & 0xff);
block[i++] = (guint8)((frame_counter >> 24) & 0xff);
block[i++] = (guint8)((frame_counter >> 16) & 0xff);
block[i++] = (guint8)((frame_counter >> 8) & 0xff);
block[i++] = (guint8)((frame_counter >> 0) & 0xff);
block[i++] = level;
/* Plaintext length. */
block[i++] = (guint8)((ctr_val >> 8) & 0xff);
block[i] = (guint8)((ctr_val >> 0) & 0xff);
} /* ccm_init_block */
/*
* Perform an in-place CTR-mode encryption/decryption.
*
*@param key Encryption Key.
*@param iv Counter initial value.
*@param mic MIC to encrypt/decrypt.
*@param data Buffer to encrypt/decrypt.
*@param length Length of the buffer.
*@return TRUE on SUCCESS, FALSE on error.
*/
gboolean
ccm_ctr_encrypt(const gchar *key, const gchar *iv, gchar *mic, gchar *data, gint length)
{
gcry_cipher_hd_t cipher_hd;
/* Open the cipher. */
if (gcry_cipher_open(&cipher_hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR, 0)) {
return FALSE;
}
/* Set the key and initial value. */
if (gcry_cipher_setkey(cipher_hd, key, 16)) {
gcry_cipher_close(cipher_hd);
return FALSE;
}
if (gcry_cipher_setctr(cipher_hd, iv, 16)) {
gcry_cipher_close(cipher_hd);
return FALSE;
}
/* Decrypt the MIC. */
if (gcry_cipher_encrypt(cipher_hd, mic, 16, NULL, 0)) {
gcry_cipher_close(cipher_hd);
return FALSE;
}
/* Decrypt the payload. */
if (gcry_cipher_encrypt(cipher_hd, data, length, NULL, 0)) {
gcry_cipher_close(cipher_hd);
return FALSE;
}
/* Done with the cipher. */
gcry_cipher_close(cipher_hd);
return TRUE;
} /* ccm_ctr_encrypt */
/**
*Generate a CBC-MAC of the decrypted payload and additional authentication headers.
*@param key Encryption Key.
*@param iv Counter initial value.
*@param a Additional auth headers.
*@param a_len Length of the additional headers.
*@param m Plaintext message.
*@param m_len Length of plaintext message.
*@param mic Output for CBC-MAC.
*@return TRUE on SUCCESS, FALSE on error.
*/
gboolean
ccm_cbc_mac(const gchar *key, const gchar *iv, const gchar *a, gint a_len, const gchar *m, gint m_len, gchar *mic)
{
gcry_cipher_hd_t cipher_hd;
guint i = 0;
unsigned char block[IEEE802154_CIPHER_SIZE];
/* Open the cipher. */
if (gcry_cipher_open(&cipher_hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_CBC_MAC)) return FALSE;
/* Set the key. */
if (gcry_cipher_setkey(cipher_hd, key, IEEE802154_CIPHER_SIZE)) {
gcry_cipher_close(cipher_hd);
return FALSE;
}
/* Process the initial value. */
if (gcry_cipher_encrypt(cipher_hd, mic, 16, iv, 16)) {
gcry_cipher_close(cipher_hd);
return FALSE;
}
/* Encode L(a) */
i = 0;
/* XXX: GINT_MAX is not defined so #if ... will always be false */
#if (GINT_MAX >= (1LL << 32))
if (a_len >= (1LL << 32)) {
block[i++] = 0xff;
block[i++] = 0xff;
block[i++] = (a_len >> 56) & 0xff;
block[i++] = (a_len >> 48) & 0xff;
block[i++] = (a_len >> 40) & 0xff;
block[i++] = (a_len >> 32) & 0xff;
block[i++] = (a_len >> 24) & 0xff;
block[i++] = (a_len >> 16) & 0xff;
block[i++] = (a_len >> 8) & 0xff;
block[i++] = (a_len >> 0) & 0xff;
}
else
#endif
if (a_len >= ((1 << 16) - (1 << 8))) {
block[i++] = 0xff;
block[i++] = 0xfe;
block[i++] = (a_len >> 24) & 0xff;
block[i++] = (a_len >> 16) & 0xff;
block[i++] = (a_len >> 8) & 0xff;
block[i++] = (a_len >> 0) & 0xff;
}
else {
block[i++] = (a_len >> 8) & 0xff;
block[i++] = (a_len >> 0) & 0xff;
}
/* Append a to get the first block of input (pad if we encounter the end of a). */
while ((i < sizeof(block)) && (a_len-- > 0)) block[i++] = *a++;
while (i < sizeof(block)) block[i++] = 0;
/* Process the first block of AuthData. */
if (gcry_cipher_encrypt(cipher_hd, mic, 16, block, 16)) {
gcry_cipher_close(cipher_hd);
return FALSE;
}
/* Transform and process the remainder of a. */
while (a_len > 0) {
/* Copy and pad. */
if ((guint)a_len >= sizeof(block)) memcpy(block, a, sizeof(block));
else {memcpy(block, a, a_len); memset(block+a_len, 0, sizeof(block)-a_len);}
/* Adjust pointers. */
a += sizeof(block);
a_len -= (int)sizeof(block);
/* Execute the CBC-MAC algorithm. */
if (gcry_cipher_encrypt(cipher_hd, mic, 16, block, sizeof(block))) {
gcry_cipher_close(cipher_hd);
return FALSE;
}
} /* while */
/* Process the message, m. */
while (m_len > 0) {
/* Copy and pad. */
if ((guint)m_len >= sizeof(block)) memcpy(block, m, sizeof(block));
else {memcpy(block, m, m_len); memset(block+m_len, 0, sizeof(block)-m_len);}
/* Adjust pointers. */
m += sizeof(block);
m_len -= (int)sizeof(block);
/* Execute the CBC-MAC algorithm. */
if (gcry_cipher_encrypt(cipher_hd, mic, 16, block, sizeof(block))) {
gcry_cipher_close(cipher_hd);
return FALSE;
}
}
/* Done with the cipher. */
gcry_cipher_close(cipher_hd);
return TRUE;
} /* ccm_cbc_mac */
/* Key hash function. */
guint ieee802154_short_addr_hash(gconstpointer key)
{
return (((const ieee802154_short_addr *)key)->addr) | (((const ieee802154_short_addr *)key)->pan << 16);
}
/* Key equal function. */
gboolean ieee802154_short_addr_equal(gconstpointer a, gconstpointer b)
{
return (((const ieee802154_short_addr *)a)->pan == ((const ieee802154_short_addr *)b)->pan) &&
(((const ieee802154_short_addr *)a)->addr == ((const ieee802154_short_addr *)b)->addr);
}
/* Key hash function. */
guint ieee802154_long_addr_hash(gconstpointer key)
{
return (guint)(((const ieee802154_long_addr *)key)->addr) & 0xFFFFFFFF;
}
/* Key equal function. */
gboolean ieee802154_long_addr_equal(gconstpointer a, gconstpointer b)
{
return (((const ieee802154_long_addr *)a)->addr == ((const ieee802154_long_addr *)b)->addr);
}
/* Set MAC key function. */
static gboolean ieee802154_set_mac_key(ieee802154_packet *packet, unsigned char *key, unsigned char *alt_key, ieee802154_key_t* uat_key)
{
ieee802154_set_mac_key_func func = (ieee802154_set_mac_key_func)wmem_tree_lookup32(mac_key_hash_handlers, uat_key->hash_type);
if (func != NULL)
return func(packet, key, alt_key, uat_key);
/* Right now, KEY_HASH_NONE and KEY_HASH_ZIP are not registered because they
work with this "default" behavior */
if (packet->key_index == uat_key->key_index)
{
memcpy(key, uat_key->key, IEEE802154_CIPHER_SIZE);
return TRUE;
}
return FALSE;
}
/**
*Creates a record that maps the given short address and pan to a long (extended) address.
*@param short_addr 16-bit short address
*@param pan 16-bit PAN id
*@param long_addr 64-bit long (extended) address
*@param proto pointer to name of current protocol
*@param fnum Frame number this mapping became valid
*@return TRUE Record was updated, FALSE Couldn't find it
*/
ieee802154_map_rec *ieee802154_addr_update(ieee802154_map_tab_t *au_ieee802154_map,
guint16 short_addr, guint16 pan, guint64 long_addr, const char *proto, guint fnum)
{
ieee802154_short_addr addr16;
ieee802154_map_rec *p_map_rec;
gpointer old_key;
/* Look up short address hash */
addr16.pan = pan;
addr16.addr = short_addr;
p_map_rec = (ieee802154_map_rec *)g_hash_table_lookup(au_ieee802154_map->short_table, &addr16);
/* Update mapping record */
if (p_map_rec) {
/* record already exists */
if ( p_map_rec->addr64 == long_addr ) {
/* no change */
return p_map_rec;
}
else {
/* mark current mapping record invalid */
p_map_rec->end_fnum = fnum;
}
}
/* create a new mapping record */
p_map_rec = wmem_new(wmem_file_scope(), ieee802154_map_rec);
p_map_rec->proto = proto;
p_map_rec->start_fnum = fnum;
p_map_rec->end_fnum = 0;
p_map_rec->addr64 = long_addr;
/* link new mapping record to addr hash tables */
if ( g_hash_table_lookup_extended(au_ieee802154_map->short_table, &addr16, &old_key, NULL) ) {
/* update short addr hash table, reusing pointer to old key */
g_hash_table_insert(au_ieee802154_map->short_table, old_key, p_map_rec);
} else {
/* create new hash entry */
g_hash_table_insert(au_ieee802154_map->short_table, wmem_memdup(wmem_file_scope(), &addr16, sizeof(addr16)), p_map_rec);
}
if ( g_hash_table_lookup_extended(au_ieee802154_map->long_table, &long_addr, &old_key, NULL) ) {
/* update long addr hash table, reusing pointer to old key */
g_hash_table_insert(au_ieee802154_map->long_table, old_key, p_map_rec);
} else {
/* create new hash entry */
g_hash_table_insert(au_ieee802154_map->long_table, wmem_memdup(wmem_file_scope(), &long_addr, sizeof(long_addr)), p_map_rec);
}
return p_map_rec;
} /* ieee802154_addr_update */
/**
*Marks a mapping record associated with device with short_addr
*as invalid at a certain frame number, typically when a
*disassociation occurs.
*
*@param short_addr 16-bit short address
*@param pan 16-bit PAN id
*@param fnum Frame number when mapping became invalid
*@return TRUE Record was updated, FALSE Couldn't find it
*/
gboolean ieee802154_short_addr_invalidate(guint16 short_addr, guint16 pan, guint fnum)
{
ieee802154_short_addr addr16;
ieee802154_map_rec *map_rec;
addr16.pan = pan;
addr16.addr = short_addr;
map_rec = (ieee802154_map_rec *)g_hash_table_lookup(ieee802154_map.short_table, &addr16);
if ( map_rec ) {
/* indicates this mapping is invalid at frame fnum */
map_rec->end_fnum = fnum;
return TRUE;
}
return FALSE;
} /* ieee802154_short_addr_invalidate */
/**
* Mark a mapping record associated with device with long_addr
* as invalid at a certain frame number, typically when a
* disassociation occurs.
*
*@param long_addr 16-bit short address
*@param fnum Frame number when mapping became invalid
*@return TRUE If record was updated, FALSE otherwise
*/
gboolean ieee802154_long_addr_invalidate(guint64 long_addr, guint fnum)
{
ieee802154_map_rec *map_rec;
map_rec = (ieee802154_map_rec *)g_hash_table_lookup(ieee802154_map.long_table, &long_addr);
if ( map_rec ) {
/* indicates this mapping is invalid at frame fnum */
map_rec->end_fnum = fnum;
return TRUE;
}
return FALSE;
} /* ieee802154_long_addr_invalidate */
/**
* Init routine for the IEEE 802.15.4 dissector. Creates hash
* tables for mapping between 16-bit to 64-bit addresses and
* populates them with static address pairs from a UAT
* preference table.
*/
static void
proto_init_ieee802154(void)
{
guint i;
ieee802154_map.short_table = g_hash_table_new(ieee802154_short_addr_hash, ieee802154_short_addr_equal);
ieee802154_map.long_table = g_hash_table_new(ieee802154_long_addr_hash, ieee802154_long_addr_equal);
/* Reload the hash table from the static address UAT. */
for (i=0; (i<num_static_addrs) && (static_addrs); i++) {
ieee802154_addr_update(&ieee802154_map,(guint16)static_addrs[i].addr16, (guint16)static_addrs[i].pan,
pntoh64(static_addrs[i].eui64), ieee802154_user, IEEE802154_USER_MAPPING);
} /* for */
} /* proto_init_ieee802154 */
/**
* Cleanup for the IEEE 802.15.4 dissector.
*/
static void
proto_cleanup_ieee802154(void)
{
g_hash_table_destroy(ieee802154_map.short_table);
g_hash_table_destroy(ieee802154_map.long_table);
}
/* Returns the prompt string for the Decode-As dialog. */
static void ieee802154_da_prompt(packet_info *pinfo _U_, gchar* result)
{
ieee802154_hints_t *hints;
hints = (ieee802154_hints_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_ieee802154, 0);
if (hints)
g_snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "IEEE 802.15.4 PAN 0x%04x as", hints->src_pan);
else
g_snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "IEEE 802.15.4 PAN Unknown");
} /* iee802154_da_prompt */
/* Returns the value to index the panid decode table with (source PAN)*/
static gpointer ieee802154_da_value(packet_info *pinfo _U_)
{
ieee802154_hints_t *hints;
hints = (ieee802154_hints_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_ieee802154, 0);
if (hints)
return GUINT_TO_POINTER((guint)(hints->src_pan));
else
return NULL;
} /* iee802154_da_value */
/**
* IEEE 802.15.4 protocol registration routine.
*/
void proto_register_ieee802154(void)
{
/* Protocol fields */
static hf_register_info hf_phy[] = {
/* PHY level */
{ &hf_ieee802154_nonask_phy_preamble,
{ "Preamble", "wpan-nonask-phy.preamble", FT_UINT32, BASE_HEX, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_nonask_phy_sfd,
{ "Start of Frame Delimiter", "wpan-nonask-phy.sfd", FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_nonask_phy_length,
{ "Frame Length", "wpan-nonask-phy.frame_length", FT_UINT8, BASE_HEX, NULL,
IEEE802154_PHY_LENGTH_MASK, NULL, HFILL }},
{ &hf_ieee802154_nonask_phr,
{ "PHR", "wpan-nonask-phy.phr", FT_UINT8, BASE_HEX, NULL,
0x0, NULL, HFILL }},
};
static hf_register_info hf[] = {
{ &hf_ieee802154_frame_length,
{ "Frame Length", "wpan.frame_length", FT_UINT8, BASE_DEC, NULL, 0x0,
"Frame Length as reported from lower layer", HFILL }},
{ &hf_ieee802154_fcf,
{ "Frame Control Field", "wpan.fcf", FT_UINT16, BASE_HEX, NULL,
0x0, NULL, HFILL }},
{ &hf_ieee802154_frame_type,
{ "Frame Type", "wpan.frame_type", FT_UINT16, BASE_HEX, VALS(ieee802154_frame_types),
IEEE802154_FCF_TYPE_MASK, NULL, HFILL }},
{ &hf_ieee802154_security,
{ "Security Enabled", "wpan.security", FT_BOOLEAN, 16, NULL, IEEE802154_FCF_SEC_EN,
"Whether security operations are performed at the MAC layer or not.", HFILL }},
{ &hf_ieee802154_pending,
{ "Frame Pending", "wpan.pending", FT_BOOLEAN, 16, NULL, IEEE802154_FCF_FRAME_PND,
"Indication of additional packets waiting to be transferred from the source device.", HFILL }},
{ &hf_ieee802154_ack_request,
{ "Acknowledge Request", "wpan.ack_request", FT_BOOLEAN, 16, NULL, IEEE802154_FCF_ACK_REQ,
"Whether the sender of this packet requests acknowledgment or not.", HFILL }},
{ &hf_ieee802154_pan_id_compression,
{ "PAN ID Compression", "wpan.pan_id_compression", FT_BOOLEAN, 16, NULL, IEEE802154_FCF_PAN_ID_COMPRESSION,
"Whether this packet contains the PAN ID or not.", HFILL }},
{ &hf_ieee802154_seqno_suppression,
{ "Sequence Number Suppression", "wpan.seqno_suppression", FT_BOOLEAN, 16, NULL, IEEE802154_FCF_SEQNO_SUPPRESSION,
"Whether this packet contains the Sequence Number or not.", HFILL }},
{ &hf_ieee802154_ie_present,
{ "Information Elements Present", "wpan.ie_present", FT_BOOLEAN, 16, NULL, IEEE802154_FCF_IE_PRESENT,
"Whether this packet contains the Information Elements or not.", HFILL }},
{ &hf_ieee802154_seqno,
{ "Sequence Number", "wpan.seq_no", FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_dst_addr_mode,
{ "Destination Addressing Mode", "wpan.dst_addr_mode", FT_UINT16, BASE_HEX, VALS(ieee802154_addr_modes),
IEEE802154_FCF_DADDR_MASK, NULL, HFILL }},
{ &hf_ieee802154_src_addr_mode,
{ "Source Addressing Mode", "wpan.src_addr_mode", FT_UINT16, BASE_HEX, VALS(ieee802154_addr_modes),
IEEE802154_FCF_SADDR_MASK, NULL, HFILL }},
{ &hf_ieee802154_version,
{ "Frame Version", "wpan.version", FT_UINT16, BASE_DEC, VALS(ieee802154_frame_versions),
IEEE802154_FCF_VERSION, NULL, HFILL }},
{ &hf_ieee802154_dst_panID,
{ "Destination PAN", "wpan.dst_pan", FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_dst16,
{ "Destination", "wpan.dst16", FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_dst64,
{ "Destination", "wpan.dst64", FT_EUI64, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_src_panID,
{ "Source PAN", "wpan.src_pan", FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_src16,
{ "Source", "wpan.src16", FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_src64,
{ "Extended Source", "wpan.src64", FT_EUI64, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_src64_origin,
{ "Origin", "wpan.src64.origin", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_fcs,
{ "FCS", "wpan.fcs", FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_rssi,
{ "RSSI", "wpan.rssi", FT_INT8, BASE_DEC|BASE_UNIT_STRING, &units_decibels, 0x0,
"Received Signal Strength", HFILL }},
{ &hf_ieee802154_fcs_ok,
{ "FCS Valid", "wpan.fcs_ok", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_correlation,
{ "LQI Correlation Value", "wpan.correlation", FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
/* Header IE */
{ &hf_ieee802154_header_ie,
{ "Header IE", "wpan.header_ie", FT_UINT16, BASE_HEX, NULL,
0x0, NULL, HFILL }},
{ &hf_ieee802154_header_ie_type,
{ "Type", "wpan.header_ie.type", FT_UINT16, BASE_DEC, VALS(ieee802154_ie_types),
IEEE802154_HEADER_IE_TYPE_MASK, NULL, HFILL }},
{ &hf_ieee802154_header_ie_id,
{ "Id", "wpan.header_ie.id", FT_UINT16, BASE_HEX, VALS(ieee802154_header_ie_names),
IEEE802154_HEADER_IE_ID_MASK, NULL, HFILL }},
{ &hf_ieee802154_header_ie_length,
{ "Length", "wpan.header_ie.length", FT_UINT16, BASE_DEC, NULL,
IEEE802154_HEADER_IE_LENGTH_MASK, NULL, HFILL }},
{ &hf_ieee802154_header_ie_data,
{ "Data", "wpan.header_ie.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
/* Time correction IE */
{ &hf_ieee802154_time_correction,
{ "Time correction", "wpan.time_correction", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_ieee802154_nack,
{ "Non-acknowledgement", "wpan.nack", FT_BOOLEAN, 16, NULL, 0x8000,
NULL, HFILL }},
{ &hf_ieee802154_time_correction_value,
{ "Time correction", "wpan.time_correction_value", FT_INT16, BASE_DEC, NULL, 0x0FFF,
NULL, HFILL }},
/* Payload IEs */
{ &hf_ieee802154_payload_ie,
{ "Header", "wpan.payload_ie", FT_UINT16, BASE_HEX, NULL,
0x0, NULL, HFILL }},
{ &hf_ieee802154_payload_ie_type,
{ "Type", "wpan.payload_ie.type", FT_UINT16, BASE_DEC, VALS(ieee802154_ie_types),
IEEE802154_PAYLOAD_IE_TYPE_MASK, NULL, HFILL }},
{ &hf_ieee802154_payload_ie_id,
{ "Id", "wpan.payload_ie.id", FT_UINT16, BASE_HEX, VALS(ieee802154_payload_ie_names),
IEEE802154_PAYLOAD_IE_ID_MASK, NULL, HFILL }},
{ &hf_ieee802154_payload_ie_length,
{ "Length", "wpan.payload_ie.length", FT_UINT16, BASE_DEC, NULL,
IEEE802154_PAYLOAD_IE_LENGTH_MASK, NULL, HFILL }},
{ &hf_ieee802154_psie_short,
{ "Payload Sub IE (short)", "wpan.payload_sub_ie.short", FT_UINT16, BASE_HEX, NULL,
0x0, NULL, HFILL }},
{ &hf_ieee802154_psie_type_short,
{ "Type", "wpan.payload_sub_ie.type_short", FT_UINT16, BASE_DEC, VALS(ieee802154_psie_types),
IEEE802154_PSIE_TYPE_MASK, NULL, HFILL }},
{ &hf_ieee802154_psie_id_short,
{ "Sub Id (Short)", "wpan.payload_sub_ie.id_short", FT_UINT16, BASE_HEX, VALS(ieee802154_psie_names),
IEEE802154_PSIE_ID_MASK_SHORT, NULL, HFILL }},
{ &hf_ieee802154_psie_length_short,
{ "Length", "wpan.payload_sub_ie.length_short", FT_UINT16, BASE_DEC, NULL,
IEEE802154_PSIE_LENGTH_MASK_SHORT, NULL, HFILL }},
{ &hf_ieee802154_psie_long,
{ "Payload Sub IE (long)", "wpan.payload_sub_ie.long", FT_UINT16, BASE_HEX, NULL,
0x0, NULL, HFILL }},
{ &hf_ieee802154_psie_type_long,
{ "Type", "wpan.payload_sub_ie.type_long", FT_UINT16, BASE_DEC, VALS(ieee802154_psie_types),
IEEE802154_PSIE_TYPE_MASK, NULL, HFILL }},
{ &hf_ieee802154_psie_id_long,
{ "Sub Id (Long)", "wpan.payload_sub_ie.id_long", FT_UINT16, BASE_HEX, VALS(ieee802154_psie_names),
IEEE802154_PSIE_ID_MASK_LONG, NULL, HFILL }},
{ &hf_ieee802154_psie_length_long,
{ "Length", "wpan.payload_sub_ie.length_long", FT_UINT16, BASE_DEC, NULL,
IEEE802154_PSIE_LENGTH_MASK_LONG, NULL, HFILL }},
{ &hf_ieee802154_psie_eb_filter,
{ "Enhanced Beacon Filter", "wpan.payload_sub_ie.eb_filter", FT_UINT8, BASE_HEX, NULL,
0, NULL, HFILL }},
{ &hf_ieee802154_tsch_sync,
{ "Time Synchronization IE", "wpan.tsch.time_sync", FT_UINT64, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_tsch_asn,
{ "Absolute Slot Number", "wpan.tsch.asn", FT_UINT64, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_tsch_join_metric,
{ "Join Metric", "wpan.tsch.join_metric", FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_tsch_channel_hopping,
{ "Channel Hopping IE", "wpan.tsch.channel_hopping", FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_tsch_slotf_link_nb_slotf,
{ "Number of Slotframes", "wpan.p_ie_mlme_sh_slotf_link_nb_slotf", FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_tsch_slotf_link_slotf_handle,
{ "Slotframe handle", "wpan.p_ie_mlme_sh_slotf_link_slotf_handle", FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_tsch_slotf_size,
{ "Slotframe size", "wpan.tsch.slotframe_size", FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_tsch_slotf_link_nb_links,
{ "Number of Links", "wpan.tsch.nb_links", FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_tsch_slotf_link_timeslot,
{ "Timeslot", "wpan.tsch.timeslot", FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_tsch_slotf_link_channel_offset,
{ "Channel Offset", "wpan.tsch.channel_offset", FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_tsch_slotf_link_options,
{ "Link Options", "wpan.tsch.link_options", FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_tsch_hopping_sequence_id,
{ "Hopping Sequence ID", "wpan.tsch.hopping_sequence_id", FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_psie_eb_filter_pjoin,
{ "Permit Join Filter", "wpan.payload_sub_ie.eb_filter.pjoin", FT_BOOLEAN, 8, TFS(&tfs_enabled_disabled),
IEEE802154_MLME_PSIE_EB_FLT_PJOIN, NULL, HFILL }},
{ &hf_ieee802154_psie_eb_filter_lqi,
{ "LQI Filter", "wpan.payload_sub_ie.eb_filter.lqi", FT_BOOLEAN, 8, TFS(&tfs_enabled_disabled),
IEEE802154_MLME_PSIE_EB_FLT_LQI, NULL, HFILL }},
{ &hf_ieee802154_psie_eb_filter_lqi_min,
{ "Minimum LQI", "wpan.payload_sub_ie.eb_filter.lqi_minimum", FT_UINT8, BASE_DEC, NULL,
0x0, NULL, HFILL }},
{ &hf_ieee802154_psie_eb_filter_percent,
{ "Probability to Respond", "wpan.payload_sub_ie.eb_filter.contains_prob", FT_BOOLEAN, 8, TFS(&tfs_enabled_disabled),
IEEE802154_MLME_PSIE_EB_FLT_PERCENT, NULL, HFILL }},
{ &hf_ieee802154_psie_eb_filter_percent_prob,
{ "Response Probability Percentage", "wpan.payload_sub_ie.eb_filter.prob", FT_UINT8, BASE_DEC, NULL,
0x0, NULL, HFILL }},
{ &hf_ieee802154_psie_eb_filter_attr_id,
{ "Requested Attribute Length", "wpan.payload_sub_ie.eb_filter.attr_id", FT_UINT8, BASE_DEC, NULL,
IEEE802154_MLME_PSIE_EB_FLT_ATTR_LEN, NULL, HFILL }},
{ &hf_ieee802154_psie_eb_filter_attr_id_bitmap,
{ "Attribute ID Bitmap", "wpan.payload_sub_ie.eb_filter.attr_id_bits", FT_UINT24, BASE_HEX, NULL,
0x0, NULL, HFILL }},
{ &hf_ieee802154_payload_ie_data,
{ "Data", "wpan.payload_ie.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_ieee802154_payload_ie_vendor_oui,
{ "Vendor OUI", "wpan.payload_ie.vendor_oui", FT_UINT24, BASE_HEX, NULL,
0x0, NULL, HFILL }},
{ &hf_ieee802154_mlme_ie_data,
{ "Data", "wpan.mlme_sub_ie.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
/* IETF IE */
{ &hf_ieee802154_p_ie_ietf_sub_id,
{ "Sub-ID", "wpan.ietf_ie.sub_id", FT_UINT8, BASE_DEC, NULL, 0,
NULL, HFILL }},
/* IETF IE - 6top IE */
{ &hf_ieee802154_6top_version,
{ "6P Version", "wpan.6top_version", FT_UINT8, BASE_DEC, NULL, IETF_6TOP_VERSION,
NULL, HFILL }},
{ &hf_ieee802154_6top_type,
{ "Type", "wpan.6top_type", FT_UINT8, BASE_HEX, VALS(ietf_6top_types), IETF_6TOP_TYPE,
NULL, HFILL }},
{ &hf_ieee802154_6top_flags_reserved,
{ "Reserved", "wpan.6top_flags_reserved", FT_UINT8, BASE_HEX, NULL, IETF_6TOP_FLAGS_RESERVED,
NULL, HFILL }},
{ &hf_ieee802154_6top_code,
{ "Code", "wpan.6top_code", FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_6top_sfid,
{ "SFID (6top Scheduling Function ID)", "wpan.6top_sfid", FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_6top_seqnum,
{ "SeqNum", "wpan.6top_seqnum", FT_UINT8, BASE_DEC, NULL, IETF_6TOP_SEQNUM,
NULL, HFILL }},
{ &hf_ieee802154_6top_gab,
{ "GAB", "wpan.6top_gab", FT_UINT8, BASE_DEC, VALS(ietf_6top_generation_numbers), IETF_6TOP_GAB,
NULL, HFILL }},
{ &hf_ieee802154_6top_gba,
{ "GBA", "wpan.6top_gba", FT_UINT8, BASE_DEC, VALS(ietf_6top_generation_numbers), IETF_6TOP_GBA,
NULL, HFILL }},
{ &hf_ieee802154_6top_metadata,
{ "Metadata", "wpan.6top_metadata", FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_6top_cell_options,
{ "Cell Options", "wpan.6top_cell_options", FT_UINT8, BASE_HEX, VALS(ietf_6top_cell_options), 0x0,
NULL, HFILL }},
{ &hf_ieee802154_6top_cell_option_tx,
{ "Transmit (TX) Cell", "wpan.6top_cell_option_tx", FT_UINT8, BASE_HEX, NULL, IETF_6TOP_CELL_OPTION_TX,
NULL, HFILL }},
{ &hf_ieee802154_6top_cell_option_rx,
{ "Receive (RX) Cell", "wpan.6top_cell_option_rx", FT_UINT8, BASE_HEX, NULL, IETF_6TOP_CELL_OPTION_RX,
NULL, HFILL }},
{ &hf_ieee802154_6top_cell_option_shared,
{ "SHARED Cell", "wpan.6top_cell_option_shared", FT_UINT8, BASE_HEX, NULL, IETF_6TOP_CELL_OPTION_SHARED,
NULL, HFILL }},
{ &hf_ieee802154_6top_cell_option_reserved,
{ "Reserved", "wpan.6top_cell_option_reserved", FT_UINT8, BASE_HEX, NULL, IETF_6TOP_CELL_OPTION_RESERVED,
NULL, HFILL }},
{ &hf_ieee802154_6top_num_cells,
{ "Number of Cells", "wpan.6top_num_cells", FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_6top_reserved,
{ "Reserved", "wpan.6top_reserved", FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_6top_offset,
{ "Offset", "wpan.6top_offset", FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_6top_max_num_cells,
{ "Maximum Number of Requested Cells", "wpan.6top_max_num_cells", FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_6top_slot_offset,
{ "Slot Offset", "wpan.6top_cell_slot_offset", FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_6top_channel_offset,
{ "Channel Offset", "wpan.6top_channel_offset", FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL }},
/* Command Frame Specific Fields */
{ &hf_ieee802154_cmd_id,
{ "Command Identifier", "wpan.cmd", FT_UINT8, BASE_HEX, VALS(ieee802154_cmd_names), 0x0,
NULL, HFILL }},
/* Capability Information Fields */
{ &hf_ieee802154_cinfo_alt_coord,
{ "Alternate PAN Coordinator", "wpan.cinfo.alt_coord", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_ALT_PAN_COORD,
"Whether this device can act as a PAN coordinator or not.", HFILL }},
{ &hf_ieee802154_cinfo_device_type,
{ "Device Type", "wpan.cinfo.device_type", FT_BOOLEAN, 8, TFS(&tfs_cinfo_device_type), IEEE802154_CMD_CINFO_DEVICE_TYPE,
"Whether this device is RFD (reduced-function device) or FFD (full-function device).", HFILL }},
{ &hf_ieee802154_cinfo_power_src,
{ "Power Source", "wpan.cinfo.power_src", FT_BOOLEAN, 8, TFS(&tfs_cinfo_power_src), IEEE802154_CMD_CINFO_POWER_SRC,
"Whether this device is operating on AC/mains or battery power.", HFILL }},
{ &hf_ieee802154_cinfo_idle_rx,
{ "Receive On When Idle", "wpan.cinfo.idle_rx", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_IDLE_RX,
"Whether this device can receive packets while idle or not.", HFILL }},
{ &hf_ieee802154_cinfo_sec_capable,
{ "Security Capability", "wpan.cinfo.sec_capable", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_SEC_CAPABLE,
"Whether this device is capable of receiving encrypted packets.", HFILL }},
{ &hf_ieee802154_cinfo_alloc_addr,
{ "Allocate Address", "wpan.cinfo.alloc_addr", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_ALLOC_ADDR,
"Whether this device wishes to use a 16-bit short address instead of its IEEE 802.15.4 64-bit long address.", HFILL }},
/* Association response fields */
{ &hf_ieee802154_assoc_addr,
{ "Short Address", "wpan.asoc.addr", FT_UINT16, BASE_HEX, NULL, 0x0,
"The short address that the device should assume. An address of 0xfffe indicates that the device should use its IEEE 64-bit long address.", HFILL }},
{ &hf_ieee802154_assoc_status,
{ "Association Status", "wpan.assoc.status", FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_disassoc_reason,
{ "Disassociation Reason", "wpan.disassoc.reason", FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL }},
/* Coordinator Realignment fields */
{ &hf_ieee802154_realign_pan,
{ "PAN ID", "wpan.realign.pan", FT_UINT16, BASE_HEX, NULL, 0x0,
"The PAN identifier the coordinator wishes to use for future communication.", HFILL }},
{ &hf_ieee802154_realign_caddr,
{ "Coordinator Short Address", "wpan.realign.addr", FT_UINT16, BASE_HEX, NULL, 0x0,
"The 16-bit address the coordinator wishes to use for future communication.", HFILL }},
{ &hf_ieee802154_realign_channel,
{ "Logical Channel", "wpan.realign.channel", FT_UINT8, BASE_DEC, NULL, 0x0,
"The logical channel the coordinator wishes to use for future communication.", HFILL }},
{ &hf_ieee802154_realign_addr,
{ "Short Address", "wpan.realign.addr", FT_UINT16, BASE_HEX, NULL, 0x0,
"A short-address that the orphaned device shall assume if applicable.", HFILL }},
{ &hf_ieee802154_realign_channel_page,
{ "Channel Page", "wpan.realign.channel_page", FT_UINT8, BASE_DEC, NULL, 0x0,
"The logical channel page the coordinator wishes to use for future communication.", HFILL }},
{ &hf_ieee802154_gtsreq_len,
{ "GTS Length", "wpan.gtsreq.length", FT_UINT8, BASE_DEC, NULL, IEEE802154_CMD_GTS_REQ_LEN,
"Number of superframe slots the device is requesting.", HFILL }},
{ &hf_ieee802154_gtsreq_dir,
{ "GTS Direction", "wpan.gtsreq.direction", FT_BOOLEAN, 8, TFS(&tfs_gtsreq_dir), IEEE802154_CMD_GTS_REQ_DIR,
"The direction of traffic in the guaranteed timeslot.", HFILL }},
{ &hf_ieee802154_gtsreq_type,
{ "Characteristic Type", "wpan.gtsreq.type", FT_BOOLEAN, 8, TFS(&tfs_gtsreq_type), IEEE802154_CMD_GTS_REQ_TYPE,
"Whether this request is to allocate or deallocate a timeslot.", HFILL }},
/* Beacon Frame Specific Fields */
{ &hf_ieee802154_beacon_order,
{ "Beacon Interval", "wpan.beacon_order", FT_UINT16, BASE_DEC, NULL, IEEE802154_BEACON_ORDER_MASK,
"Specifies the transmission interval of the beacons.", HFILL }},
{ &hf_ieee802154_superframe_order,
{ "Superframe Interval", "wpan.superframe_order", FT_UINT16, BASE_DEC, NULL,
IEEE802154_SUPERFRAME_ORDER_MASK,
"Specifies the length of time the coordinator will interact with the PAN.", HFILL }},
{ &hf_ieee802154_cap,
{ "Final CAP Slot", "wpan.cap", FT_UINT16, BASE_DEC, NULL, IEEE802154_SUPERFRAME_CAP_MASK,
"Specifies the final superframe slot used by the CAP.", HFILL }},
{ &hf_ieee802154_superframe_battery_ext,
{ "Battery Extension", "wpan.battery_ext", FT_BOOLEAN, 16, NULL, IEEE802154_BATT_EXTENSION_MASK,
"Whether transmissions may not extend past the length of the beacon frame.", HFILL }},
{ &hf_ieee802154_superframe_coord,
{ "PAN Coordinator", "wpan.bcn_coord", FT_BOOLEAN, 16, NULL, IEEE802154_SUPERFRAME_COORD_MASK,
"Whether this beacon frame is being transmitted by the PAN coordinator or not.", HFILL }},
{ &hf_ieee802154_assoc_permit,
{ "Association Permit", "wpan.assoc_permit", FT_BOOLEAN, 16, NULL, IEEE802154_ASSOC_PERMIT_MASK,
"Whether this PAN is accepting association requests or not.", HFILL }},
{ &hf_ieee802154_gts_count,
{ "GTS Descriptor Count", "wpan.gts.count", FT_UINT8, BASE_DEC, NULL, 0x0,
"The number of GTS descriptors present in this beacon frame.", HFILL }},
{ &hf_ieee802154_gts_permit,
{ "GTS Permit", "wpan.gts.permit", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
"Whether the PAN coordinator is accepting GTS requests or not.", HFILL }},
{ &hf_ieee802154_gts_direction,
{ "Direction", "wpan.gts.direction", FT_BOOLEAN, BASE_NONE, TFS(&ieee802154_gts_direction_tfs), 0x0,
"A flag defining the direction of the GTS Slot.", HFILL }},
{ &hf_ieee802154_gts_address,
{ "Address", "wpan.gts.address", FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_pending16,
{ "Address", "wpan.pending16", FT_UINT16, BASE_HEX, NULL, 0x0,
"Device with pending data to receive.", HFILL }},
{ &hf_ieee802154_pending64,
{ "Address", "wpan.pending64", FT_EUI64, BASE_NONE, NULL, 0x0,
"Device with pending data to receive.", HFILL }},
/* Auxiliary Security Header Fields */
{ &hf_ieee802154_aux_security_header,
{ "Auxiliary Security Header", "wpan.aux_sec.hdr", FT_NONE, BASE_NONE, NULL,
0x0, "The Auxiliary Security Header of the frame", HFILL }},
{ &hf_ieee802154_security_level,
{ "Security Level", "wpan.aux_sec.sec_level", FT_UINT8, BASE_HEX, VALS(ieee802154_sec_level_names),
IEEE802154_AUX_SEC_LEVEL_MASK, "The Security Level of the frame", HFILL }},
{ &hf_ieee802154_security_control_field,
{ "Security Control Field", "wpan.aux_sec.security_control_field", FT_UINT8, BASE_HEX, NULL,
0x0, NULL, HFILL }},
{ &hf_ieee802154_key_id_mode,
{ "Key Identifier Mode", "wpan.aux_sec.key_id_mode", FT_UINT8, BASE_HEX, VALS(ieee802154_key_id_mode_names),
IEEE802154_AUX_KEY_ID_MODE_MASK,
"The scheme to use by the recipient to lookup the key in its key table", HFILL }},
{ &hf_ieee802154_aux_sec_reserved,
{ "Reserved", "wpan.aux_sec.reserved", FT_UINT8, BASE_HEX, NULL, IEEE802154_AUX_KEY_RESERVED_MASK,
NULL, HFILL }},
{ &hf_ieee802154_aux_sec_frame_counter,
{ "Frame Counter", "wpan.aux_sec.frame_counter", FT_UINT32, BASE_DEC, NULL, 0x0,
"Frame counter of the originator of the protected frame", HFILL }},
{ &hf_ieee802154_aux_sec_key_source,
{ "Key Source", "wpan.aux_sec.key_source", FT_UINT64, BASE_HEX, NULL, 0x0,
"Key Source for processing of the protected frame", HFILL }},
{ &hf_ieee802154_aux_sec_key_source_bytes,
{ "Key Source", "wpan.aux_sec.key_source.bytes", FT_BYTES, BASE_NONE, NULL, 0x0,
"Key Source for processing of the protected frame", HFILL }},
{ &hf_ieee802154_aux_sec_key_index,
{ "Key Index", "wpan.aux_sec.key_index", FT_UINT8, BASE_HEX, NULL, 0x0,
"Key Index for processing of the protected frame", HFILL }},
{ &hf_ieee802154_mic,
{ "Decrypted MIC", "wpan.mic", FT_BYTES, BASE_NONE, NULL, 0x0,
"The Decrypted MIC", HFILL }},
{ &hf_ieee802154_key_number,
{ "Key Number", "wpan.key_number", FT_UINT8, BASE_DEC, NULL, 0x0,
"Key number used to decode", HFILL }},
/* IEEE 802.15.4-2003 Security Header Fields */
{ &hf_ieee802154_sec_frame_counter,
{ "Frame Counter", "wpan.sec_frame_counter", FT_UINT32, BASE_HEX, NULL, 0x0,
"Frame counter of the originator of the protected frame (802.15.4-2003)", HFILL }},
{ &hf_ieee802154_sec_key_sequence_counter,
{ "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 }},
/* ZBOSS dump */
{ &zboss_channel,
{ "Channel", "wpan.zboss.channel", FT_UINT8, BASE_DEC, NULL, 0x0,
"Channel number", HFILL }},
{ &zboss_direction,
{ "ZBOSS Direction", "wpan.zboss.direction", FT_UINT8, BASE_HEX, VALS(zboss_direction_names), 0x0,
"ZBOSS Packet Direction", HFILL }},
{ &zboss_trace_number,
{ "Trace number", "wpan.zboss.trace", FT_UINT32, BASE_DEC, NULL, 0x0,
"Trace item number", HFILL }},
};
/* Subtrees */
static gint *ett[] = {
&ett_ieee802154_nonask_phy,
&ett_ieee802154_nonask_phy_phr,
&ett_ieee802154,
&ett_ieee802154_fcf,
&ett_ieee802154_auxiliary_security,
&ett_ieee802154_aux_sec_control,
&ett_ieee802154_aux_sec_key_id,
&ett_ieee802154_fcs,
&ett_ieee802154_cmd,
&ett_ieee802154_superframe,
&ett_ieee802154_gts,
&ett_ieee802154_gts_direction,
&ett_ieee802154_gts_descriptors,
&ett_ieee802154_pendaddr,
&ett_ieee802154_header,
&ett_ieee802154_header_ie,
&ett_ieee802154_h_ie_payload,
&ett_ieee802154_payload,
&ett_ieee802154_payload_ie,
&ett_ieee802154_mlme_payload,
&ett_ieee802154_mlme_payload_data,
&ett_ieee802154_psie_short,
&ett_ieee802154_psie_short_bitmap,
&ett_ieee802154_psie_long,
&ett_ieee802154_psie_long_bitmap,
&ett_ieee802154_psie_enh_beacon_flt,
&ett_ieee802154_psie_enh_beacon_flt_bitmap,
&ett_ieee802154_psie_slotframe_link_slotframes,
&ett_ieee802154_zigbee,
&ett_ieee802154_zboss,
&ett_ieee802154_p_ie_6top,
&ett_ieee802154_p_ie_6top_version_type,
&ett_ieee802154_p_ie_6top_seqnum_gab_gba,
&ett_ieee802154_p_ie_6top_cell_options,
&ett_ieee802154_p_ie_6top_cell_list,
&ett_ieee802154_p_ie_6top_cell
};
static ei_register_info ei[] = {
{ &ei_ieee802154_invalid_addressing, { "wpan.invalid_addressing", PI_MALFORMED, PI_WARN,
"Invalid Addressing", EXPFILL }},
#if 0
{ &ei_ieee802154_invalid_panid_compression, { "wpan.invalid_panid_compression", PI_MALFORMED, PI_ERROR,
"Invalid Setting for PAN ID Compression", EXPFILL }},
#endif
{ &ei_ieee802154_invalid_panid_compression2, { "wpan.seqno_supression_fv2_invalid", PI_MALFORMED, PI_WARN,
"Invalid Pan ID Compression and addressing combination for Frame Version 2", EXPFILL }},
{ &ei_ieee802154_dst, { "wpan.dst_invalid", PI_MALFORMED, PI_ERROR,
"Invalid Destination Address Mode", EXPFILL }},
{ &ei_ieee802154_src, { "wpan.src_invalid", PI_MALFORMED, PI_ERROR,
"Invalid Source Address Mode", EXPFILL }},
{ &ei_ieee802154_frame_ver, { "wpan.frame_version_unknown", PI_MALFORMED, PI_ERROR,
"Frame Version Unknown Cannot Dissect", EXPFILL }},
#if 0
{ &ei_ieee802154_frame_type, { "wpan.frame_type_unknown", PI_MALFORMED, PI_ERROR,
"Frame Type Unknown Cannot Dissect", EXPFILL }},
#endif
{ &ei_ieee802154_decrypt_error, { "wpan.decrypt_error", PI_UNDECODED, PI_WARN,
"Decryption error", EXPFILL }},
{ &ei_ieee802154_fcs, { "wpan.fcs.bad", PI_CHECKSUM, PI_WARN,
"Bad FCS", EXPFILL }},
{ &ei_ieee802154_seqno_suppression, { "wpan.seqno_supression_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,
"Unsupported Type of Message", EXPFILL }},
{ &ei_ieee802154_6top_unsupported_command, { "wpan.6top_unsupported_command", PI_PROTOCOL, PI_WARN,
"Unsupported 6Top command", EXPFILL }},
{ &ei_ieee802154_time_correction_error, { "wpan.time_correction.error", PI_PROTOCOL, PI_WARN,
"Incorrect value. Reference: IEEE-802.15.4-2015. Table 7-8: Values of the Time Sync Info field for ACK with timing Information", EXPFILL}},
{ &ei_ieee802154_6top_unsupported_return_code, { "wpan.6top_unsupported_code", PI_PROTOCOL, PI_WARN,
"Unsupported 6Top return code", EXPFILL }},
};
/* Preferences. */
module_t *ieee802154_module;
expert_module_t* expert_ieee802154;
static uat_field_t addr_uat_flds[] = {
UAT_FLD_HEX(addr_uat,addr16,"Short Address",
"16-bit short address in hexadecimal."),
UAT_FLD_HEX(addr_uat,pan,"PAN Identifier",
"16-bit PAN identifier in hexadecimal."),
UAT_FLD_BUFFER(addr_uat,eui64,"EUI-64",
"64-bit extended unique identifier."),
UAT_END_FIELDS
};
static uat_field_t key_uat_flds[] = {
UAT_FLD_CSTRING(key_uat,pref_key,"Decryption key",
"128-bit decryption key in hexadecimal format"),
UAT_FLD_DEC(key_uat,key_index,"Decryption key index",
"Key index in decimal format"),
UAT_FLD_VS(key_uat, hash_type, "Key hash", ieee802154_key_hash_vals, "Specifies which hash scheme is used to derived the key"),
UAT_END_FIELDS
};
static build_valid_func ieee802154_da_build_value[1] = {ieee802154_da_value};
static decode_as_value_t ieee802154_da_values = {ieee802154_da_prompt, 1, ieee802154_da_build_value};
static decode_as_t ieee802154_da = {
IEEE802154_PROTOABBREV_WPAN, "PAN", IEEE802154_PROTOABBREV_WPAN_PANID,
1, 0, &ieee802154_da_values, NULL, NULL,
decode_as_default_populate_list, decode_as_default_reset, decode_as_default_change, NULL
};
/* Register the init routine. */
register_init_routine(proto_init_ieee802154);
register_cleanup_routine(proto_cleanup_ieee802154);
/* Register Protocol name and description. */
proto_ieee802154 = proto_register_protocol("IEEE 802.15.4 Low-Rate Wireless PAN", "IEEE 802.15.4",
IEEE802154_PROTOABBREV_WPAN);
proto_ieee802154_nonask_phy = proto_register_protocol("IEEE 802.15.4 Low-Rate Wireless PAN non-ASK PHY",
"IEEE 802.15.4 non-ASK PHY", "wpan-nonask-phy");
proto_zboss = proto_register_protocol("ZBOSS IEEE 802.15.4 dump",
"ZBOSS dump", "wpan-zboss");
/* Register header fields and subtrees. */
proto_register_field_array(proto_ieee802154, hf, array_length(hf));
proto_register_field_array(proto_ieee802154, hf_phy, array_length(hf_phy));
proto_register_subtree_array(ett, array_length(ett));
expert_ieee802154 = expert_register_protocol(proto_ieee802154);
expert_register_field_array(expert_ieee802154, ei, array_length(ei));
ieee802_15_4_short_address_type = address_type_dissector_register("AT_IEEE_802_15_4_SHORT", "IEEE 802.15.4 16-bit short address",
ieee802_15_4_short_address_to_str, ieee802_15_4_short_address_str_len, NULL, NULL, ieee802_15_4_short_address_len, NULL, NULL);
/* add a user preference to set the 802.15.4 ethertype */
ieee802154_module = prefs_register_protocol(proto_ieee802154,
proto_reg_handoff_ieee802154);
prefs_register_uint_preference(ieee802154_module, "802154_ethertype",
"802.15.4 Ethertype (in hex)",
"(Hexadecimal) Ethertype used to indicate IEEE 802.15.4 frame.",
16, &ieee802154_ethertype);
prefs_register_bool_preference(ieee802154_module, "802154_cc24xx",
"TI CC24xx FCS format",
"Set if the FCS field is in TI CC24xx format.",
&ieee802154_cc24xx);
prefs_register_bool_preference(ieee802154_module, "802154_fcs_ok",
"Dissect only good FCS",
"Dissect payload only if FCS is valid.",
&ieee802154_fcs_ok);
/* Create a UAT for static address mappings. */
static_addr_uat = uat_new("Static Addresses",
sizeof(static_addr_t), /* record size */
"802154_addresses", /* filename */
TRUE, /* from_profile */
&static_addrs, /* data_ptr */
&num_static_addrs, /* numitems_ptr */
UAT_AFFECTS_DISSECTION, /* affects dissection of packets, but not set of named fields */
NULL, /* help */
NULL, /* copy callback */
addr_uat_update_cb, /* update callback */
NULL, /* free callback */
NULL, /* post update callback */
NULL, /* reset callback */
addr_uat_flds); /* UAT field definitions */
prefs_register_uat_preference(ieee802154_module, "static_addr",
"Static Addresses",
"A table of static address mappings between 16-bit short addressing and EUI-64 addresses",
static_addr_uat);
/* Create a UAT for key management. */
ieee802154_key_uat = uat_new("Keys",
sizeof(ieee802154_key_t), /* record size */
"ieee802154_keys", /* filename */
TRUE, /* from_profile */
&ieee802154_keys, /* data_ptr */
&num_ieee802154_keys, /* numitems_ptr */
UAT_AFFECTS_DISSECTION, /* affects dissection of packets, but not set of named fields */
NULL, /* help */
ieee802154_key_copy_cb, /* copy callback */
ieee802154_key_update_cb, /* update callback */
ieee802154_key_free_cb, /* free callback */
ieee802154_key_post_update_cb, /* post update callback */
NULL, /* reset callback */
key_uat_flds); /* UAT field definitions */
prefs_register_uat_preference(ieee802154_module, "ieee802154_keys",
"Decryption Keys",
"Decryption key configuration data",
ieee802154_key_uat);
/* Register preferences for a decryption key */
prefs_register_obsolete_preference(ieee802154_module, "802154_key");
prefs_register_enum_preference(ieee802154_module, "802154_sec_suite",
"Security Suite (802.15.4-2003)",
"Specifies the security suite to use for 802.15.4-2003 secured frames"
" (only supported suites are listed). Option ignored for 802.15.4-2006"
" and unsecured frames.",
&ieee802154_sec_suite, ieee802154_2003_sec_suite_enums, FALSE);
prefs_register_bool_preference(ieee802154_module, "802154_extend_auth",
"Extend authentication data (802.15.4-2003)",
"Set if the manufacturer extends the authentication data with the"
" security header. Option ignored for 802.15.4-2006 and unsecured frames.",
&ieee802154_extend_auth);
/* Register the subdissector list */
panid_dissector_table = register_dissector_table(IEEE802154_PROTOABBREV_WPAN_PANID, "IEEE 802.15.4 PANID", proto_ieee802154, FT_UINT16, BASE_HEX);
ieee802154_heur_subdissector_list = register_heur_dissector_list(IEEE802154_PROTOABBREV_WPAN, proto_ieee802154);
ieee802154_beacon_subdissector_list = register_heur_dissector_list(IEEE802154_PROTOABBREV_WPAN_BEACON, proto_ieee802154);
/* Register dissectors with Wireshark. */
ieee802154_handle = register_dissector(IEEE802154_PROTOABBREV_WPAN, dissect_ieee802154, proto_ieee802154);
ieee802154_nofcs_handle = register_dissector("wpan_nofcs", dissect_ieee802154_nofcs, proto_ieee802154);
register_dissector("wpan_cc24xx", dissect_ieee802154_cc24xx, proto_ieee802154);
ieee802154_nonask_phy_handle = register_dissector("wpan-nonask-phy", dissect_ieee802154_nonask_phy, proto_ieee802154_nonask_phy);
/* setup registration for other dissectors to provide mac key hash algorithms */
mac_key_hash_handlers = wmem_tree_new(wmem_epan_scope());
/* Register a Decode-As handler. */
register_decode_as(&ieee802154_da);
} /* proto_register_ieee802154 */
/**
* Registers the IEEE 802.15.4 dissector with Wireshark.
* Will be called every time 'apply' is pressed in the preferences menu.
* as well as during Wireshark initialization
*/
void proto_reg_handoff_ieee802154(void)
{
static gboolean prefs_initialized = FALSE;
static unsigned int old_ieee802154_ethertype;
if (!prefs_initialized){
/* Get the dissector handles. */
zigbee_beacon_handle = find_dissector_add_dependency("zbee_beacon", proto_ieee802154);
zigbee_ie_handle = find_dissector_add_dependency("zbee_ie", proto_ieee802154);
zigbee_nwk_handle = find_dissector("zbee_nwk");
dissector_add_uint("wtap_encap", WTAP_ENCAP_IEEE802_15_4, ieee802154_handle);
dissector_add_uint("wtap_encap", WTAP_ENCAP_IEEE802_15_4_NONASK_PHY, ieee802154_nonask_phy_handle);
dissector_add_uint("wtap_encap", WTAP_ENCAP_IEEE802_15_4_NOFCS, ieee802154_nofcs_handle);
dissector_add_uint("sll.ltype", LINUX_SLL_P_IEEE802154, ieee802154_handle);
prefs_initialized = TRUE;
} else {
dissector_delete_uint("ethertype", old_ieee802154_ethertype, ieee802154_handle);
}
old_ieee802154_ethertype = ieee802154_ethertype;
/* Register dissector handles. */
dissector_add_uint("ethertype", ieee802154_ethertype, ieee802154_handle);
} /* proto_reg_handoff_ieee802154 */
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/