wireshark/epan/dissectors/packet-ieee802154.c

5243 lines
223 KiB
C
Raw Normal View History

/* 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>
Move show_exception() and show_reported_bounds_error() to epan/show_exception.c, as it's used outside epan/dissectors/packet-frame.c. Update their callers to include <epan/show_exception.h> to get their declaration. Add a CATCH_NONFATAL_ERRORS macro that catches all exceptions that, if there's more stuff in the packet to dissect after the dissector call that threw the exception, doesn't mean you shouldn't go ahead and dissect that stuff. Use it in all those cases, including ones where BoundsError was inappropriately being caught (you want those passed up to the top level, so that the packet is reported as having been cut short in the capture process). Add a CATCH_BOUNDS_ERRORS macro that catches all exceptions that correspond to running past the end of the data for a tvbuff; use it rather than explicitly catching those exceptions individually, and rather than just catching all exceptions (the only place that DissectorError should be caught, for example, is at the top level, so dissector bugs show up in the protocol tree). Don't catch and then immediately rethrow exceptions without doing anything else; just let the exceptions go up to the final catcher. Use show_exception() to report non-fatal errors, rather than doing it yourself. If a dissector is called from Lua, catch all non-fatal errors and use show_exception() to report them rather than catching only ReportedBoundsError and adding a proto_malformed item. Don't catch exceptions when constructing a trailer tvbuff in packet-ieee8023.c - just construct it after the payload has been dissected, and let whatever exceptions that throws be handled at the top level. Avoid some TRY/CATCH/ENDTRY cases by using checks such as tvb_bytes_exist() before even looking in the tvbuff. svn path=/trunk/; revision=47924
2013-02-27 22:43:54 +00:00
#include <epan/show_exception.h>
#include <epan/proto_data.h>
#include <epan/etypes.h>
#include <epan/oui.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)
/*
* Decryption Keys 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 int dissect_ieee802154_header_ie(tvbuff_t *, packet_info *, proto_tree *, guint, ieee802154_packet *);
static int dissect_ieee802154_payload_ie(tvbuff_t *, packet_info *, proto_tree *, guint, ieee802154_packet *);
static void dissect_802154_enhanced_beacon_filter(tvbuff_t *tvb, proto_tree *subtree, guint16 psie_remaining, gint *offset);
static void dissect_802154_tsch_time_sync(tvbuff_t *, proto_tree *, int *, guint);
static void dissect_802154_tsch_timeslot(tvbuff_t *, proto_tree *, guint, guint16, gint*);
static void dissect_802154_tsch_slotframe_link(tvbuff_t *, proto_tree *, guint16, guint16, guint *);
static void dissect_802154_channel_hopping(tvbuff_t *, proto_tree *, guint16, guint *);
/* 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_ies = -1;
static int hf_ieee802154_header_ie_tlv = -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_ie_unknown_content = -1;
static int hf_ieee802154_hie_unsupported = -1;
static int hf_ieee802154_hie_time_correction = -1;
static int hf_ieee802154_hie_ht1 = -1;
static int hf_ieee802154_hie_ht2 = -1;
static int hf_ieee802154_nack = -1;
static int hf_ieee802154_hie_time_correction_time_sync_info = -1;
static int hf_ieee802154_hie_time_correction_value = -1;
static int hf_ieee802154_hie_csl = -1;
static int hf_ieee802154_hie_csl_phase = -1;
static int hf_ieee802154_hie_csl_period = -1;
static int hf_ieee802154_hie_csl_rendezvous_time = -1;
static int hf_ieee802154_payload_ies = -1;
static int hf_ieee802154_payload_ie_tlv = -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_pie_unsupported = -1;
static int hf_ieee802154_pie_termination = -1;
static int hf_ieee802154_pie_vendor = -1;
static int hf_ieee802154_pie_ietf = -1;
static int hf_ieee802154_mlme = -1;
static int hf_ieee802154_payload_ie_vendor_oui = -1;
static int hf_ieee802154_timeslot_ie = -1;
static int hf_ieee802154_enhanced_beacon_filter_ie = -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_slotframe = -1;
static int hf_ieee802154_tsch_slotframe_list = -1;
static int hf_ieee802154_tsch_link_info = -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 = -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_gen = -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_cell_list = -1;
static int hf_ieee802154_6top_rel_cell_list = -1;
static int hf_ieee802154_6top_cand_cell_list = -1;
static int hf_ieee802154_6top_cell = -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 hf_ieee802154_6top_total_num_cells = -1;
static int hf_ieee802159_mpx = -1;
static int hf_ieee802159_mpx_transaction_control = -1;
static int hf_ieee802159_mpx_transfer_type = -1;
static int hf_ieee802159_mpx_transaction_id = -1;
static int hf_ieee802159_mpx_transaction_id_as_multiplex_id = -1;
static int hf_ieee802159_mpx_fragment_number = -1;
static int hf_ieee802159_mpx_total_frame_size = -1;
static int hf_ieee802159_mpx_multiplex_id = -1;
static int hf_ieee802159_mpx_kmp_id = -1;
static int hf_ieee802159_mpx_kmp_vendor_oui = -1;
static int hf_ieee802159_mpx_fragment = -1;
static int proto_zboss = -1;
static int hf_zboss_direction = -1;
static int hf_zboss_page = -1;
static int hf_zboss_channel = -1;
static int hf_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_aux_sec_security_control = -1;
static int hf_ieee802154_aux_sec_security_level = -1;
static int hf_ieee802154_aux_sec_key_id_mode = -1;
static int hf_ieee802154_aux_sec_frame_counter_suppression = -1;
static int hf_ieee802154_aux_sec_asn_in_nonce = -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_ies = -1;
static gint ett_ieee802154_header_ie = -1;
static gint ett_ieee802154_header_ie_tlv = -1;
static gint ett_ieee802154_hie_unsupported = -1;
static gint ett_ieee802154_hie_time_correction = -1;
static gint ett_ieee802154_hie_ht = -1;
static gint ett_ieee802154_hie_csl = -1;
static gint ett_ieee802154_payload_ie = -1;
static gint ett_ieee802154_payload_ie_tlv = -1;
static gint ett_ieee802154_pie_termination = -1;
static gint ett_ieee802154_pie_vendor = -1;
static gint ett_ieee802154_pie_ietf = -1;
static gint ett_ieee802154_pie_unsupported = -1;
static gint ett_ieee802154_mlme = -1;
static gint ett_ieee802154_mlme_payload = -1;
static gint ett_ieee802154_mlme_payload_data = -1;
static gint ett_ieee802154_tsch_timeslot = -1;
static gint ett_ieee802154_tsch_synch = -1;
static gint ett_ieee802154_channel_hopping = -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_cell_options = -1;
static gint ett_ieee802154_p_ie_6top_cell_list = -1;
static gint ett_ieee802154_p_ie_6top_cand_cell_list = -1;
static gint ett_ieee802154_p_ie_6top_rel_cell_list = -1;
static gint ett_ieee802154_p_ie_6top_cell = -1;
static gint ett_ieee802159_mpx = -1;
static gint ett_ieee802159_mpx_transaction_control = -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 expert_field ei_ieee802154_ie_unsupported_id = EI_INIT;
static expert_field ei_ieee802154_ie_unknown_extra_content = EI_INIT;
static expert_field ei_ieee802159_mpx_invalid_transfer_type = EI_INIT;
static expert_field ei_ieee802159_mpx_unsupported_kmp = EI_INIT;
static expert_field ei_ieee802159_mpx_unknown_kmp = 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;
/* For the IEs */
static dissector_table_t header_ie_dissector_table;
static dissector_table_t payload_ie_dissector_table;
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;
static dissector_table_t ethertype_table; // for the MPX-IE
static dissector_handle_t eapol_handle; // for the MPX-IE
/* 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_IE_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_HT1, "Header Termination 1 IE" },
{ IEEE802154_HEADER_IE_HT2, "Header Termination 2 IE" },
{ 0, NULL }
};
static const true_false_string hf_ieee802154_nack_tfs = {
"Negative Acknowledgement",
"Acknowledgement"
};
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_MPX, "MPX IE" },
{ IEEE802154_PAYLOAD_IE_IETF, "IETF IE" },
{ IEEE802154_PAYLOAD_IE_TERMINATION, "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_page_names[] = {
{ 0, "2.4 GHz" },
{ 28, "863-868 MHz band"},
{ 29, "868-870, 870-876 MHz band" },
{ 30, "870-876 MHz band" },
{ 31, "915-921 MHz band" },
{ 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_RELOCATE, "RELOCATE" },
{ IETF_6TOP_CMD_COUNT, "COUNT" },
{ 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_ERROR, "ERROR" },
{ IETF_6TOP_RC_EOL, "EOL" },
{ IETF_6TOP_RC_RESET, "RESET" },
{ IETF_6TOP_RC_VER_ERR, "VER_ERR" },
{ IETF_6TOP_RC_SFID_ERR, "SFID_ERR" },
{ IETF_6TOP_RC_GEN_ERR, "GEN_ERR" },
{ IETF_6TOP_RC_BUSY, "BUSY" },
{ IETF_6TOP_RC_NORES, "NORES" },
{ IETF_6TOP_RC_CELLLIST_ERR, "CELLLIST_ERR" },
{ 0, NULL }
};
static const value_string ietf_6top_generation_numbers[] = {
{ 0, "Clear" },
{ 1, "Lollipop Counter Value" },
{ 2, "Lollipop Counter Value" },
{ 3, "Lollipop Counter Value" },
{ 4, "Lollipop Counter Value" },
{ 5, "Lollipop Counter Value" },
{ 6, "Lollipop Counter Value" },
{ 7, "Lollipop Counter Value" },
{ 8, "Lollipop Counter Value" },
{ 9, "Lollipop Counter Value" },
{ 10, "Reserved" },
{ 11, "Reserved" },
{ 12, "Reserved" },
{ 13, "Reserved" },
{ 14, "Reserved" },
{ 15, "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}
};
static const value_string mpx_transfer_type_vals[] = {
{ IEEE802159_MPX_FULL_FRAME, "Full Frame" },
{ IEEE802159_MPX_FULL_FRAME_NO_MUXID, "Full frame with compressed Multiplex ID" },
{ IEEE802159_MPX_NON_LAST_FRAGMENT, "Non-last Fragment" },
{ IEEE802159_MPX_LAST_FRAGMENT, "Last Fragment" },
{ IEEE802159_MPX_ABORT, "Abort" },
{ 0, NULL }
};
static const value_string mpx_multiplex_id_vals[] = {
{ IEEE802159_MPX_MULTIPLEX_ID_KMP, "KMP" },
{ 0, NULL }
};
static const value_string mpx_kmp_id_vals[] = {
{ IEEE802159_MPX_KMP_ID_IEEE8021X, "IEEE 802.1X/MKA" },
{ IEEE802159_MPX_KMP_ID_HIP, "HIP" },
{ IEEE802159_MPX_KMP_ID_IKEV2, "IKEv2" },
{ IEEE802159_MPX_KMP_ID_PANA, "PANA" },
{ IEEE802159_MPX_KMP_ID_DRAGONFLY, "Dragonfly" },
{ IEEE802159_MPX_KMP_ID_IEEE80211_4WH, "IEEE 802.11/4WH" },
{ IEEE802159_MPX_KMP_ID_IEEE80211_GKH, "IEEE 802.11/GKH" },
{ IEEE802159_MPX_KMP_ID_ETSI_TS_102_887_2, "ETSI TS 102 887-2" },
{ IEEE802159_MPX_KMP_ID_VENDOR_SPECIFIC, "Vendor-specific" },
{ 0, NULL }
};
static const int * header_short_format_nested_ie[] = {
&hf_ieee802154_psie_type_short,
&hf_ieee802154_psie_id_short,
&hf_ieee802154_psie_length_short,
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 = 1; /* Minimum length of the auxiliary header. */
static const int * security_fields[] = {
&hf_ieee802154_aux_sec_security_level,
&hf_ieee802154_aux_sec_key_id_mode,
&hf_ieee802154_aux_sec_frame_counter_suppression,
&hf_ieee802154_aux_sec_asn_in_nonce,
&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);
if (packet->version == IEEE802154_VERSION_2015) {
packet->frame_counter_suppression = security_control & IEEE802154_AUX_FRAME_COUNTER_SUPPRESSION_MASK ? TRUE : FALSE;
}
/* Compute the length of the auxiliary header and create a subtree. */
if (!packet->frame_counter_suppression) aux_length += 4;
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_aux_sec_security_control, ett_ieee802154_aux_sec_control, security_fields, ENC_NA);
(*offset)++;
/* Frame Counter Field */
if (!packet->frame_counter_suppression) {
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)
{
proto_tree *zboss_tree;
proto_item *proto_root;
guint off = 0;
guint32 direction_byte, page_byte, channel;
if (tvb_captured_length(tvb) > 5)
{
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')
{
/* Create the protocol 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_ret_uint(zboss_tree, hf_zboss_direction, tvb, off, 1, ENC_NA, &direction_byte);
proto_item_append_text(proto_root, ", %s", direction_byte ? "OUT" : "IN");
proto_tree_add_item_ret_uint(zboss_tree, hf_zboss_page, tvb, off, 1, ENC_NA, &page_byte);
proto_item_append_text(proto_root, ", page %u", page_byte);
off++;
proto_tree_add_item_ret_uint(zboss_tree, hf_zboss_channel, tvb, off, 1, ENC_NA, &channel);
proto_item_append_text(proto_root, ", channel %u", channel);
off++;
proto_tree_add_item(zboss_tree, hf_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);
}
}
/* Existence 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) {
offset += 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 MIC and FCS fields at the end. */
gint reported_len = tvb_reported_length(tvb)-offset-rx_mic_len-IEEE802154_FCS_LEN;
gint captured_len = tvb_captured_length(tvb)-offset;
payload_tvb = tvb_new_subset_length_caplen(tvb, offset, MIN(captured_len, reported_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_FRAME_COUNTER_SUPPRESSION_UNSUPPORTED:
expert_add_info_format(pinfo, proto_root, &ei_ieee802154_decrypt_error, "Decryption of 802.15.4-2015 with frame counter suppression is not supported");
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);
}
offset = 0;
/* Presence of Payload IEs is defined by the termination of the Header IEs */
if (packet->payload_ie_present) {
offset += dissect_ieee802154_payload_ie(payload_tvb, pinfo, ieee802154_tree, offset, packet);
}
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 */
/*
* Information Elements Processing (IEs)
*/
/**
* Create a tree for a Payload IE incl. the TLV header and append the IE name to the parent item
*
* @param tvb the tv buffer
* @param tree the tree to append this item to
* @param hf field index
* @param ett tree index
* @param id the IE ID used to append the IE name to the parent item of tree
* @param new_item if != NULL, pointer to store the item created for this Payload IE
* @returns the tree created for the Payload IE
*/
static proto_tree*
create_payload_ie_tree(tvbuff_t *tvb, proto_tree *tree, int hf, gint ett, guint16 id, proto_item** new_item)
{
proto_item *subitem;
proto_tree *subtree;
static const int * tlv_fields[] = {
&hf_ieee802154_payload_ie_type,
&hf_ieee802154_payload_ie_id,
&hf_ieee802154_payload_ie_length,
NULL
};
subitem = proto_tree_add_item(tree, hf, tvb, 0, tvb_reported_length(tvb), ENC_NA);
subtree = proto_item_add_subtree(subitem, ett);
proto_tree_add_bitmask_with_flags(subtree, tvb, 0, hf_ieee802154_payload_ie_tlv, ett_ieee802154_payload_ie_tlv,
tlv_fields, ENC_LITTLE_ENDIAN, BMT_NO_FLAGS);
const char *name = try_val_to_str(id, ieee802154_payload_ie_names);
if (name) {
proto_item_append_text(proto_tree_get_parent(tree), ", %s", name);
} else {
proto_item_append_text(proto_tree_get_parent(tree), ", Unknown IE 0x%02x", id);
proto_item_append_text(subitem, ": 0x%02x", id);
}
if (new_item) {
*new_item = subitem;
}
return subtree;
}
/**
* Subdissector for the MLME Channel Hopping Payload IE
*
* Reference: IEEE 802.15.4-2015 - 7.4.4.31 Channel hopping IE
*
* @param tvb pointer to buffer containing raw packet.
* @param tree 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_channel_hopping(tvbuff_t *tvb, proto_tree *tree, guint16 psie_remaining, guint *offset)
{
proto_item *tsch_channel_hopping_data_item = NULL;
proto_tree *tsch_channel_hopping_data_tree = NULL;
static const int * fields_long[] = {
&hf_ieee802154_psie_type_long,
&hf_ieee802154_psie_id_long,
&hf_ieee802154_psie_length_long,
NULL
};
tsch_channel_hopping_data_item = proto_tree_add_item(tree, hf_ieee802154_tsch_channel_hopping, tvb, (*offset), 2 + psie_remaining, ENC_NA);
tsch_channel_hopping_data_tree = proto_item_add_subtree(tsch_channel_hopping_data_item, ett_ieee802154_mlme_payload);
proto_tree_add_bitmask(tsch_channel_hopping_data_tree, tvb, *offset, hf_ieee802154_psie_long, ett_ieee802154_psie_long_bitmap, fields_long, ENC_LITTLE_ENDIAN);
*offset += 2;
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_channel_hopping */
/**
* Subdissector for the Payload Information Element MLME TSCH Synchronization
*
* @param tvb pointer to buffer containing raw packet.
* @param tree 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 *tree, int *offset, guint psie_remaining)
{
proto_item *tsch_sync_data_item = NULL;
proto_tree *tsch_sync_data_tree = NULL;
tsch_sync_data_item = proto_tree_add_item(tree, hf_ieee802154_tsch_sync, tvb, *offset, 2 + psie_remaining, ENC_NA);
tsch_sync_data_tree = proto_item_add_subtree(tsch_sync_data_item, ett_ieee802154_tsch_synch);
proto_tree_add_bitmask(tsch_sync_data_tree, tvb, *offset, hf_ieee802154_psie_short, ett_ieee802154_psie_short_bitmap, header_short_format_nested_ie, ENC_LITTLE_ENDIAN);
*offset += 2;
proto_tree_add_item(tsch_sync_data_tree, hf_ieee802154_tsch_asn, tvb, (*offset), 5, ENC_LITTLE_ENDIAN);
*offset += 5;
proto_tree_add_item(tsch_sync_data_tree, hf_ieee802154_tsch_join_metric, tvb, (*offset), 1, ENC_LITTLE_ENDIAN);
*offset += 1;
}/* dissect_802154_tsch_time_sync*/
/**
* Subdissector for the Payload Information Element MLME TSCH Slotframe and Link
*
* @param tvb pointer to buffer containing raw packet.
* @param tree 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_slotframe_link(tvbuff_t *tvb, proto_tree *tree, guint16 psie_remaining, guint16 psie_id,
guint *offset)
{
guint8 nb_slotframes;
guint8 nb_slotframes_aux;
guint8 nb_links;
guint8 nb_links_aux;
guint8 slotframe_index;
proto_item *tsch_slotframe_item;
proto_tree *tsch_slotframe_tree;
proto_item *tsch_slotframe_list_item;
proto_tree *tsch_slotframe_list_tree;
proto_item *tsch_slotframe_data_item;
proto_tree *tsch_slotframe_data_tree;
tsch_slotframe_item = proto_tree_add_item(tree, hf_ieee802154_tsch_slotframe, tvb, *offset, 2+ psie_remaining, ENC_NA);
tsch_slotframe_tree = proto_item_add_subtree(tsch_slotframe_item, ett_ieee802154_psie_slotframe_link_slotframes);
proto_tree_add_bitmask(tsch_slotframe_tree, tvb, *offset, hf_ieee802154_psie_short, ett_ieee802154_psie_short_bitmap, header_short_format_nested_ie, ENC_LITTLE_ENDIAN);
proto_item_set_text(tsch_slotframe_tree, "%s", val_to_str_const(psie_id, ieee802154_psie_names, "Unknown IE"));
*offset += 2;
nb_slotframes = tvb_get_guint8(tvb, *offset);
nb_slotframes_aux = nb_slotframes;
proto_tree_add_item(tsch_slotframe_tree, 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;
tsch_slotframe_list_item = proto_tree_add_none_format(tsch_slotframe_tree, hf_ieee802154_tsch_slotframe_list, tvb, *offset, 4 + 5 * nb_links_aux, "Slotframes [%u]", slotframe_index);
tsch_slotframe_list_tree = proto_item_add_subtree(tsch_slotframe_list_item, ett_ieee802154_psie_slotframe_link_slotframes);
slotframe_index += 1;
proto_tree_add_item(tsch_slotframe_list_tree, hf_ieee802154_tsch_slotf_link_slotf_handle, tvb, (*offset), 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(tsch_slotframe_list_tree, hf_ieee802154_tsch_slotf_size, tvb, (*offset) + 1, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(tsch_slotframe_list_tree, 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) {
tsch_slotframe_data_item = proto_tree_add_item(tsch_slotframe_list_tree, hf_ieee802154_tsch_link_info, tvb, *offset, 5, ENC_NA);
tsch_slotframe_data_tree = proto_item_add_subtree(tsch_slotframe_data_item, ett_ieee802154_mlme_payload_data);
proto_tree_add_item(tsch_slotframe_data_tree, hf_ieee802154_tsch_slotf_link_timeslot, tvb, (*offset), 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(tsch_slotframe_data_tree, hf_ieee802154_tsch_slotf_link_channel_offset, tvb, (*offset) + 2, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(tsch_slotframe_data_tree, hf_ieee802154_tsch_slotf_link_options, tvb, (*offset) + 4, 1, ENC_LITTLE_ENDIAN);
nb_links_aux -= 1;
*offset += 5;
}
}
}/* dissect_802154_tsch_slotframe_link */
/**
* Subdissector for the 6TOP Protocol contained within the Payload Information Elements.
*/
static int
dissect_ietf_ie(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *ies_tree, void *data _U_)
{
const guint8 supported_6p_version = 0x00;
proto_tree *p_inf_elem_tree = create_payload_ie_tree(tvb, ies_tree, hf_ieee802154_pie_ietf, ett_ieee802154_pie_ietf,
IEEE802154_PAYLOAD_IE_IETF, NULL);
guint offset = 2;
guint pie_length = tvb_reported_length(tvb) - 2;
guint8 subie;
guint8 version;
guint8 type;
guint8 code;
guint8 num_cells;
gboolean have_cell_list = FALSE;
int i;
proto_item *sixtop_item = NULL;
proto_tree *sixtop_tree = NULL;
proto_item *cell_list_item = NULL;
proto_tree *cell_list_tree = NULL;
proto_item *cell_item = 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 + 2;
}
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 + 2;
}
type = (tvb_get_guint8(tvb, offset + 1) & IETF_6TOP_TYPE) >> 4;
code = tvb_get_guint8(tvb, offset + 2);
proto_tree_add_item(p_inf_elem_tree, hf_ieee802154_p_ie_ietf_sub_id, tvb, offset, 1, ENC_LITTLE_ENDIAN);
sixtop_item = proto_tree_add_item(p_inf_elem_tree, hf_ieee802154_6top, tvb, offset, pie_length, ENC_NA);
sixtop_tree = proto_item_add_subtree(sixtop_item, ett_ieee802154_p_ie_6top);
proto_tree_add_item(sixtop_tree, hf_ieee802154_6top_version, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
type_item = proto_tree_add_item(sixtop_tree, hf_ieee802154_6top_type, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(sixtop_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);
proto_tree_add_item(sixtop_tree, hf_ieee802154_6top_seqnum, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(sixtop_tree, hf_ieee802154_6top_gen, 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:
case IETF_6TOP_CMD_RELOCATE:
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);
num_cells = tvb_get_guint8(tvb, offset + 3);
pie_length -= 4;
offset += 4;
if (pie_length > 0 && (pie_length % 4) == 0) {
have_cell_list = TRUE;
}
break;
case IETF_6TOP_CMD_COUNT:
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 == 2) {
proto_tree_add_item(sixtop_tree, hf_ieee802154_6top_total_num_cells, tvb, offset, 2, ENC_LITTLE_ENDIAN);
pie_length -= 2;
offset += 2;
} else if (pie_length > 0 && (pie_length % 4) == 0) {
have_cell_list = TRUE;
}
}
break;
case IETF_6TOP_RC_EOL:
if(pie_length > 0 && (pie_length % 4) == 0) {
have_cell_list = TRUE;
}
break;
case IETF_6TOP_RC_ERROR:
case IETF_6TOP_RC_RESET:
case IETF_6TOP_RC_VER_ERR:
case IETF_6TOP_RC_SFID_ERR:
case IETF_6TOP_RC_GEN_ERR:
case IETF_6TOP_RC_BUSY:
case IETF_6TOP_RC_NORES:
case IETF_6TOP_RC_CELLLIST_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) {
if (type == IETF_6TOP_TYPE_REQUEST && code == IETF_6TOP_CMD_RELOCATE) {
cell_list_item = proto_tree_add_item(sixtop_tree, hf_ieee802154_6top_rel_cell_list, tvb, offset, pie_length, ENC_NA);
cell_list_tree = proto_item_add_subtree(cell_list_item, ett_ieee802154_p_ie_6top_rel_cell_list);
/* num_cells is expected to be set properly */
for (i = 0; i < num_cells; offset += 4, i++) {
cell_item = proto_tree_add_item(cell_list_tree, hf_ieee802154_6top_cell, tvb, offset, 4, ENC_NA);
cell_tree = proto_item_add_subtree(cell_item, ett_ieee802154_p_ie_6top_cell);
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);
}
pie_length -= num_cells * 4;
cell_list_item = proto_tree_add_item(sixtop_tree, hf_ieee802154_6top_cand_cell_list, tvb, offset, pie_length, ENC_NA);
cell_list_tree = proto_item_add_subtree(cell_list_item, ett_ieee802154_p_ie_6top_cand_cell_list);
for (i = 0; pie_length > 0; pie_length -= 4, offset += 4, i++) {
cell_item = proto_tree_add_item(cell_list_tree, hf_ieee802154_6top_cell, tvb, offset, 4, ENC_NA);
cell_tree = proto_item_add_subtree(cell_item, ett_ieee802154_p_ie_6top_cell);
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);
}
} else {
cell_list_item = proto_tree_add_item(sixtop_tree, hf_ieee802154_6top_cell_list, tvb, offset, pie_length, ENC_NA);
cell_list_tree = proto_item_add_subtree(cell_list_item, ett_ieee802154_p_ie_6top_cell_list);
for (i = 0; pie_length > 0; pie_length -= 4, offset += 4, i++) {
cell_item = proto_tree_add_item(cell_list_tree, hf_ieee802154_6top_cell, tvb, offset, 4, ENC_NA);
cell_tree = proto_item_add_subtree(cell_item, ett_ieee802154_p_ie_6top_cell);
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;
} /* dissect_ieee802154_6top */
/**
* Subdissector 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 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 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.
* @param 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 */
/*
* Header IEs
*/
/**
* Create a tree for a Header IE incl. the TLV header and append the IE name to the parent item
*
* @param tvb the tv buffer
* @param tree the tree to append this item to
* @param hf field index
* @param ett tree index
* @param id the IE ID used to append the IE name to the parent item of tree
* @param new_item if != NULL, pointer to store the item created for this Header IE
* @returns the tree created for the Header IE
*/
static proto_tree*
create_header_ie_tree(tvbuff_t *tvb, proto_tree *tree, int hf, gint ett, guint16 id, proto_item** new_item)
{
proto_item *subitem;
proto_tree *subtree;
static const int * tlv_fields[] = {
&hf_ieee802154_header_ie_type,
&hf_ieee802154_header_ie_id,
&hf_ieee802154_header_ie_length,
NULL
};
subitem = proto_tree_add_item(tree, hf, tvb, 0, tvb_reported_length(tvb), ENC_NA);
subtree = proto_item_add_subtree(subitem, ett);
proto_tree_add_bitmask_with_flags(subtree, tvb, 0, hf_ieee802154_header_ie_tlv, ett_ieee802154_header_ie_tlv,
tlv_fields, ENC_LITTLE_ENDIAN, BMT_NO_FLAGS);
const char *name = try_val_to_str(id, ieee802154_header_ie_names);
if (name) {
proto_item_append_text(proto_tree_get_parent(tree), ", %s", name);
} else {
proto_item_append_text(proto_tree_get_parent(tree), ", Unknown IE 0x%02x", id);
proto_item_append_text(subitem, ": 0x%02x", id);
}
if (new_item) {
*new_item = subitem;
}
return subtree;
}
/*
* The dissectors for the individual Header IEs
* They are called via call_dissector with the tvb including the IE header and data as ieee802154_packet
*/
/**
* Dissect the CSL IE (7.4.2.3)
*/
static int
dissect_hie_csl(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
{
proto_tree *subtree = create_header_ie_tree(tvb, tree, hf_ieee802154_hie_csl, ett_ieee802154_hie_csl, IEEE802154_HEADER_IE_CSL, NULL);
proto_tree_add_item(subtree, hf_ieee802154_hie_csl_phase, tvb, 2, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(subtree, hf_ieee802154_hie_csl_period, tvb, 4, 2, ENC_LITTLE_ENDIAN);
if (tvb_reported_length(tvb) >= 8) {
proto_tree_add_item(subtree, hf_ieee802154_hie_csl_rendezvous_time, tvb, 6, 2, ENC_LITTLE_ENDIAN);
return 2 + 6;
}
return 2 + 4;
}
/**
* Dissect the Time Correction Header IE (7.4.2.7)
*
* 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.
*/
static int
dissect_hie_time_correction(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *ies_tree, void *data _U_)
{
static const int * fields[] = {
&hf_ieee802154_hie_time_correction_value,
&hf_ieee802154_nack,
NULL
};
proto_item *subitem;
proto_tree *tree = create_header_ie_tree(tvb, ies_tree, hf_ieee802154_hie_time_correction, ett_ieee802154_hie_time_correction,
IEEE802154_HEADER_IE_TIME_CORR, &subitem);
guint16 time_sync_value = tvb_get_letohs(tvb, 2);
proto_tree_add_bitmask_with_flags(tree, tvb, 2, hf_ieee802154_hie_time_correction_time_sync_info, ett_ieee802154_header_ie,
fields, ENC_LITTLE_ENDIAN, BMT_NO_FLAGS);
if (time_sync_value & ~(0x8fff)) {
expert_add_info(pinfo, subitem, &ei_ieee802154_time_correction_error);
}
if (time_sync_value & 0x8000) {
proto_item_append_text(proto_tree_get_parent(ies_tree), ": NACK");
}
return 2 + 2;
}
/**
* 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.
*
* @param tvb the tv buffer
* @param pinfo pointer to packet information fields.
* @param tree the tree to append this item to
* @param orig_offset offset into the tvbuff to begin dissection.
* @param packet IEEE 802.15.4 packet information.
*/
static int
dissect_ieee802154_header_ie(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint orig_offset, ieee802154_packet *packet)
{
// GCC emits a spurious -Wclobbered if offset is used as function parameter (even with volatile)
volatile guint offset = orig_offset;
proto_item *ies_item = proto_tree_add_item(tree, hf_ieee802154_header_ies, tvb, offset, -1, ENC_NA);
proto_tree *ies_tree = proto_item_add_subtree(ies_item, ett_ieee802154_header_ie);
do {
volatile int consumed = 0;
guint16 ie_header = tvb_get_letohs(tvb, offset);
guint16 id = (guint16) ((ie_header & IEEE802154_HEADER_IE_ID_MASK) >> 7);
guint16 length = (guint16) (ie_header & IEEE802154_HEADER_IE_LENGTH_MASK);
tvbuff_t *ie_tvb = tvb_new_subset_length(tvb, offset, 2 + length);
if (id == IEEE802154_HEADER_IE_HT1 || id == IEEE802154_HEADER_IE_HT2) {
create_header_ie_tree(ie_tvb, ies_tree, id == IEEE802154_HEADER_IE_HT1 ? hf_ieee802154_hie_ht1 : hf_ieee802154_hie_ht2,
ett_ieee802154_hie_ht, id, NULL);
consumed = 2;
} else {
TRY {
consumed = dissector_try_uint_new(header_ie_dissector_table, id, ie_tvb, pinfo, ies_tree, FALSE, packet);
if (consumed == 0) {
proto_item *subitem;
proto_tree *subtree = create_header_ie_tree(ie_tvb, ies_tree, hf_ieee802154_hie_unsupported,
ett_ieee802154_hie_unsupported, id, &subitem);
proto_tree_add_item(subtree, hf_ieee802154_ie_unknown_content, ie_tvb, 2, length, ENC_NA);
consumed = 2 + length;
expert_add_info(pinfo, subitem, &ei_ieee802154_ie_unsupported_id);
}
}
CATCH_ALL {
show_exception(tvb, pinfo, ies_tree, EXCEPT_CODE, GET_MESSAGE);
consumed = 2 + length;
}
ENDTRY;
}
if (consumed < 2 + length) {
proto_tree_add_item(ies_tree, hf_ieee802154_ie_unknown_content, ie_tvb, consumed, 2 + length - consumed, ENC_NA);
expert_add_info(pinfo, ies_item, &ei_ieee802154_ie_unknown_extra_content);
}
offset += 2 + length;
if (id == IEEE802154_HEADER_IE_HT1 || id == IEEE802154_HEADER_IE_HT2) {
packet->payload_ie_present = id == IEEE802154_HEADER_IE_HT1;
break;
}
} while ((tvb_reported_length_remaining(tvb, offset) > IEEE802154_MIC_LENGTH(packet->security_level) + IEEE802154_FCS_LEN + 1));
proto_item_set_len(ies_item, offset - orig_offset);
return offset - orig_offset;
}
/**
* Subdissector for MAC Layer Management Entitiy (MLME) Payload Sub IEs
*
* Reference: IEEE 802.15.4-2015: 7.4.3.2 MLME IE
*
* @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)
{
guint16 psie_ie;
guint16 psie_id;
guint psie_remaining = 0;
int orig_offset = offset;
psie_ie = tvb_get_letohs(tvb, offset);
if (psie_ie & IEEE802154_PSIE_TYPE_MASK) {
/* long format: Table 7-17-Sub-ID allocation for long format */
psie_id = (guint16) ((psie_ie & IEEE802154_PSIE_ID_MASK_LONG) >> 11);
psie_remaining = (guint) (psie_ie & IEEE802154_PSIE_LENGTH_MASK_LONG);
}
else {
/* short format: Table 7-16-Sub-ID allocation for short format */
psie_id = (guint16) ((psie_ie & IEEE802154_PSIE_ID_MASK_SHORT) >> 8);
psie_remaining = (guint) (psie_ie & IEEE802154_PSIE_LENGTH_MASK_SHORT);
}
switch (psie_id) {
case IEEE802154_MLME_SUBIE_TSCH_SYNCH:
// 7.4.4.2 TSCH Synchronization IE
dissect_802154_tsch_time_sync(tvb, tree, &offset, psie_remaining);
break;
case IEEE802154_MLME_SUBIE_TSCH_SLOTFR_LINK:
// 7.4.4.3 TSCH Slotframe and Link IE
dissect_802154_tsch_slotframe_link(tvb, tree, psie_remaining, psie_id, &offset);
break;
case IEEE802154_MLME_SUBIE_TSCH_TIMESLOT:
// 7.4.4.4 TSCH Timeslot IE
dissect_802154_tsch_timeslot(tvb, tree, psie_remaining, psie_id, &offset);
break;
case IEEE802154_MLME_SUBIE_ENHANCED_BEACON_FILTER:
// 7.4.4.6 Enhanced Beacon Filter IE
dissect_802154_enhanced_beacon_filter(tvb, tree, psie_remaining, &offset);
break;
case IEEE802154_MLME_SUBIE_CHANNEL_HOPPING:
// 7.4.4.31 Channel hopping IE
dissect_802154_channel_hopping(tvb, tree, psie_remaining, &offset);
break;
case IEEE802154_MLME_SUBIE_HOPPING_TIMING:
// 7.4.4.5 Hopping timing IE
// TODO
case IEEE802154_MLME_SUBIE_MAC_METRICS:
// 7.4.4.7 MAC Metrics IE
// TODO
case IEEE802154_MLME_SUBIE_ALL_MAC_METRICS:
// 7.4.4.8 All MAC Metrics IE
// TODO
case IEEE802154_MLME_SUBIE_COEXISTENCE_SPEC:
// 7.4.4.9 Coexistence Specification IE
// TODO
case IEEE802154_MLME_SUBIE_SUN_DEVICE_CAPABILITIES:
// 7.4.4.10 SUN Device Capabilities IE
// TODO
case IEEE802154_MLME_SUBIE_SUN_FSK_GEN_PHY:
// 7.4.4.11 SUN FSK Generic PHY IE
// TODO
case IEEE802154_MLME_SUBIE_MODE_SWITCH_PARAMETER:
// 7.4.4.12 Mode Switch Parameter IE
// TODO
case IEEE802154_MLME_SUBIE_PHY_PARAMETER_CHANGE:
// 7.4.4.13 PHY Parameter Change IE
// TODO
case IEEE802154_MLME_SUBIE_O_QPSK_PHY_MODE:
// 7.4.4.14 O-QPSK PHY Mode IE
// TODO
case IEEE802154_MLME_SUBIE_PCA_ALLOCATION:
// 7.4.4.15 PCA Allocation IE
// TODO
case IEEE802154_MLME_SUBIE_DSSS_OPER_MODE:
// 7.4.4.16 LECIM DSSS Operating Mode IE
// TODO
case IEEE802154_MLME_SUBIE_FSK_OPER_MODE:
// 7.4.4.17 LECIM FSK Operating Mode IE
// TODO
case IEEE802154_MLME_SUBIE_TVWS_PHY_OPE_MODE:
// 7.4.4.18 TVWS PHY Operating Mode Description IE
// TODO
case IEEE802154_MLME_SUBIE_TVWS_DEVICE_CAPAB:
// 7.4.4.19 TVWS Device Capabilities IE
// TODO
case IEEE802154_MLME_SUBIE_TVWS_DEVICE_CATEG:
// 7.4.4.20 TVWS Device Category IE
// TODO
case IEEE802154_MLME_SUBIE_TVWS_DEVICE_IDENTIF:
// 7.4.4.21 TVWS Device Identification IE
// TODO
case IEEE802154_MLME_SUBIE_TVWS_DEVICE_LOCATION:
// 7.4.4.22 TVWS Device Location IE
// TODO
case IEEE802154_MLME_SUBIE_TVWS_CH_INFOR_QUERY:
// 7.4.4.23 TVWS Channel Information Query IE
// TODO
case IEEE802154_MLME_SUBIE_TVWS_CH_INFOR_SOURCE:
// 7.4.4.24 TVWS Channel Information Source IE
// TODO
case IEEE802154_MLME_SUBIE_CTM:
// 7.4.4.25 CTM IE
// TODO
case IEEE802154_MLME_SUBIE_TIMESTAMP:
// 7.4.4.26 Timestamp IE
// TODO
case IEEE802154_MLME_SUBIE_TIMESTAMP_DIFF:
// 7.4.4.27 Timestamp Difference IE
// TODO
case IEEE802154_MLME_SUBIE_TMCP_SPECIFICATION:
// 7.4.4.28 TMCTP Specification IE
// TODO
case IEEE802154_MLME_SUBIE_RCC_PHY_OPER_MODE:
// 7.4.4.29 RCC PHY Operating Mode IE
// TODO
default:
offset += 2;
if (psie_remaining) {
proto_tree_add_item(tree, hf_ieee802154_mlme_ie_data, tvb, offset, psie_remaining, ENC_NA);
expert_add_info(pinfo, tree, &ei_ieee802154_ie_unsupported_id);
offset += psie_remaining;
}
break;
}
return (offset - orig_offset);
}
/**
* Subdissector for MAC Layer Management Entitiy (MLME) Payload Sub IEs
*
* Reference: IEEE 802.15.4-2015 - 7.4.4.4 TSCH Timeslot IE
*/
static void
dissect_802154_tsch_timeslot(tvbuff_t *tvb, proto_tree *tree, guint psie_remaining, guint16 psie_id, int *offset)
{
proto_tree * timeslot_tree;
proto_item * timeslot_item;
timeslot_item = proto_tree_add_item(tree, hf_ieee802154_timeslot_ie, tvb, *offset, 2 + psie_remaining, ENC_NA);
timeslot_tree = proto_item_add_subtree(timeslot_item, ett_ieee802154_tsch_timeslot);
proto_tree_add_bitmask(timeslot_tree, tvb, *offset, hf_ieee802154_payload_ie_tlv, ett_ieee802154_psie_short_bitmap,
header_short_format_nested_ie, ENC_LITTLE_ENDIAN);
proto_item_set_text(timeslot_tree, "%s", val_to_str_const(psie_id, ieee802154_psie_names, "Unknown IE"));
*offset += 2;
if (psie_remaining) {
proto_tree_add_item(timeslot_tree, hf_ieee802154_mlme_ie_data, tvb, *offset, psie_remaining, ENC_NA);
*offset += psie_remaining;
}
}
static void
dissect_802154_enhanced_beacon_filter(tvbuff_t *tvb, proto_tree *tree, guint16 psie_remaining, gint *offset)
{
guint8 filter;
guint8 attr_len;
guint32 attr_bitmap = 0;
proto_item *item;
proto_tree *subtree;
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
};
item = proto_tree_add_item(tree, hf_ieee802154_enhanced_beacon_filter_ie, tvb, *offset, 2 + psie_remaining, ENC_NA);
subtree = proto_item_add_subtree(item, ett_ieee802154_tsch_synch);
proto_tree_add_bitmask(subtree, tvb, *offset, hf_ieee802154_psie_short, ett_ieee802154_psie_short_bitmap, header_short_format_nested_ie, ENC_LITTLE_ENDIAN);
*offset += 2;
filter = tvb_get_guint8(tvb, *offset);
proto_tree_add_bitmask(subtree, tvb, (const guint) *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) {
/* just display in hex until we know how to decode */
proto_tree_add_item(subtree, hf_ieee802154_psie_eb_filter_attr_id_bitmap, tvb, *offset, attr_len, attr_bitmap);
*offset += attr_len;
}
}
/**
* Subdissector for MLME IEs
*/
static int
dissect_pie_mlme(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *ies_tree, void *data _U_)
{
proto_tree *tree = create_payload_ie_tree(tvb, ies_tree, hf_ieee802154_mlme, ett_ieee802154_mlme,
IEEE802154_PAYLOAD_IE_MLME, NULL);
guint offset = 2;
while (tvb_reported_length_remaining(tvb, offset) > 1) {
offset += dissect_ieee802154_payload_mlme_sub_ie(tvb, pinfo, tree, offset);
}
return offset;
}
/**
* Subdissector for MPX IEs (IEEE 802.15.9)
*/
static int
dissect_mpx_ie(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *ies_tree, void *data _U_)
{
static const int * fields[] = {
&hf_ieee802159_mpx_transaction_id,
&hf_ieee802159_mpx_transfer_type,
NULL
};
static const int * fields_compressed_multiplex_id[] = {
&hf_ieee802159_mpx_transaction_id_as_multiplex_id,
&hf_ieee802159_mpx_transfer_type,
NULL
};
proto_tree *tree = create_payload_ie_tree(tvb, ies_tree, hf_ieee802159_mpx, ett_ieee802159_mpx, IEEE802154_PAYLOAD_IE_MPX, NULL);
guint offset = 2;
guint8 transaction_control = tvb_get_guint8(tvb, offset);
guint8 transfer_type = (guint8) (transaction_control & IEEE802159_MPX_TRANSFER_TYPE_MASK);
guint8 transaction_id = (guint8) ((transaction_control & IEEE802159_MPX_TRANSACTION_ID_MASK) >> IEEE802159_MPX_TRANSACTION_ID_SHIFT);
gint32 multiplex_id = -1;
guint8 fragment_number;
if (transfer_type == IEEE802159_MPX_FULL_FRAME_NO_MUXID) {
proto_tree_add_bitmask_with_flags(tree, tvb, offset, hf_ieee802159_mpx_transaction_control, ett_ieee802159_mpx_transaction_control,
fields_compressed_multiplex_id, ENC_LITTLE_ENDIAN, BMT_NO_FLAGS);
multiplex_id = transaction_id;
} else {
proto_tree_add_bitmask_with_flags(tree, tvb, offset, hf_ieee802159_mpx_transaction_control, ett_ieee802159_mpx_transaction_control,
fields, ENC_LITTLE_ENDIAN, BMT_NO_FLAGS);
}
offset += 1;
switch (transfer_type) { // cf. IEEE 802.15.9 Table 18 - Summary of different MPX IE formats
case IEEE802159_MPX_FULL_FRAME:
proto_tree_add_item(tree, hf_ieee802159_mpx_multiplex_id, tvb, offset, 2, ENC_LITTLE_ENDIAN);
multiplex_id = tvb_get_letohs(tvb, offset);
offset += 2;
break;
case IEEE802159_MPX_FULL_FRAME_NO_MUXID:
break; // nothing to do
case IEEE802159_MPX_NON_LAST_FRAGMENT:
fragment_number = tvb_get_guint8(tvb, offset);
proto_tree_add_item(tree, hf_ieee802159_mpx_fragment_number, tvb, offset, 1, ENC_LITTLE_ENDIAN);
offset += 1;
if (fragment_number == 0) {
proto_tree_add_item(tree, hf_ieee802159_mpx_total_frame_size, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
multiplex_id = tvb_get_letohs(tvb, offset);
proto_tree_add_item(tree, hf_ieee802159_mpx_multiplex_id, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
}
break;
case IEEE802159_MPX_LAST_FRAGMENT:
proto_tree_add_item(tree, hf_ieee802159_mpx_fragment_number, tvb, offset, 1, ENC_LITTLE_ENDIAN);
offset += 1;
break;
case IEEE802159_MPX_ABORT:
if (tvb_reported_length_remaining(tvb, offset) == 2) {
proto_tree_add_item(tree, hf_ieee802159_mpx_total_frame_size, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
}
return offset;
default: // reserved values -> warning and return
expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_ieee802159_mpx_invalid_transfer_type);
return offset;
}
// TODO: reassembly
dissector_handle_t dissector = NULL;
if (multiplex_id == IEEE802159_MPX_MULTIPLEX_ID_KMP) {
guint8 kmp_id = tvb_get_guint8(tvb, offset);
proto_tree_add_item(tree, hf_ieee802159_mpx_kmp_id, tvb, offset, 1, ENC_LITTLE_ENDIAN);
offset += 1;
switch (kmp_id) {
case IEEE802159_MPX_KMP_ID_IEEE8021X:
case IEEE802159_MPX_KMP_ID_IEEE80211_4WH:
case IEEE802159_MPX_KMP_ID_IEEE80211_GKH:
dissector = eapol_handle;
break;
// TODO
case IEEE802159_MPX_KMP_ID_HIP:
case IEEE802159_MPX_KMP_ID_IKEV2:
case IEEE802159_MPX_KMP_ID_PANA:
case IEEE802159_MPX_KMP_ID_DRAGONFLY:
case IEEE802159_MPX_KMP_ID_ETSI_TS_102_887_2:
expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_ieee802159_mpx_unsupported_kmp);
break;
case IEEE802159_MPX_KMP_ID_VENDOR_SPECIFIC:
proto_tree_add_item(tree, hf_ieee802159_mpx_kmp_vendor_oui, tvb, offset, 3, ENC_BIG_ENDIAN);
offset += 3;
break;
// Unknown
default:
expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_ieee802159_mpx_unknown_kmp);
}
}
if (transfer_type == IEEE802159_MPX_FULL_FRAME || transfer_type == IEEE802159_MPX_FULL_FRAME_NO_MUXID) {
tvbuff_t * payload = tvb_new_subset_remaining(tvb, offset);
if (multiplex_id > 1500) {
dissector = dissector_get_uint_handle(ethertype_table, (guint)multiplex_id);
}
if (dissector) {
call_dissector(dissector, payload, pinfo, proto_tree_get_root(tree)); // exceptions are caught in our caller
} else {
call_data_dissector(payload, pinfo, proto_tree_get_root(tree));
}
} else {
proto_tree_add_item(tree, hf_ieee802159_mpx_fragment, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_NA);
}
offset = tvb_reported_length(tvb);
return offset;
}
/**
* Subdissector for Vendor Specific Payload IEs (Information Elements)
*/
static int
dissect_pie_vendor(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *ies_tree, void *data _U_)
{
proto_tree *tree = create_payload_ie_tree(tvb, ies_tree, hf_ieee802154_pie_vendor, ett_ieee802154_pie_vendor,
IEEE802154_PAYLOAD_IE_VENDOR, NULL);
guint offset = 2;
guint pie_length = tvb_reported_length(tvb) - 2;
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 tvb_reported_length(tvb);
}
/**
* Subdissector for Payload IEs (Information Elements)
*
* @param tvb the tv buffer
* @param pinfo pointer to packet information fields.
* @param tree the tree to append this item to
* @param orig_offset offset into the tvbuff to begin dissection.
* @param packet IEEE 802.15.4 packet information.
*/
static int
dissect_ieee802154_payload_ie(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint orig_offset, ieee802154_packet *packet)
{
// GCC emits a spurious -Wclobbered if offset is used as function parameter (even with volatile)
volatile guint offset = orig_offset;
proto_item *ies_item = proto_tree_add_item(tree, hf_ieee802154_payload_ies, tvb, offset, -1, ENC_NA);
proto_tree *ies_tree = proto_item_add_subtree(ies_item, ett_ieee802154_payload_ie);
do {
volatile int consumed = 0;
guint16 ie_header = tvb_get_letohs(tvb, offset);
guint16 id = (guint16) ((ie_header & IEEE802154_PAYLOAD_IE_ID_MASK) >> 11);
guint16 length = (guint16) (ie_header & IEEE802154_PAYLOAD_IE_LENGTH_MASK);
tvbuff_t *ie_tvb = tvb_new_subset_length(tvb, offset, 2 + length);
if (id == IEEE802154_PAYLOAD_IE_TERMINATION) {
create_payload_ie_tree(ie_tvb, ies_tree, hf_ieee802154_pie_termination, ett_ieee802154_pie_termination, id, NULL);
consumed = 2;
} else {
TRY {
consumed = dissector_try_uint_new(payload_ie_dissector_table, id, ie_tvb, pinfo, ies_tree, FALSE, packet);
if (consumed == 0) {
proto_item *subitem;
proto_tree *subtree = create_payload_ie_tree(ie_tvb, ies_tree, hf_ieee802154_pie_unsupported,
ett_ieee802154_pie_unsupported, id, &subitem);
proto_tree_add_item(subtree, hf_ieee802154_ie_unknown_content, ie_tvb, 2, length, ENC_NA);
consumed = 2 + length;
expert_add_info(pinfo, subitem, &ei_ieee802154_ie_unsupported_id);
}
}
CATCH_ALL {
show_exception(tvb, pinfo, ies_tree, EXCEPT_CODE, GET_MESSAGE);
consumed = 2 + length;
}
ENDTRY;
}
if (consumed < 2 + length) {
proto_tree_add_item(ies_tree, hf_ieee802154_ie_unknown_content, ie_tvb, consumed, 2 + length - consumed, ENC_NA);
expert_add_info(pinfo, ies_item, &ei_ieee802154_ie_unknown_extra_content);
}
offset += 2 + length;
if (id == IEEE802154_PAYLOAD_IE_TERMINATION) {
break;
}
} while (tvb_reported_length_remaining(tvb, offset) > 1);
proto_item_set_len(ies_item, offset - orig_offset);
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;
/* 802.15.4-2015 TSCH mode with frame counter suppression is not supported yet */
if (packet->frame_counter_suppression) {
*payload_info->status = DECRYPT_FRAME_COUNTER_SUPPRESSION_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 }},
/* Information Elements */
{ &hf_ieee802154_ie_unknown_content,
{ "Unknown Content", "wpan.ie.unknown_content", FT_BYTES, SEP_SPACE, NULL, 0x0,
NULL, HFILL }},
/* Header IE */
{ &hf_ieee802154_header_ies,
{ "Header IEs", "wpan.header_ie", FT_NONE, BASE_NONE, NULL,
0x0, NULL, HFILL }},
{ &hf_ieee802154_header_ie_tlv,
{ "IE Header", "wpan.header_ie_tlv", 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 }},
/* Individual Header IEs */
{ &hf_ieee802154_hie_unsupported,
{ "Unsupported Header IE", "wpan.header_ie.unsupported", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_hie_ht1,
{ "Header Termination 1 IE (Payload IEs follow)", "wpan.header_ie.ht1", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_hie_ht2,
{ "Header Termination 2 IE (Payload follows)", "wpan.header_ie.ht2", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
/* Time correction IE */
{ &hf_ieee802154_hie_time_correction,
{ "Time Correction IE", "wpan.header_ie.time_correction", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_hie_time_correction_time_sync_info,
{ "Time Sync Info", "wpan.header_ie.time_correction.time_sync_info", FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_nack,
{ "Nack", "wpan.nack", FT_BOOLEAN, 16, TFS(&hf_ieee802154_nack_tfs), 0x8000,
NULL, HFILL }},
{ &hf_ieee802154_hie_time_correction_value,
{ "Time Correction", "wpan.header_ie.time_correction.value", FT_INT16, BASE_DEC|BASE_UNIT_STRING, &units_microseconds, 0x0FFF,
"Time correction in microseconds", HFILL }},
/* CSL IE */
{ &hf_ieee802154_hie_csl,
{ "CSL IE", "wpan.header_ie.csl", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_hie_csl_phase,
{ "Phase", "wpan.header_ie.csl.phase", FT_INT16, BASE_DEC, NULL, 0x0,
"CSL Phase in units of 10 symbols", HFILL }},
{ &hf_ieee802154_hie_csl_period,
{ "Period", "wpan.header_ie.csl.period", FT_INT16, BASE_DEC, NULL, 0x0,
"CSL Period in units of 10 symbols", HFILL }},
{ &hf_ieee802154_hie_csl_rendezvous_time,
{ "Rendezvous Time", "wpan.header_ie.csl.rendezvous_time", FT_INT16, BASE_DEC, NULL, 0x0,
"CSL Rendezvous Time in units of 10 symbols", HFILL }},
/* Payload IEs */
{ &hf_ieee802154_payload_ies,
{ "Payload IEs", "wpan.payload_ie", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_ieee802154_payload_ie_tlv,
{ "IE Header", "wpan.payload_ie_tlv", 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 }},
/* Individual Payload IEs */
{ &hf_ieee802154_pie_unsupported,
{ "Unknown Payload IE", "wpan.payload_ie.unknown", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_pie_termination,
{ "Payload Termination IE", "wpan.payload_ie.termination", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_pie_vendor,
{ "Vendor Specific IE", "wpan.payload_ie.vendor", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_mlme,
{ "MLME IE", "wpan.mlme", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_ieee802154_timeslot_ie,
{ "Timeslot IE", "wpan.timeslot", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_ieee802154_enhanced_beacon_filter_ie,
{ "Enhanced Beacon Filter IE", "wpan.enhanced_beacon_filter", FT_NONE, BASE_NONE, NULL, 0x0, 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_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_tsch_asn,
{ "Absolute Slot Number", "wpan.tsch.asn", FT_UINT40, 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.channel_hopping", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_tsch_slotframe,
{ "Slotframe IE", "wpan.tsch.slotframe", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_ieee802154_tsch_slotframe_list,
{ "Slotframe info list", "wpan.tsch.slotframe_list", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_ieee802154_tsch_link_info,
{ "Link Information", "wpan.tsch.link_info", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_ieee802154_tsch_slotf_link_nb_slotf,
{ "Number of Slotframes", "wpan.tsch.slotframe_num", FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_tsch_slotf_link_slotf_handle,
{ "Slotframe handle", "wpan.tsch.slotframe_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_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_pie_ietf,
{ "IETF Payload IE", "wpan.payload_ie.ietf", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &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,
{ "6top IE", "wpan.6top", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &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_gen,
{ "GEN", "wpan.6top_gen", FT_UINT8, BASE_DEC, VALS(ietf_6top_generation_numbers), IETF_6TOP_GEN,
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_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_6top_cell_list,
{ "CellList", "wpan.6top_cell_list", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_6top_rel_cell_list,
{ "Rel. CellList", "wpan.6top_rel_cell_list", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_6top_cand_cell_list,
{ "Cand. CellList", "wpan.6top_cand_cell_list", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }},
{ &hf_ieee802154_6top_cell,
{ "Cell", "wpan.6top_cell", FT_BYTES, BASE_NONE, 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 }},
{ &hf_ieee802154_6top_total_num_cells,
{ "Total Number of Cells", "wpan.6top_total_num_cells", FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
/* MPX IE (IEEE 802.15.9) */
{ &hf_ieee802159_mpx,
{ "MPX IE", "wpan.mpx", FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_ieee802159_mpx_transaction_control,
{ "Transaction Control", "wpan.mpx.transaction_control", FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL }
},
{ &hf_ieee802159_mpx_transfer_type,
{ "Transfer Type", "wpan.mpx.transfer_type", FT_UINT8, BASE_HEX, VALS(mpx_transfer_type_vals), IEEE802159_MPX_TRANSFER_TYPE_MASK,
NULL, HFILL }
},
{ &hf_ieee802159_mpx_transaction_id,
{ "Transaction ID", "wpan.mpx.transaction_id", FT_UINT8, BASE_HEX, NULL, IEEE802159_MPX_TRANSACTION_ID_MASK,
NULL, HFILL }
},
{ &hf_ieee802159_mpx_transaction_id_as_multiplex_id,
{ "Multiplex ID", "wpan.mpx.multiplex_id", FT_UINT8, BASE_HEX, VALS(mpx_multiplex_id_vals), IEEE802159_MPX_TRANSACTION_ID_MASK,
"Transaction ID used as Multiplex ID", HFILL }
},
{ &hf_ieee802159_mpx_fragment_number,
{ "Fragment Number", "wpan.mpx.fragment_number", FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_ieee802159_mpx_total_frame_size,
{ "Total Frame Size", "wpan.mpx.total_frame_size", FT_UINT16, BASE_DEC, NULL, 0x0,
"Total Upper-Layer Frame Size", HFILL }
},
{ &hf_ieee802159_mpx_multiplex_id,
{ "Multiplex ID", "wpan.mpx.multiplex_id", FT_UINT16, BASE_HEX, VALS(etype_vals), 0x0,
NULL, HFILL }
},
{ &hf_ieee802159_mpx_kmp_id,
{ "KMP ID", "wpan.mpx.kmp.id", FT_UINT8, BASE_DEC, VALS(mpx_kmp_id_vals), 0x0,
NULL, HFILL }
},
{ &hf_ieee802159_mpx_kmp_vendor_oui,
{ "Vendor OUI", "wpan.mpx.kmp.vendor_oui", FT_UINT24, BASE_HEX, VALS(oui_vals), 0x0,
NULL, HFILL }
},
{ &hf_ieee802159_mpx_fragment,
{ "Upper-Layer Frame Fragment", "wpan.mpx.fragment", FT_BYTES, SEP_SPACE, 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_aux_sec_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_aux_sec_security_control,
{ "Security Control Field", "wpan.aux_sec.security_control_field", FT_UINT8, BASE_HEX, NULL,
0x0, NULL, HFILL }},
{ &hf_ieee802154_aux_sec_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_frame_counter_suppression,
{ "Frame Counter Suppression", "wpan.aux_sec.frame_counter_suppression", FT_BOOLEAN, 8, NULL,
IEEE802154_AUX_FRAME_COUNTER_SUPPRESSION_MASK,
"Whether the frame counter is omitted from the Auxiliary Security Header", HFILL }},
{ &hf_ieee802154_aux_sec_asn_in_nonce,
{ "ASN in Nonce", "wpan.aux_sec.asn_in_nonce", FT_BOOLEAN, 8, NULL,
IEEE802154_AUX_ASN_IN_NONCE_MASK,
"Whether the ASN is used to generate the nonce instead of the frame counter", HFILL }},
{ &hf_ieee802154_aux_sec_reserved,
{ "Reserved", "wpan.aux_sec.reserved", FT_UINT8, BASE_HEX, NULL, IEEE802154_AUX_CTRL_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 */
{ &hf_zboss_page,
{ "Page", "wpan.zboss.page", FT_UINT8, BASE_DEC_HEX, VALS(zboss_page_names), 0xFE,
"IEEE802.15.4 page number", HFILL } },
{ &hf_zboss_channel,
{ "Channel", "wpan.zboss.channel", FT_UINT8, BASE_DEC, NULL, 0x0,
"Channel number", HFILL }},
{ &hf_zboss_direction,
{ "ZBOSS Direction", "wpan.zboss.direction", FT_UINT8, BASE_HEX, VALS(zboss_direction_names), 0x01,
"ZBOSS Packet Direction", HFILL }},
{ &hf_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_ies,
&ett_ieee802154_header_ie,
&ett_ieee802154_header_ie_tlv,
&ett_ieee802154_hie_unsupported,
&ett_ieee802154_hie_time_correction,
&ett_ieee802154_hie_ht,
&ett_ieee802154_hie_csl,
&ett_ieee802154_payload_ie,
&ett_ieee802154_payload_ie_tlv,
&ett_ieee802154_pie_termination,
&ett_ieee802154_pie_vendor,
&ett_ieee802159_mpx,
&ett_ieee802159_mpx_transaction_control,
&ett_ieee802154_pie_ietf,
&ett_ieee802154_pie_unsupported,
&ett_ieee802154_tsch_timeslot,
&ett_ieee802154_tsch_synch,
&ett_ieee802154_channel_hopping,
&ett_ieee802154_mlme,
&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_cell_options,
&ett_ieee802154_p_ie_6top_cell_list,
&ett_ieee802154_p_ie_6top_rel_cell_list,
&ett_ieee802154_p_ie_6top_cand_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 }},
{ &ei_ieee802154_ie_unsupported_id, { "wpan.ie_unsupported_id", PI_PROTOCOL, PI_WARN,
"Unsupported IE ID", EXPFILL }},
{ &ei_ieee802154_ie_unknown_extra_content, { "wpan.ie_unknown_extra_content", PI_PROTOCOL, PI_WARN,
"Unexpected extra content for IE", EXPFILL }},
{ &ei_ieee802159_mpx_invalid_transfer_type, { "wpan.payload_ie.mpx.invalid_transfer_type", PI_PROTOCOL, PI_WARN,
"Invalid transfer type (cf. IEEE 802.15.9 Table 19)", EXPFILL }},
{ &ei_ieee802159_mpx_unsupported_kmp, { "wpan.payload_ie.mpx.invalid_transfer_type", PI_PROTOCOL, PI_WARN,
"Unsupported KMP ID", EXPFILL }},
{ &ei_ieee802159_mpx_unknown_kmp, { "wpan.payload_ie.mpx.invalid_transfer_type", PI_PROTOCOL, PI_WARN,
"Unknown KMP ID (cf. IEEE 802.15.9 Table 21)", 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 dissector tables for IEs */
header_ie_dissector_table = register_dissector_table(IEEE802154_HEADER_IE_DTABLE, "IEEE 802.15.4 Header IEs", proto_ieee802154, FT_UINT8, BASE_HEX);
payload_ie_dissector_table = register_dissector_table(IEEE802154_PAYLOAD_IE_DTABLE, "IEEE 802.15.4 Payload IEs", proto_ieee802154, FT_UINT8, BASE_HEX);
/* 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);
/* Register internal IE handlers */
dissector_add_uint(IEEE802154_HEADER_IE_DTABLE, IEEE802154_HEADER_IE_TIME_CORR, create_dissector_handle(dissect_hie_time_correction, -1));
dissector_add_uint(IEEE802154_HEADER_IE_DTABLE, IEEE802154_HEADER_IE_CSL, create_dissector_handle(dissect_hie_csl, -1));
dissector_add_uint(IEEE802154_PAYLOAD_IE_DTABLE, IEEE802154_PAYLOAD_IE_MLME, create_dissector_handle(dissect_pie_mlme, -1));
dissector_add_uint(IEEE802154_PAYLOAD_IE_DTABLE, IEEE802154_PAYLOAD_IE_VENDOR, create_dissector_handle(dissect_pie_vendor, -1));
dissector_add_uint(IEEE802154_PAYLOAD_IE_DTABLE, IEEE802154_PAYLOAD_IE_MPX, create_dissector_handle(dissect_mpx_ie, -1));
dissector_add_uint(IEEE802154_PAYLOAD_IE_DTABLE, IEEE802154_PAYLOAD_IE_IETF, create_dissector_handle(dissect_ietf_ie, -1));
/* For the MPX-IE */
ethertype_table = find_dissector_table("ethertype");
eapol_handle = find_dissector("eapol");
} /* 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:
*/