/* packet-ieee802154.c * * Auxiliary Security Header support and * option to force TI CC24xx FCS format * By Jean-Francois Wauthy * Copyright 2009 The University of Namur, Belgium * * IEEE 802.15.4 Dissectors for Wireshark * By Owen Kirby * Copyright 2007 Exegin Technologies Limited * * Wireshark - Network traffic analyzer * By Gerald Combs * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Use libgcrypt for cipher libraries. */ #include #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 = 0; 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> 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= 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; (isrc_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: */