Wireshark-dev: [Wireshark-dev] [PATCH] IEEE 802.15.4 dissectors and libpcap support.
From: Owen Kirby <osk@xxxxxxxxxxxxx>
Date: Fri, 06 Jul 2007 11:00:48 -0700
Wireshark-dev,Following the discussion with Mikko Saarnivala from Sensinode, and Guy Harris, I have revised the IEEE 802.15.4 patch to use a standard pseudo-header. The updated patch has been tested using the Wireshark SVN sources as of yesterday.
This patch adds the dissectors for the IEEE 802.15.4 MAC layer, as well as support for the DLT_IEEE802_15_4 type.
Thanks, Owen Kirby
Index: epan/dissectors/Makefile.common =================================================================== --- epan/dissectors/Makefile.common (revision 22248) +++ epan/dissectors/Makefile.common (working copy) @@ -423,6 +423,7 @@ packet-icq.c \ packet-idp.c \ packet-ieee80211.c \ + packet-ieee802154.c \ packet-ieee8023.c \ packet-ieee802a.c \ packet-ifcp.c \ @@ -875,6 +876,7 @@ packet-iax2.h \ packet-idp.h \ packet-ieee80211.h \ + packet-ieee802154.h \ packet-ieee8023.h \ packet-ieee802a.h \ packet-igap.h \ Index: epan/dissectors/packet-ieee802154.c =================================================================== --- epan/dissectors/packet-ieee802154.c (revision 0) +++ epan/dissectors/packet-ieee802154.c (revision 0) @@ -0,0 +1,1816 @@ +/* packet-ieee802154.c + * + * $Id: $ + * + * IEEE 802.15.4 Dissectors for Wireshark + * By Owen Kirby <osk@xxxxxxxxxx> + * Copyright 2007 Exegin Technologies Limited + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@xxxxxxxxxxxxx> + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *------------------------------------------------------------ + * + * In IEEE 802.15.4 packets, all fields are little endian. And + * Each byte is transmitted least significan bit first. + *------------------------------------------------------------ + * + * 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 value of 0x0000 + * instead of the more common 0xffff. + *------------------------------------------------------------ + * + * 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 CRC. + * - ChipCon/Texas Instruments CC24xx style FCS. + * - No FCS at all. + *------------------------------------------------------------ + * + * No support has been provided for decryption. Maybe a TODO + * item, but this is unlikely as the decryption process requires + * the extended source address, which will not be present most + * of the time. + *------------------------------------------------------------ + */ + +/* Include files */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVEHCONFIG_H */ + +#include <string.h> +#include <stdlib.h> +#include <gmodule.h> +#include <glib.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <epan/emem.h> +#include <epan/packet.h> +#include <epan/prefs.h> +#include <epan/expert.h> +#include <epan/addr_resolv.h> + +#include "packet-ieee802154.h" + +/* Function declarations */ +/* Register Functions. Loads the dissector into Wireshark. */ +void proto_reg_handoff_ieee802154 (void); +void proto_register_ieee802154 (void); + +/* Dissection Routines. */ +void dissect_ieee802154 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); +void dissect_ieee802154_maybefcs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); +void dissect_ieee802154_nofcs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); +void dissect_ieee802154_ccfcs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); +void dissect_ieee802154_common (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); +void dissect_ieee802154_beacon (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); +void dissect_ieee802154_cmd (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); + +/* Helper Functions. */ +guint16 ieee802154_crc16 (tvbuff_t *tvb, guint offset, guint len); +guint16 update_crc_ccitt (guint16 crc, guint8 c); +gchar *print_eui64 (guint64); +gchar *print_eui64_oui (guint64); + +/* Initialize Protocol and Registered fields */ +/* Required for displaying information on Ethereal */ +static int proto_ieee802154 = -1; +static int hf_ieee802154_frame_type = -1; +static int hf_ieee802154_security_enable = -1; +static int hf_ieee802154_frame_pending = -1; +static int hf_ieee802154_ack_request = -1; +static int hf_ieee802154_intra_pan = -1; +static int hf_ieee802154_seqno = -1; +static int hf_ieee802154_src_addr_mode = -1; +static int hf_ieee802154_dst_addr_mode = -1; +static int hf_ieee802154_version = -1; +static int hf_ieee802154_dst_panID = -1; +static int hf_ieee802154_dst_addr16 = -1; +static int hf_ieee802154_dst_addr64 = -1; +static int hf_ieee802154_src_panID = -1; +static int hf_ieee802154_src_addr16 = -1; +static int hf_ieee802154_src_addr64 = -1; +static int hf_ieee802154_crc = -1; +static int hf_ieee802154_rssi = -1; +static int hf_ieee802154_crc_ok = -1; +static int hf_ieee802154_correlation; + +/* Registered fields for Command Packets */ +/* Required for displaying information on Ethereal */ +static int hf_ieee802154_cmd_frm_id = -1; +static int hf_ieee802154_cmd_payload = -1; +static int hf_ieee802154_cmd_cinfo_alt_pan_coord = -1; +static int hf_ieee802154_cmd_cinfo_device_type = -1; +static int hf_ieee802154_cmd_cinfo_power_src = -1; +static int hf_ieee802154_cmd_cinfo_idle_rx = -1; +static int hf_ieee802154_cmd_cinfo_sec_capable = -1; +static int hf_ieee802154_cmd_cinfo_alloc_addr = -1; +static int hf_ieee802154_cmd_asrsp_shrt_addr = -1; +static int hf_ieee802154_cmd_asrsp_assoc_status = -1; +static int hf_ieee802154_cmd_disas_reason = -1; +static int hf_ieee802154_cmd_coord_panID = -1; +static int hf_ieee802154_cmd_coord_caddr16 = -1; +static int hf_ieee802154_cmd_coord_channel = -1; +static int hf_ieee802154_cmd_coord_addr16 = -1; +static int hf_ieee802154_cmd_coord_channel_page = -1; +static int hf_ieee802154_cmd_gts_req_len = -1; +static int hf_ieee802154_cmd_gts_req_dir = -1; +static int hf_ieee802154_cmd_gts_req_type = -1; + +/* Registered fields for Beacon Packets */ +/* Required for displaying information on Ethereal */ +static int hf_ieee802154_bcn_sfrm_bo = -1; +static int hf_ieee802154_bcn_sfrm_sfo = -1; +static int hf_ieee802154_bcn_sfrm_CAP_slot = -1; +static int hf_ieee802154_bcn_sfrm_batt_extn = -1; +static int hf_ieee802154_bcn_sfrm_coord = -1; +static int hf_ieee802154_bcn_sfrm_assoc_perm = -1; +static int hf_ieee802154_bcn_gts_desc_count = -1; +static int hf_ieee802154_bcn_gts_permit = -1; +static int hf_ieee802154_bcn_gts_direction[IEEE802154_BCN_GTS_MAX_SLOTS] = {-1, -1, -1, -1, -1, -1, -1}; + +/* Initialize Subtree Pointers */ +/* Required for displaying information on Ethereal */ +static gint ett_ieee802154 = -1; +static gint ett_ieee802154_fcf = -1; +static gint ett_ieee802154_fcs = -1; +static gint ett_ieee802154_cmd = -1; +static gint ett_ieee802154_cmd_cinfo = -1; +static gint ett_ieee802154_bcn = -1; +static gint ett_ieee802154_bcn_sfrm_spec = -1; +static gint ett_ieee802154_bcn_gts_spec = -1; +static gint ett_ieee802154_bcn_gts_direct = -1; +static gint ett_ieee802154_bcn_gts_device[IEEE802154_BCN_GTS_MAX_SLOTS] = {-1, -1, -1, -1, -1, -1, -1}; +static gint ett_ieee802154_bcn_paddrs = -1; + +/* Initialize preference values */ +static gboolean gPREF_ignore_bad_crc = FALSE; + +/* Dissector handle*/ +static dissector_handle_t data_handle; +static heur_dissector_list_t ieee802154_heur_subdissector_list; + +static char* ieee802154_FrameTypeNames[] = { + "Beacon", + "Data", + "Ack", + "Command", + "Reserved" +}; + +/* Name strings for address & frame types */ +static char* ieee802154_AddrTypeNames[] = { + "None", + "Reserved", + "Short/16-bit", + "Long/64-bit" +}; + +/* Precomputed partial CRC table. */ +static const guint16 crc_tabccitt[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +/* Table of bytes with reverse bits */ +/* Necessary for CRC generation because the CRC is generated from the bits ordered as + * they are transmitted over the air. But, IEEE 802.15.4 transmits the least signficant + * bits first. */ +static const guint8 rev_bitorder_table[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, +}; +#define REV_BITS(byte) rev_bitorder_table[byte] + +/*FUNCTION:------------------------------------------------------ + * NAME + * update_crc_ccitt + * DESCRIPTION + * Computes the 16-bit CCITT CRC according to the previous CRC, and the byte to add + * PARAMETERS + * guint16 crc - previous CRC value + * guint8 c - the next byte to calculate with + * RETURNS + * guint16 - the updated 16-bit CRC. + *--------------------------------------------------------------- + * This function was adapted from Lammert Bies's free software library + * http://www.lammertbies.nl/comm/software/index.html + *--------------------------------------------------------------- + * Also, the crc table this function refers to was generated using + * functions from Lammert Bies's free software library and the CCITT + * polynomial of x^16 + x^12 + x^5 + x (0x1021) + *--------------------------------------------------------------- + */ +guint16 update_crc_ccitt( guint16 crc, guint8 c ) { + + guint16 tmp, short_c; + + short_c = 0x00ff & (guint16) c; + tmp = (crc >> 8) ^ short_c; + crc = (crc << 8) ^ crc_tabccitt[tmp]; + + return crc; +} /* update_crc_ccitt */ + +/*FUNCTION:------------------------------------------------------ + * NAME + * ieee802154_crc16 + * DESCRIPTION + * Computes the 16-bit CRC according to the CCITT/ITU-T Standard + * + * NOTE: bit-reversal within bytes is necessary because IEEE 802.15.4 + * CRC is calculated on the packet in the order the bits are + * being sent, which is least-significan bit first. + * PARAMETERS + * tvbuff_t *tvb - pointer to buffer containing raw packet. + * guint - offset to the beginning of where to calculate the CRC from + * guint - number of bytes over which to calculate the CRC + * RETURNS + * guint16 + *--------------------------------------------------------------- + */ +guint16 ieee802154_crc16(tvbuff_t *tvb, guint offset, guint len) +{ + guint i; + guint16 crc = 0x0000; + for(i=0;i<len;i++){ + crc = update_crc_ccitt(crc, REV_BITS(tvb_get_guint8(tvb, offset+i))); + } + + /* Need to reverse the 16-bit field so that it agrees with the spec. */ + return REV_BITS((crc&0xff00)>>8) + (REV_BITS(crc&0x00ff)<<8); +} /* ieee802154_crc16 */ + + +#define EUI64_STRLEN (3*(sizeof(guint64)+1)) +/*FUNCTION:------------------------------------------------------ + * NAME + * print_eui64 + * DESCRIPTION + * Prints an EUI-64 address in a string. Does not attempt to + * resolve the OUI value. + * + * PARAMETERS + * guint64 addr + * RETURNS + * gchar* + *--------------------------------------------------------------- + */ +gchar *print_eui64(guint64 addr) +{ + gchar *addr_string = ep_alloc(EUI64_STRLEN); + gchar addr_bytes[sizeof(guint64)]; + guint64 j = 0xFF00000000000000L; + gint i, k; + + /* Copy the EUI-64 addr into the byte array. */ + for (i=0; i<8; i++, j=(j>>8)) { + addr_bytes[i] = (gchar)((addr & j) >> 8*(sizeof(guint64)-i-1)); + } + + /* Print the address into the buffer. */ + for (i=0, k=0; i<sizeof(guint64); i++) { + k += g_snprintf(addr_string+k, EUI64_STRLEN-k, "%02x:", 0xff & addr_bytes[i]); + } + + /* Remove the last character (should be ':') */ + addr_string[k-1] = '\0'; + + return addr_string; +} /* print_eui64 */ + +/*FUNCTION:------------------------------------------------------ + * NAME + * print_eui64_oui + * DESCRIPTION + * Prints an EUI-64 address in a string. Attempts to lookup + * the vendor name from the OUI, + * + * PARAMETERS + * guint64 addr + * RETURNS + * gchar* + *--------------------------------------------------------------- + */ +gchar *print_eui64_oui(guint64 addr) +{ + gchar *addr_string = ep_alloc(EUI64_STRLEN); + gchar addr_bytes[sizeof(guint64)]; + const gchar *manuf_name; + gint i, k; + guint64 j = 0xFF00000000000000L; + + /* Copy the EUI-64 addr into the byte array. */ + for (i=0; i<sizeof(guint64); i++, j=(j>>8)) { + addr_bytes[i] = (gchar)((addr & j) >> 8*(sizeof(guint64)-i-1)); + } + + /* Attempt an OUI lookup. */ + manuf_name = get_manuf_name_if_known(addr_bytes); + if (manuf_name == NULL) { + /* Could not find an OUI. */ + return print_eui64(addr); + } + + /* Found an OUI, print it to the buffer. */ + k = g_snprintf(addr_string, EUI64_STRLEN, "%s_", manuf_name); + + /* Print the rest of the EUI. */ + for (i=3; i<sizeof(guint64); i++) { + k += g_snprintf(addr_string+k, EUI64_STRLEN-k, "%02x:", 0xff & addr_bytes[i]); + } + + /* Remove the last character (should be ':') from the string. */ + addr_string[k-1] = '\0'; + + /* Done. */ + return addr_string; +} /* print_eui64_oui */ + +/*FUNCTION:------------------------------------------------------ + * NAME + * dissect_ieee802154 + * DESCRIPTION + * Dissector for IEEE 802.15.4 packet with an FCS containing + * a 16-bit CRC value. + * + * PARAMETERS + * tvbuff_t *tvb - pointer to buffer containing raw packet. + * packet_info *pinfo - pointer to packet information fields + * proto_tree *tree - pointer to data tree ethereal uses to display packet. + * RETURNS + * void + *--------------------------------------------------------------- + */ +void +dissect_ieee802154(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + ieee802154_packet packet; + memset(&packet, 0, sizeof(ieee802154_packet)); + pinfo->private_data = (void *)&packet; + + /* Setup the packet structure for a 16-bit CRC FCS. */ + packet.fcs_mode = IEEE802154_FCS_CRC; + + /* Call the common dissector. */ + dissect_ieee802154_common(tvb, pinfo, tree); +} /* dissect_ieee802154 */ + +/*FUNCTION:------------------------------------------------------ + * NAME + * dissect_ieee802154_maybefcs + * DESCRIPTION + * Dissector for IEEE 802.15.4 packet with an unknown FCS. + * Will check the IEEE 802.15.4 pseudo header for and determine + * the type of FCS based on the PHR length value. + * + * PARAMETERS + * tvbuff_t *tvb - pointer to buffer containing raw packet. + * packet_info *pinfo - pointer to packet information fields + * proto_tree *tree - pointer to data tree ethereal uses to display packet. + * RETURNS + * void + *--------------------------------------------------------------- + */ +void +dissect_ieee802154_maybefcs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + ieee802154_packet packet; + memset(&packet, 0, sizeof(ieee802154_packet)); + pinfo->private_data = (void *)&packet; + + /* Setup the packet structure for a ChipCon/TI FCS. */ + if (pinfo->fd->lnk_t == WTAP_ENCAP_IEEE802_15_4) { + guint8 phr_len = pinfo->pseudo_header->ieee802154.length; + + /* If the FCS exists, then phr_len should equal the length of the tvbuff_t. */ + if (phr_len == tvb_length(tvb)) { + /* Length matches, the FCS exists! */ + packet.fcs_mode = IEEE802154_FCS_CRC; + } + else { + /* Length mismatch, either the FCS doesn't exist, + * or the packet is badly broken. + */ + packet.fcs_mode = IEEE802154_FCS_NONE; + } + } + else { + /* No Other linktypes expected. Assume no FCS, that will probably do the least harm. */ + packet.fcs_mode = IEEE802154_FCS_NONE; + } + + /* Call the common dissector. */ + dissect_ieee802154_common(tvb, pinfo, tree); +} /* dissect_ieee802154_maybefcs */ + +/*FUNCTION:------------------------------------------------------ + * NAME + * dissect_ieee802154_nofcs + * DESCRIPTION + * Dissector for IEEE 802.15.4 packet with without an FCS. + * this is typically called by layers encapsulating an + * IEEE 802.15.4 packet. + * + * PARAMETERS + * tvbuff_t *tvb - pointer to buffer containing raw packet. + * packet_info *pinfo - pointer to packet information fields + * proto_tree *tree - pointer to data tree ethereal uses to display packet. + * RETURNS + * void + *--------------------------------------------------------------- + */ +void +dissect_ieee802154_nofcs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + ieee802154_packet packet; + memset(&packet, 0, sizeof(ieee802154_packet)); + pinfo->private_data = (void *)&packet; + + /* Setup the packet structure for no FCS. */ + packet.fcs_mode = IEEE802154_FCS_NONE; + + /* Call the common dissector. */ + dissect_ieee802154_common(tvb, pinfo, tree); +} /* dissect_ieee802154_nofcs */ + +/*FUNCTION:------------------------------------------------------ + * NAME + * dissect_ieee802154_ccfcs + * DESCRIPTION + * 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. + * + * PARAMETERS + * tvbuff_t *tvb - pointer to buffer containing raw packet. + * packet_info *pinfo - pointer to packet information fields + * proto_tree *tree - pointer to data tree ethereal uses to display packet. + * RETURNS + * void + *--------------------------------------------------------------- + */ +void +dissect_ieee802154_ccfcs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + ieee802154_packet packet; + memset(&packet, 0, sizeof(ieee802154_packet)); + pinfo->private_data = (void *)&packet; + + /* Setup the packet structure for a ChipCon/TI FCS. */ + packet.fcs_mode = IEEE802154_FCS_CHIPCON; + + /* Call the common dissector. */ + dissect_ieee802154_common(tvb, pinfo, tree); +} /* dissect_ieee802154_ccfcs */ + +/*FUNCTION:------------------------------------------------------ + * NAME + * dissect_ieee802154_common + * DESCRIPTION + * IEEE 802.15.4 packet dissection routine for Ethereal. + * 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 pinfo->private_data pointer. + * + * PARAMETERS + * tvbuff_t *tvb - pointer to buffer containing raw packet. + * packet_info *pinfo - pointer to packet information fields + * proto_tree *tree - pointer to data tree ethereal uses to display packet. + * RETURNS + * void + *--------------------------------------------------------------- + */ +void +dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + tvbuff_t *payload_tvb = NULL; + proto_item *ti; + proto_item *proto_root; + proto_tree *ieee802154_tree = NULL; + proto_tree *field_tree; + + guint16 expected_crc; + guint offset = 0; + gint i; + + ieee802154_packet *packet = pinfo->private_data; + + /* Create the protocol tree. */ + if (tree) { + proto_root = proto_tree_add_protocol_format(tree, proto_ieee802154, tvb, 0, tvb_length(tvb), "IEEE 802.15.4"); + ieee802154_tree = proto_item_add_subtree(proto_root, ett_ieee802154); + } + /* Add the protocol name. */ + if(check_col(pinfo->cinfo, COL_PROTOCOL)){ + col_set_str(pinfo->cinfo, COL_PROTOCOL, "802.15.4"); + } + /* Add the packet length. */ + if(check_col(pinfo->cinfo, COL_PACKET_LENGTH)){ + col_clear(pinfo->cinfo, COL_PACKET_LENGTH); + col_add_fstr(pinfo->cinfo, COL_PACKET_LENGTH, "%i", tvb_length(tvb)); + } + + /****************************************************** + * BEGIN DISSECTION + ****************************************************** + */ + /* Retrieve FCF (7.2.1.1 in the IEEE 802.15.4 document */ + packet->fcf = tvb_get_ntohs(tvb, offset); + + /* Parse Frame Type */ + switch (packet->fcf & IEEE802154_FCF_TYPE_MASK){ + case IEEE802154_FCF_BEACON: + packet->frame_type = ieee802154_beacon; + if (tree) proto_item_append_text(proto_root, " Beacon"); + if (check_col(pinfo->cinfo, COL_INFO)) col_set_str(pinfo->cinfo, COL_INFO, "Beacon"); + break; + case IEEE802154_FCF_DATA: + packet->frame_type = ieee802154_data; + if (tree) proto_item_append_text(proto_root, " Data"); + if (check_col(pinfo->cinfo, COL_INFO)) col_set_str(pinfo->cinfo, COL_INFO, "Data"); + break; + case IEEE802154_FCF_ACK: + packet->frame_type = ieee802154_ack; + if (tree) proto_item_append_text(proto_root, " Ack"); + if (check_col(pinfo->cinfo, COL_INFO)) col_set_str(pinfo->cinfo, COL_INFO, "Ack"); + break; + case IEEE802154_FCF_CMD: + packet->frame_type = ieee802154_cmd; + if (tree) proto_item_append_text(proto_root, " Command"); + if (check_col(pinfo->cinfo, COL_INFO)) col_set_str(pinfo->cinfo, COL_INFO, "Command"); + break; + default: + packet->frame_type = ieee802154_reserved; + if (tree) proto_item_append_text(proto_root, " Reserved Type"); + if (check_col(pinfo->cinfo, COL_INFO)) col_set_str(pinfo->cinfo, COL_INFO, "Reserved Frame Type"); + break; + } + /* Parse FCF Flags. */ + packet->security_enable = packet->fcf & IEEE802154_FCF_SEC_EN; + packet->frame_pending = packet->fcf & IEEE802154_FCF_FRAME_PND; + packet->ack_request = packet->fcf & IEEE802154_FCF_ACK_REQ; + packet->intra_pan = packet->fcf & IEEE802154_FCF_INTRA_PAN; + packet->version = packet->fcf & IEEE802154_FCF_VERSION; + /* Addressing Modes. */ + switch (packet->fcf & IEEE802154_FCF_DADDR) { + case IEEE802154_FCF_DADDR0: + packet->dst_addr_mode = ieee802154_addr_none; + break; + case IEEE802154_FCF_DADDR16: + packet->dst_addr_mode = ieee802154_addr16; + break; + case IEEE802154_FCF_DADDR64: + packet->dst_addr_mode = ieee802154_addr64; + break; + default: + packet->dst_addr_mode = ieee802154_addr_invalid; + break; + } /* switch */ + switch (packet->fcf & IEEE802154_FCF_SADDR) { + case IEEE802154_FCF_SADDR0: + packet->src_addr_mode = ieee802154_addr_none; + break; + case IEEE802154_FCF_SADDR16: + packet->src_addr_mode = ieee802154_addr16; + break; + case IEEE802154_FCF_SADDR64: + packet->src_addr_mode = ieee802154_addr64; + break; + default: + packet->src_addr_mode = ieee802154_addr_invalid; + break; + } /* switch */ + + /* Add the FCF to the protocol tree. */ + if (tree) { + /* Create the FCF subtree. */ + ti = proto_tree_add_text(ieee802154_tree, tvb, offset, 2, "Frame Control Field: %s (0x%04x)", ieee802154_FrameTypeNames[packet->frame_type], packet->fcf); + field_tree = proto_item_add_subtree(ti, ett_ieee802154_fcf); + + /* FCF Flags. */ + ti = proto_tree_add_uint(field_tree, hf_ieee802154_frame_type, tvb, offset, 1, packet->fcf & IEEE802154_FCF_TYPE_MASK); + proto_item_append_text(ti, " (%s)", ieee802154_FrameTypeNames[packet->frame_type]); + if (packet->frame_type == ieee802154_reserved) { + expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_WARN, "Invalid Frame Type"); + } + proto_tree_add_boolean(field_tree, hf_ieee802154_security_enable, tvb, offset, 1, packet->security_enable); + proto_tree_add_boolean(field_tree, hf_ieee802154_frame_pending, tvb, offset, 1, packet->frame_pending); + proto_tree_add_boolean(field_tree, hf_ieee802154_ack_request, tvb, offset, 1, packet->ack_request); + proto_tree_add_boolean(field_tree, hf_ieee802154_intra_pan, tvb, offset, 1, packet->intra_pan); + + /* Dest Addressing Mode. */ + ti = proto_tree_add_uint(field_tree, hf_ieee802154_dst_addr_mode, tvb, offset+1, 1, packet->fcf & IEEE802154_FCF_DADDR); + proto_item_append_text(ti, " (%s)", ieee802154_AddrTypeNames[packet->dst_addr_mode]); + if (packet->dst_addr_mode == ieee802154_addr_invalid) { + /* Don't abort yet, wait until we can't dissect any further. */ + expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR, "Invalid Addressing Mode"); + } + + /* Frame Version, added in IEEE 802.15.4-2006. */ + proto_tree_add_uint(field_tree, hf_ieee802154_version, tvb, offset+1, 1, packet->version); + + /* Source Addressing Mode. */ + ti = proto_tree_add_uint(field_tree, hf_ieee802154_src_addr_mode, tvb, offset+1, 1, packet->fcf & IEEE802154_FCF_SADDR); + proto_item_append_text(ti, " (%s)", ieee802154_AddrTypeNames[packet->src_addr_mode]); + if (packet->src_addr_mode == ieee802154_addr_invalid) { + /* Don't abort yet, wait until we can't dissect any further. */ + expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR, "Invalid Addressing Mode"); + } + } + + /* Increment the offset by the FCF length. */ + offset += sizeof(guint16); + + /* Retrieve Sequence Number */ + packet->seqno = tvb_get_guint8(tvb, offset); + + /* Display Sequence No. */ + 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_ack) { + proto_item_append_text(proto_root, ", Sequence Number: %u", packet->seqno); + } + } + + /* Increment offset by the length of the sequence number field. */ + offset += sizeof(guint8); + + /* Clear out the addressing strings. */ + SET_ADDRESS(&pinfo->dst, AT_NONE, 0, NULL); + SET_ADDRESS(&pinfo->src, AT_NONE, 0, NULL); + SET_ADDRESS(&pinfo->dl_dst, AT_NONE, 0, NULL); + SET_ADDRESS(&pinfo->dl_src, AT_NONE, 0, NULL); + SET_ADDRESS(&pinfo->net_dst, AT_NONE, 0, NULL); + SET_ADDRESS(&pinfo->net_src, AT_NONE, 0, NULL); + + /* Get destination address & PAN if present. */ + if (packet->dst_addr_mode == ieee802154_addr16) { + gchar *dst_addr = ep_alloc(32); + + packet->dst_panID = tvb_get_letohs(tvb, offset); + packet->dst_addr16 = tvb_get_letohs(tvb, offset+2); + + /* Display the destination address. */ + if(packet->dst_addr16==IEEE802154_BCAST_ADDR) g_snprintf(dst_addr, 32, "Broadcast"); + else g_snprintf(dst_addr, 32, "0x%04x", packet->dst_addr16); + SET_ADDRESS(&pinfo->dl_dst, AT_STRINGZ, strlen(dst_addr)+1, dst_addr); + SET_ADDRESS(&pinfo->dst, AT_STRINGZ, strlen(dst_addr)+1, dst_addr); + if (tree) { + proto_tree_add_uint(ieee802154_tree, hf_ieee802154_dst_panID, tvb, offset, 2, packet->dst_panID); + proto_tree_add_uint_format(ieee802154_tree, hf_ieee802154_dst_addr16, tvb, offset+2, 2, packet->dst_addr16, "Destination: 0x%04x", packet->dst_addr16); + proto_item_append_text(proto_root, ", Dst: %s", dst_addr); + } + if ((packet->frame_type == ieee802154_data) && check_col(pinfo->cinfo, COL_INFO)) { + /* For data packets, print to info column as well. */ + col_append_fstr(pinfo->cinfo, COL_INFO, ", Dst: %s", dst_addr); + } + offset += sizeof(guint16) + sizeof(guint16); + } + else if (packet->dst_addr_mode == ieee802154_addr64) { + gchar *addr = ep_alloc(sizeof(guint64)); + gchar *dst, *dst_oui; + guint64 j = 0xFF00000000000000L; + packet->dst_panID = tvb_get_letohs(tvb, offset); + packet->dst_addr64 = tvb_get_letoh64(tvb, offset+2); + + /* print the address strings. */ + dst = print_eui64(packet->dst_addr64); + dst_oui = print_eui64_oui(packet->dst_addr64); + + /* Copy the 64-bit address into the gchar array. */ + for (i=0; i<sizeof(guint64); i++, j=(j>>8)) { + addr[i] = (gchar)((packet->dst_addr64 & j) >> 8*(sizeof(guint64)-i-1)); + } + + /* Display the destination address. */ + /* NOTE: OUI resolution doesn't happen when displaying EUI64 addresses + * might want to switch to AT_STRINZ type to display the OUI in + * the address columns. */ + SET_ADDRESS(&pinfo->dl_dst, AT_EUI64, sizeof(guint64), addr); + SET_ADDRESS(&pinfo->dst, AT_EUI64, sizeof(guint64), addr); + if (tree) { + proto_tree_add_uint(ieee802154_tree, hf_ieee802154_dst_panID, tvb, offset, 2, packet->dst_panID); + proto_tree_add_uint64_format(ieee802154_tree, hf_ieee802154_dst_addr64, tvb, offset+2, 8, packet->dst_addr64, "Destination: %s (%s)", dst_oui, dst); + proto_item_append_text(proto_root, ", Dst: %s", dst_oui); + //proto_item_append_text(proto_root, " (%s)", dst); + } + if ((packet->frame_type == ieee802154_data) && check_col(pinfo->cinfo, COL_INFO)) { + /* For data packets, print to info column as well. */ + col_append_fstr(pinfo->cinfo, COL_INFO, ", Dst: %s", dst_oui); + } + offset += sizeof(guint16) + sizeof(guint64); + } + else if (packet->dst_addr_mode == ieee802154_addr_invalid) { + /* Invalid destination addressing. Abort dissection. */ + return; + } + + /* Get the source PAN if it exists. */ + if ((packet->src_addr_mode == ieee802154_addr16) || (packet->src_addr_mode == ieee802154_addr64)) { + if (!(packet->intra_pan && packet->dst_addr_mode != ieee802154_addr_none)) { + /* Source PAN is present, extract it and add it to the tree. */ + packet->src_panID = tvb_get_letohs(tvb, offset); + if (tree) { + proto_tree_add_uint(ieee802154_tree, hf_ieee802154_src_panID, tvb, offset, 2, packet->src_panID); + } + offset += sizeof(guint16); + } + else { + packet->src_panID = packet->dst_panID; + } + } + else if (packet->src_addr_mode == ieee802154_addr_invalid) { + /* Invalid source addressing. Abort dissection. */ + return; + } + + /* Get source address if present. */ + if (packet->src_addr_mode == ieee802154_addr16) { + gchar *src_addr = ep_alloc(32); + packet->src_addr16 = tvb_get_letohs(tvb, offset); + + /* Update the Address fields. */ + if(packet->src_addr16==IEEE802154_BCAST_ADDR) g_snprintf(src_addr, 32, "Broadcast"); + else g_snprintf(src_addr, 32, "0x%04x", packet->src_addr16); + SET_ADDRESS(&pinfo->dl_src, AT_STRINGZ, strlen(src_addr)+1, src_addr); + SET_ADDRESS(&pinfo->src, AT_STRINGZ, strlen(src_addr)+1, src_addr); + + /* Add the addressing info to the tree. */ + if (tree) { + proto_tree_add_uint_format(ieee802154_tree, hf_ieee802154_src_addr16, tvb, offset, 2, packet->src_addr16, "Source: 0x%04x", packet->src_addr16); + proto_item_append_text(proto_root, ", Src: %s", src_addr); + } + if ((packet->frame_type == ieee802154_data) && check_col(pinfo->cinfo, COL_INFO)) { + /* For data packets, print to info column as well. */ + col_append_fstr(pinfo->cinfo, COL_INFO, ", Src: %s", src_addr); + } + offset += sizeof(guint16); + } + else if (packet->src_addr_mode == ieee802154_addr64) { + gchar *addr = ep_alloc(sizeof(guint64)); + gchar *src, *src_oui; + guint64 j = 0xFF00000000000000L; + packet->src_addr64 = tvb_get_letoh64(tvb, offset); + + /* Print the address strings. */ + src = print_eui64(packet->src_addr64); + src_oui = print_eui64_oui(packet->src_addr64); + + /* Copy the 64-bit address into the gchar array. */ + for (i=0; i<sizeof(guint64); i++, j=(j>>8)) { + addr[i] = (gchar)((packet->src_addr64 & j) >> 8*(sizeof(guint64)-i-1)); + } + + /* Display the source address. */ + /* NOTE: OUI resolution doesn't happen when displaying EUI64 addresses + * might want to switch to AT_STRINZ type to display the OUI in + * the address columns. */ + SET_ADDRESS(&pinfo->dl_src, AT_EUI64, sizeof(guint64), addr); + SET_ADDRESS(&pinfo->src, AT_EUI64, sizeof(guint64), addr); + if (tree) { + proto_tree_add_uint64_format(ieee802154_tree, hf_ieee802154_src_addr64, tvb, offset, sizeof(guint64), packet->src_addr64, "Source: %s (%s)", src_oui, src); + proto_item_append_text(proto_root, ", Src: %s", src_oui); + //proto_item_append_text(proto_root, " (%s)", src); + } + if ((packet->frame_type == ieee802154_data) && check_col(pinfo->cinfo, COL_INFO)) { + /* For data packets, print to info column as well. */ + col_append_fstr(pinfo->cinfo, COL_INFO, ", Src: %s", src_oui); + } + offset += sizeof(guint64); + } + + /* Calculate payload length & offset */ + if (packet->fcs_mode == IEEE802154_FCS_NONE) { + packet->payload_offset = offset; + packet->payload_length = tvb_length(tvb) - offset; + } + else { + packet->payload_offset = offset; + packet->payload_length = tvb_length(tvb) - offset - IEEE802154_MAC_FTR_OVRHD; + } + + /* Check that the payload length is sane. */ + tvb_ensure_bytes_exist(tvb, offset, packet->payload_length); + + /* If the payload exists, create a tvb for it */ + if(packet->payload_length != 0){ + payload_tvb = tvb_new_subset(tvb, packet->payload_offset, packet->payload_length, packet->payload_length); + } + + /* Check the FCS before dissecting the payload. */ + /* Don't display the FCS yet, otherwise the payload dissection may be out of place in the tree. */ + switch (packet->fcs_mode) { + case IEEE802154_FCS_NONE: + packet->crc_ok = TRUE; + break; + + case IEEE802154_FCS_CRC: + /* Packet is using an IEEE style FCS. */ + expected_crc = ieee802154_crc16(tvb, 0, tvb_length(tvb)-2); + packet->crc = tvb_get_letohs(tvb, tvb_length(tvb)-2); + packet->crc_ok = (packet->crc == expected_crc); + break; + + case IEEE802154_FCS_CHIPCON: + /* Packet is using ChipCon/TI style FCS. */ + packet->rssi = (gint8)tvb_get_guint8(tvb, tvb_length(tvb)-2); + packet->correlation = tvb_get_guint8(tvb, tvb_length(tvb)-1); + packet->crc_ok = !!(packet->correlation & CC2420_FCS_CRC_OK); + packet->correlation &= CC2420_FCS_CORR_MASK; + break; + + default: + /* This should never occur. */ + REPORT_DISSECTOR_BUG("Invalid FCS Mode"); + } + if (!packet->crc_ok) { + /* If the CRC is invalid, make a note of it in the info column. */ + if(check_col(pinfo->cinfo, COL_INFO)){ + col_append_fstr(pinfo->cinfo, COL_INFO, ", Bad CRC"); + } + if(tree){ + proto_item_append_text(proto_root, ", Bad CRC"); + } + } + + if (payload_tvb && packet->security_enable) { + /* Payload exists and is encrypted. */ + /* We can't handle this. */ + expert_add_info_format(pinfo, proto_root, PI_UNDECODED, PI_WARN, "Encrypted Payload"); + call_dissector(data_handle, payload_tvb, pinfo, tree); + } + else { + /* Dissect the payload. */ + switch (packet->frame_type) { + case ieee802154_beacon: + if (payload_tvb) dissect_ieee802154_beacon(payload_tvb, pinfo, ieee802154_tree); + else { + expert_add_info_format(pinfo, proto_root, PI_MALFORMED, PI_ERROR, "Missing Beacon Frame"); + THROW(BoundsError); + } + break; + case ieee802154_cmd: + if (payload_tvb) dissect_ieee802154_cmd(payload_tvb, pinfo, ieee802154_tree); + else { + expert_add_info_format(pinfo, proto_root, PI_MALFORMED, PI_ERROR, "Missing Command Frame"); + THROW(BoundsError); + } + break; + case ieee802154_data: + if ((packet->crc_ok || gPREF_ignore_bad_crc) && (payload_tvb)) { + /* Attempt heuristic subdissection. */ + if (dissector_try_heuristic(ieee802154_heur_subdissector_list, payload_tvb, pinfo, tree)) { + /* found a sub-dissector! */ + break; + } + } + /* If no sub-dissector was called, fall-through to the data dissector. */ + call_dissector(data_handle, payload_tvb, pinfo, tree); + break; + case ieee802154_ack: + /* Ack should not contain a payload. */ + if (payload_tvb) { + expert_add_info_format(pinfo, proto_root, PI_MALFORMED, PI_WARN, "Unexpected Payload in Acknowledgement"); + call_dissector(data_handle, payload_tvb, pinfo, tree); + } + break; + default: + /* Unknown frame type! */ + if (payload_tvb) { + call_dissector(data_handle, payload_tvb, pinfo, tree); + } + break; + } /* switch */ + } + + /* Display the FCS. */ + if (tree) { + switch (packet->fcs_mode) { + case IEEE802154_FCS_CRC: + ti = proto_tree_add_uint(ieee802154_tree, hf_ieee802154_crc, tvb, tvb_length(tvb)-2, 2, packet->crc); + proto_tree_add_boolean_hidden(field_tree, hf_ieee802154_crc_ok, tvb, tvb_length(tvb)-2 , 2, packet->crc_ok); + if (packet->crc_ok) proto_item_append_text(ti, " (Correct)"); + else { + proto_item_append_text(ti, " (Incorrect, expected CRC=0x%04x", expected_crc); + expert_add_info_format(pinfo, ti, PI_CHECKSUM, PI_WARN, "Bad CRC"); + } + break; + + case IEEE802154_FCS_CHIPCON: + /* Create a subtree for the FCS. */ + ti = proto_tree_add_text(ieee802154_tree, tvb, tvb_length(tvb) - 2, 2, "Frame Check Sequence: CRC %s", (packet->crc_ok) ? "OK" : "Bad"); + field_tree = proto_item_add_subtree(ti, ett_ieee802154_fcs); + /* Display FCS contents. */ + ti = proto_tree_add_int(field_tree, hf_ieee802154_rssi, tvb, tvb_length(tvb) - 2, 1, packet->rssi); + proto_item_append_text(ti, " dBm"); /* Displaying Units */ + ti = proto_tree_add_boolean(field_tree, hf_ieee802154_crc_ok, tvb, tvb_length(tvb) - 1 , 1, packet->crc_ok); + if (!packet->crc_ok) expert_add_info_format(pinfo, ti, PI_CHECKSUM, PI_WARN, "Bad CRC"); + proto_tree_add_uint(field_tree, hf_ieee802154_correlation, tvb, tvb_length(tvb) - 1, 1, packet->correlation); + break; + + case IEEE802154_FCS_NONE: + default: + /* Nothing to do here. */ + break; + } /* switch */ + } +} /* dissect_ieee802154_common */ + + +/*FUNCTION:------------------------------------------------------ + * NAME + * dissect_ieee802154_beacon + * DESCRIPTION + * ZigBee packet dissection routine for beacon packets.Please refer + * to section 7.2.2.1 in the IEEE 802.15.4 document on Beacon frame format + * PARAMETERS + * tvbuff_t *tvb - pointer to buffer containing raw packet. + * packet_info *pinfo - pointer to packet information fields + * proto_tree *tree - pointer to data tree ethereal uses to display packet. + * RETURNS + * void + *--------------------------------------------------------------- + */ +void dissect_ieee802154_beacon(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + proto_tree *field_tree; + proto_tree *bcn_tree; + proto_item *ti; + ieee802154_packet *packet = pinfo->private_data; + + guint8 superframe_spec_hi; + guint8 superframe_spec_lo; + guint8 gts_spec; + guint8 gts_desc_count; + guint8 gts_directions; + guint8 paddr_spec; + guint8 paddr_num16; + guint8 paddr_num64; + guint8 bcn_payload_len; + + gint i; + gint offset = 0; + + /* Parse the superframe spec. */ + superframe_spec_hi = tvb_get_guint8(tvb, offset); + superframe_spec_lo = tvb_get_guint8(tvb, offset+1); + if(tree){ + guint8 bo = superframe_spec_hi & IEEE802154_BCN_BO_MASK; + guint8 sfo = (superframe_spec_hi & IEEE802154_BCN_SFO_MASK)>>IEEE802154_BCN_SFO_SHIFT; + + /* Add Subtree for beacon frame */ + ti = proto_tree_add_text(tree, tvb, 0, tvb_length(tvb), "Beacon Frame"); + bcn_tree = proto_item_add_subtree(ti, ett_ieee802154_bcn); + + /* 'Light' Assert to check for valid addressing. */ + if (packet->src_addr_mode == ieee802154_addr_none) { + expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_WARN, "Missing Source Address in Beacon" ); + } + + /* Add Subtree for superframe specification */ + ti = proto_tree_add_text(bcn_tree, tvb, offset, 2, "Superframe Specification"); + field_tree = proto_item_add_subtree(ti, ett_ieee802154_bcn_sfrm_spec); + + /* Add Beacon Order to the superframe spec. */ + ti = proto_tree_add_uint_format(field_tree, hf_ieee802154_bcn_sfrm_bo, tvb, offset, 1, bo, "Beacon Order: "); + if(bo == 0xf) proto_item_append_text(ti, "Beacons Disabled"); + else proto_item_append_text(ti, "%i", IEEE802154_BCN_SFRM_DURATION*(1<<bo)); + + /* Add superframe order to superframe spec. */ + ti = proto_tree_add_uint_format(field_tree, hf_ieee802154_bcn_sfrm_sfo, tvb, offset, 1, sfo, "Superframe Order: "); + if(bo == 0xf) proto_item_append_text(ti, "Inactive"); + else proto_item_append_text(ti, "%i", IEEE802154_BCN_SFRM_DURATION*(1<<sfo)); + + /* Add the CAP and Flags. */ + proto_tree_add_uint(field_tree, hf_ieee802154_bcn_sfrm_CAP_slot, tvb, offset+1, 1, superframe_spec_lo & IEEE802154_BCN_CAP_MASK); + proto_tree_add_boolean(field_tree, hf_ieee802154_bcn_sfrm_batt_extn, tvb, offset+1, 1, superframe_spec_lo & IEEE802154_BCN_BATT_EXTN_MASK); + proto_tree_add_boolean(field_tree, hf_ieee802154_bcn_sfrm_coord, tvb, offset+1, 1, superframe_spec_lo & IEEE802154_BCN_COORD_MASK); + proto_tree_add_boolean(field_tree, hf_ieee802154_bcn_sfrm_assoc_perm, tvb, offset+1, 1, superframe_spec_lo & IEEE802154_BCN_ASSOC_PERM_MASK); + } + offset += sizeof(guint16); + + /* Get the GTS specification field */ + gts_spec = tvb_get_guint8(tvb, offset); + gts_desc_count = gts_spec & IEEE802154_BCN_GTS_COUNT_MASK; + if(gts_desc_count){ + /* GTS directions mask will only exist if the descriptor count is non-zero */ + gts_directions = tvb_get_guint8(tvb, offset + 1); + } + if(tree){ + guint8 gts_numRx = 0; + + /* Add fields to GTS subtree */ + ti = proto_tree_add_uint(bcn_tree, hf_ieee802154_bcn_gts_desc_count, tvb, offset, 1, gts_desc_count); + proto_tree_add_boolean(bcn_tree, hf_ieee802154_bcn_gts_permit, tvb, offset, 1, gts_spec & IEEE802154_BCN_GTS_PERMIT_MASK); + + if(gts_desc_count){ + gts_numRx = 0; + for (i=0; i<gts_desc_count; i++) { + if (gts_directions & IEEE802154_BCN_GTS_DIRECTION_SLOT(i)) gts_numRx++; + } + + /* Create a subtree for the GTS directions masks if it exists.*/ + ti = proto_tree_add_text(bcn_tree, tvb, offset+1, 1, "GTS Directions: %i Receive & %i Transmit", gts_numRx, gts_desc_count-gts_numRx); + field_tree = proto_item_add_subtree(ti, ett_ieee802154_bcn_gts_direct); + for (i=0; i<gts_desc_count; i++) { + gboolean dir = gts_directions & IEEE802154_BCN_GTS_DIRECTION_SLOT(i); + ti = proto_tree_add_boolean(field_tree, hf_ieee802154_bcn_gts_direction[i], tvb, offset+1, 1, gts_directions & IEEE802154_BCN_GTS_DIRECTION_SLOT(i)); + if (dir) proto_item_append_text(ti, " (Receive Only)"); + else proto_item_append_text(ti, " (Send Only)"); + } + } + } + offset += sizeof(guint8); + if(gts_desc_count){ + offset += sizeof(guint8); + } + + /* Get and display the GTS descriptors. */ + for (i=0; i<gts_desc_count; i++) { + guint16 gts_addr = tvb_get_letohs(tvb, offset); + guint8 gts_slot = tvb_get_guint8(tvb, offset+2); + guint8 gts_slot_len = (gts_slot & IEEE802154_BCN_GTS_LENGTH_MASK) >> IEEE802154_BCN_GTS_LENGTH_SHIFT; + + if (tree) { + /* Add a subtree for this GTS device. */ + ti = proto_tree_add_text(bcn_tree, tvb, offset, 3, "GTS Descriptor %i, Addr: 0x%04x", i+1, gts_addr); + field_tree = proto_item_add_subtree(ti, ett_ieee802154_bcn_gts_device[i]); + + /* Add address, slot, and time length fields. */ + /* HACK: should be using a type (not text) to add these fields, but that doesn't work so + * well with being in an array. */ + proto_tree_add_text(field_tree, tvb, offset, 2, "Address: 0x%04x", gts_addr); + proto_tree_add_text(field_tree, tvb, offset+2, 1, "Starting Slot: %i", gts_slot); + ti = proto_tree_add_text(field_tree, tvb, offset+2, 1, "Slot Length: %i", gts_slot_len); + } + + /* Increase the offset. */ + offset += sizeof(guint16)+sizeof(guint8); + } /* for */ + + /* Get the Pending Addresses specification fields */ + paddr_spec = tvb_get_guint8(tvb, offset); + paddr_num16 = paddr_spec & IEEE802154_BCN_PADDR_SHORT_MASK; + paddr_num64 = (paddr_spec & IEEE802154_BCN_PADDR_LONG_MASK) >> IEEE802154_BCN_PADDR_LONG_SHIFT; + if(tree){ + /* Add Subtree for the addresses */ + ti = proto_tree_add_text(bcn_tree, tvb, offset, 1 + 2*paddr_num16 + 8*paddr_num64, "Pending Addresses: %i Short and %i Long", paddr_num16, paddr_num64); + field_tree = proto_item_add_subtree(ti, ett_ieee802154_bcn_paddrs); + } + offset += sizeof(guint8); + + for (i=0; i<paddr_num16; i++) { + if (tree) { + proto_tree_add_text(field_tree, tvb, offset, sizeof(guint16), "0x%04x", tvb_get_letohs(tvb, offset)); + } + offset += sizeof(guint16); + } + for (i=0; i<paddr_num64; i++) { + guint64 addr = tvb_get_letoh64(tvb, offset); + if (tree) { + proto_tree_add_text(field_tree, tvb, offset, sizeof(guint64), "%s (%s)", print_eui64_oui(addr), print_eui64(addr)); + } + offset += sizeof(guint64); + } + + /* Get the beacon payload (if it exists) */ + bcn_payload_len = tvb_length(tvb) - offset; + if(bcn_payload_len){ + proto_tree *root_tree = proto_tree_get_root(tree); + tvbuff_t *payload_tvb = tvb_new_subset(tvb, offset, bcn_payload_len, bcn_payload_len); + /* Attempt subdissection. */ + if(!dissector_try_heuristic(ieee802154_heur_subdissector_list, payload_tvb, pinfo, root_tree)) { + /* heuristic subdissector was not called. use data subdissector instead. */ + call_dissector(data_handle, payload_tvb, pinfo, root_tree); + } + } +} /* dissect_ieee802154_beacon */ + +/*FUNCTION:------------------------------------------------------ + * NAME + * dissect_ieee802154_mac_cmd + * DESCRIPTION + * IEEE 802.15.4 packet dissection routine for command packets + * PARAMETERS + * tvbuff_t *tvb - pointer to buffer containing raw packet. + * packet_info *pinfo - pointer to packet information fields + * proto_tree *tree - pointer to data tree Ethereal uses to display packet. + * RETURNS + * void + *--------------------------------------------------------------- + * MAC Command Frames have a MAC Payload organized as follows: + * |Command Frame Identifier| Command Payload | + * | 1 Byte |dependant upon command| + *--------------------------------------------------------------- + */ +void dissect_ieee802154_cmd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + ieee802154_packet *packet = pinfo->private_data; + guint8 cmd_id; + guint8 offset = 0; + proto_tree *field_tree; + proto_tree *cmd_tree; + proto_item *ti; + proto_item *cmd_root = NULL; + +#define IS_CMD_ID_VALID(x) ((x!=0) && (x<=IEEE802154_CMD_GTS_REQ)) + static gchar *cmd_names[] = { + "Reserved", + "Association Request", + "Association Response", + "Disassociation Notification", + "Data Request", + "PanID Conflict", + "Orphan Notification", + "Beacon Request", + "Coordinator Realignment", + "GTS Request" + }; + +#define CMD_ADDR_CHECK(x, s) if (!(x)) expert_add_info_format(pinfo, cmd_root, PI_MALFORMED, PI_WARN, "Invalid Addressing for %s", s) + + /* Get the command frame identifier. */ + cmd_id = tvb_get_guint8(tvb, offset); + if(check_col(pinfo->cinfo, COL_INFO) && IS_CMD_ID_VALID(cmd_id)) { + col_set_str(pinfo->cinfo, COL_INFO, cmd_names[cmd_id]); + } + if(tree){ + /* Create a subtree for this command frame. */ + cmd_root = proto_tree_add_text(tree, tvb, 0, tvb_length(tvb), "Command Frame"); + cmd_tree = proto_item_add_subtree(cmd_root, ett_ieee802154_cmd); + if (IS_CMD_ID_VALID(cmd_id)) proto_item_append_text(cmd_root, ", %s", cmd_names[cmd_id]); + + /* Add the command ID to the subtree. */ + ti = proto_tree_add_uint(cmd_tree, hf_ieee802154_cmd_frm_id, tvb, 0, 1, cmd_id); + if (IS_CMD_ID_VALID(cmd_id)) proto_item_append_text(ti, " (%s)", cmd_names[cmd_id]); + else proto_item_append_text(ti, " (%s)", cmd_names[0]); + } + + /* Increment the offset field. */ + offset += sizeof(guint8); + + /* Parse the Command Payloads. */ + switch(cmd_id){ + case IEEE802154_CMD_ASRQ:{ + /* Get the capability info. */ + guint8 capability_info; + + /* Check that the addressing is correct for this command type. */ + CMD_ADDR_CHECK((packet->src_addr_mode == ieee802154_addr64) + && (packet->src_panID == IEEE802154_BCAST_PAN) + && (packet->dst_addr_mode != ieee802154_addr_none), + "Association Request"); + + /* Get the capability info. */ + capability_info = tvb_get_guint8(tvb, offset); + + /* Display capability info. */ + if (tree) { + ti = proto_tree_add_text(cmd_tree, tvb, 1, 1, "Capabilities Information"); + field_tree = proto_item_add_subtree(ti, ett_ieee802154_cmd_cinfo); + + /* Enter the capability bits. */ + proto_tree_add_boolean(field_tree, hf_ieee802154_cmd_cinfo_alt_pan_coord, tvb, offset, 1, capability_info & IEEE802154_CMD_CINFO_ALT_PAN_COORD); + ti = proto_tree_add_boolean(field_tree, hf_ieee802154_cmd_cinfo_device_type, tvb, offset, 1, capability_info & IEEE802154_CMD_CINFO_DEVICE_TYPE); + if (capability_info & IEEE802154_CMD_CINFO_DEVICE_TYPE) proto_item_append_text(ti, " (FFD)"); + else proto_item_append_text(ti, " (RFD)"); + ti = proto_tree_add_boolean(field_tree, hf_ieee802154_cmd_cinfo_power_src, tvb, offset, 1, capability_info & IEEE802154_CMD_CINFO_POWER_SRC); + if (capability_info & IEEE802154_CMD_CINFO_POWER_SRC) proto_item_append_text(ti, " (AC/Mains Power)"); + else proto_item_append_text(ti, " (Battery)"); + proto_tree_add_boolean(field_tree, hf_ieee802154_cmd_cinfo_idle_rx, tvb, offset, 1, capability_info & IEEE802154_CMD_CINFO_IDLE_RX); + proto_tree_add_boolean(field_tree, hf_ieee802154_cmd_cinfo_sec_capable, tvb, offset, 1, capability_info & IEEE802154_CMD_CINFO_SEC_CAPABLE); + proto_tree_add_boolean(field_tree, hf_ieee802154_cmd_cinfo_alloc_addr, tvb, offset, 1, capability_info & IEEE802154_CMD_CINFO_ALLOC_ADDR); + } + + /* Increase the offset. */ + offset += sizeof(guint8); + + break; + } + case IEEE802154_CMD_ASRSP:{ + /* Get the short address and status. */ + guint16 short_addr; + guint8 status; + + /* Check that the addressing is correct for this command type. */ + CMD_ADDR_CHECK((packet->src_addr_mode == ieee802154_addr64) + && (packet->dst_addr_mode == ieee802154_addr64), + "Association Response"); + + /* Get and display the short address. */ + short_addr = tvb_get_letohs(tvb, offset); + if (tree) { + proto_tree_add_uint(cmd_tree, hf_ieee802154_cmd_asrsp_shrt_addr, tvb, offset, 2, short_addr); + } + offset += sizeof(guint16); + + /* Get and display the status. */ + status = tvb_get_guint8(tvb, offset); + if (tree) { + ti = proto_tree_add_uint(cmd_tree, hf_ieee802154_cmd_asrsp_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 += sizeof(guint8); + + /* Update the info column. */ + if (check_col(pinfo->cinfo, COL_INFO)) { + if (status == IEEE802154_CMD_ASRSP_AS_SUCCESS) { + /* Association was successful. */ + if (packet->src_addr_mode != ieee802154_addr_none) { + col_append_fstr(pinfo->cinfo, COL_INFO, ", PAN: 0x%04x", packet->dst_panID); + } + if (short_addr != IEEE802154_NO_ADDR16) { + col_append_fstr(pinfo->cinfo, COL_INFO, " Addr: 0x%04x", short_addr); + } + } + else { + /* Association was unsuccessful. */ + col_append_fstr(pinfo->cinfo, COL_INFO, ", Unsuccessful"); + } + } + + break; + } + case IEEE802154_CMD_DISAS:{ + guint8 reason; + + /* Check that the addressing is correct for this command type. */ + CMD_ADDR_CHECK((packet->src_addr_mode == ieee802154_addr64) + && (packet->dst_addr_mode == ieee802154_addr64), + "Disassociation Notification"); + + /* Get and display the dissasociation reason. */ + reason = tvb_get_guint8(tvb, offset); + if (tree) { + ti = proto_tree_add_uint(cmd_tree, hf_ieee802154_cmd_disas_reason, tvb, offset, 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 */ + } + offset += sizeof(guint8); + + break; + } + case IEEE802154_CMD_DATA_RQ:{ + /* Check that the addressing is correct for this command type. */ + CMD_ADDR_CHECK((packet->src_addr_mode != ieee802154_addr_none) + && (packet->dst_addr_mode != ieee802154_addr_none), + "Data Request"); + + /* Data Req contains no payload. */ + break; + } + case IEEE802154_CMD_PANID_ERR:{ + /* Check that the addressing is correct for this command type. */ + CMD_ADDR_CHECK((packet->src_addr_mode == ieee802154_addr64) + && (packet->dst_addr_mode == ieee802154_addr64), + "PANID Error"); + + /* PANID Err contains no payload. */ + break; + } + case IEEE802154_CMD_ORPH_NOTIF:{ + /* Check that the addressing is correct for this command type. */ + CMD_ADDR_CHECK((packet->src_addr_mode == ieee802154_addr64) + && (packet->dst_addr_mode == ieee802154_addr16) + && (packet->dst_addr16 == IEEE802154_BCAST_ADDR) + && (packet->src_panID == IEEE802154_BCAST_PAN) + && (packet->dst_panID == IEEE802154_BCAST_PAN), + "Orphan Notification"); + + /* Orphan Notification contains no payload. */ + break; + } + case IEEE802154_CMD_BCN_RQ:{ + /* Check that the addressing is correct for this command type. */ + CMD_ADDR_CHECK((packet->dst_addr_mode == ieee802154_addr16) + && (packet->src_addr_mode == ieee802154_addr_none) + && (packet->dst_addr16 == IEEE802154_BCAST_ADDR) + && (packet->dst_panID == IEEE802154_BCAST_PAN), + "Beacon Request"); + + /* Beacon Request contains no payload. */ + break; + } + case IEEE802154_CMD_COORD_REAL:{ + guint16 pan_id; + guint16 coord_addr; + guint8 channel; + guint16 short_addr; + + /* Check that the addressing is correct for this command type. */ + CMD_ADDR_CHECK((packet->src_addr_mode == ieee802154_addr64) + && (packet->dst_panID == IEEE802154_BCAST_PAN) + && (packet->dst_addr_mode != ieee802154_addr_none), + "Coordinator Realignment"); + + if (packet->dst_addr_mode == ieee802154_addr16) { + /* If directed to a 16-bit address, check that it is being broadcast. */ + CMD_ADDR_CHECK((packet->dst_addr16 == IEEE802154_BCAST_ADDR), "Coordinator Realignment"); + } + + /* Get and display the command PAN ID. */ + pan_id = tvb_get_letohs(tvb, offset); + if (tree) { + proto_tree_add_uint(cmd_tree, hf_ieee802154_cmd_coord_panID, tvb, offset, 2, pan_id); + } + if (check_col(pinfo->cinfo, COL_INFO)) { + col_append_fstr(pinfo->cinfo, COL_INFO, ", PAN: 0x%04x", pan_id); + } + offset += sizeof(guint16); + + /* Get and display the coordinator address. */ + coord_addr = tvb_get_letohs(tvb, offset); + if (tree) { + proto_tree_add_uint(cmd_tree, hf_ieee802154_cmd_coord_caddr16, tvb, offset, 2, coord_addr); + } + if (check_col(pinfo->cinfo, COL_INFO)) { + col_append_fstr(pinfo->cinfo, COL_INFO, ", Coordinator: 0x%04x", coord_addr); + } + offset += sizeof(guint16); + + /* Get and display the channel. */ + channel = tvb_get_guint8(tvb, offset); + if (tree) { + proto_tree_add_uint(cmd_tree, hf_ieee802154_cmd_coord_channel, tvb, offset, 1, channel); + } + if (check_col(pinfo->cinfo, COL_INFO)) { + col_append_fstr(pinfo->cinfo, COL_INFO, ", Channel: %u", channel); + } + offset += sizeof(guint8); + + /* Get and display the short address. */ + short_addr = tvb_get_letohs(tvb, offset); + if (tree) { + proto_tree_add_uint(cmd_tree, hf_ieee802154_cmd_coord_addr16, tvb, offset, 2, short_addr); + } + if ( (check_col(pinfo->cinfo, COL_INFO)) + && (packet->dst_addr_mode == ieee802154_addr64) + && (short_addr != IEEE802154_NO_ADDR16)) { + col_append_fstr(pinfo->cinfo, COL_INFO, ", Addr: 0x%04x", short_addr); + } + offset += sizeof(guint16); + + /* Get and display the channel page, if it exists. Added in IEEE802.15.4-2006 */ + if (tvb_bytes_exist(tvb, offset, sizeof(guint8))) { + guint8 channel_page = tvb_get_guint8(tvb, offset); + + if (tree) { + proto_tree_add_uint(cmd_tree, hf_ieee802154_cmd_coord_channel_page, tvb, offset, sizeof(guint8), channel_page); + } + offset += sizeof(guint8); + } + + break; + } + case IEEE802154_CMD_GTS_REQ:{ + guint8 characteristics; + guint8 length; + guint8 direction; + guint8 type; + + /* Check that the addressing is correct for this command type. */ + CMD_ADDR_CHECK((packet->src_addr_mode == ieee802154_addr16) + && (packet->dst_addr_mode == ieee802154_addr_none) + && (packet->src_addr16 != IEEE802154_BCAST_ADDR) + && (packet->src_addr16 != IEEE802154_NO_ADDR16), + "GTS Request"); + + /* Get and display the characteristics field. */ + characteristics = tvb_get_guint8(tvb, offset); + length = characteristics & IEEE802154_CMD_GTS_REQ_LEN; + direction = characteristics & IEEE802154_CMD_GTS_REQ_DIR; + type = characteristics & IEEE802154_CMD_GTS_REQ_TYPE; + if (tree) { + proto_tree_add_uint(cmd_tree, hf_ieee802154_cmd_gts_req_len, tvb, offset, 1, length); + ti = proto_tree_add_boolean(cmd_tree, hf_ieee802154_cmd_gts_req_dir, tvb, offset, 1, direction); + if (direction) proto_item_append_text(ti, " (Receive)"); + else proto_item_append_text(ti, " (Transmit)"); + ti = proto_tree_add_boolean(cmd_tree, hf_ieee802154_cmd_gts_req_type, tvb, offset, 1, type); + if (type) proto_item_append_text(ti, " (Allocate GTS)"); + else proto_item_append_text(ti, " (Deallocate GTS)"); + } + offset += sizeof(guint8); + + break; + } + default: + break; + } /* switch */ + + /* If there are bytes leftover, call the data dissector to handle them. */ + if (offset < tvb_length(tvb)) { + guint leftover_len = tvb_length(tvb) - offset; + proto_tree *root = proto_tree_get_root(tree); + tvbuff_t *leftover_tvb = tvb_new_subset(tvb, offset, leftover_len, leftover_len); + + /* Call the data dissector. */ + if (leftover_tvb) call_dissector(data_handle, leftover_tvb, pinfo, root); + } +} /* dissect_ieee802154_cmd */ + +/*FUNCTION:------------------------------------------------------ + * NAME + * proto_register_ieee802154 + * DESCRIPTION + * IEEE 802.15.4 protocol registration routine. + * PARAMETERS + * none + * RETURNS + * void + *--------------------------------------------------------------- + */ +void proto_register_ieee802154(void) +{ + module_t *ieee802154_module; + + static hf_register_info hf[] = { + { &hf_ieee802154_frame_type, + { "Frame Type", "ieee802154.frame_type", FT_UINT16, BASE_DEC, NULL, IEEE802154_FCF_TYPE_MASK, + "", HFILL }}, + + { &hf_ieee802154_security_enable, + { "Security Enabled", "ieee802154.security_enable", FT_BOOLEAN, 16, NULL, IEEE802154_FCF_SEC_EN, + "Whether security operations are performed at the MAC layer or not.", HFILL }}, + + { &hf_ieee802154_frame_pending, + { "Frame Pending", "ieee802154.frame_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", "ieee802154.ack_request", FT_BOOLEAN, 16, NULL, IEEE802154_FCF_ACK_REQ, + "Whether the sender of this packet requests acknowledgement or not.", HFILL }}, + + { &hf_ieee802154_intra_pan, + { "Intra-PAN", "ieee802154.intra_pan", FT_BOOLEAN, 16, NULL, IEEE802154_FCF_INTRA_PAN, + "Whether this packet originated and terminated within the same PAN or not.", HFILL }}, + + { &hf_ieee802154_seqno, + { "Sequence Number", "ieee802154.seq_no", FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + { &hf_ieee802154_src_addr_mode, + { "Source Addressing Mode", "ieee802154.src_addr_mode", FT_UINT16, BASE_DEC, NULL, IEEE802154_FCF_SADDR, + "", HFILL }}, + + { &hf_ieee802154_dst_addr_mode, + { "Destination Addressing Mode", "ieee802154.dst_addr_mode", FT_UINT16, BASE_DEC, NULL, IEEE802154_FCF_DADDR, + "", HFILL }}, + + { &hf_ieee802154_version, + { "Frame Version", "ieee802154.version", FT_UINT16, BASE_DEC, NULL, IEEE802154_FCF_VERSION, + "", HFILL }}, + + { &hf_ieee802154_dst_panID, + { "Destination PAN", "ieee802154.dst_pan", FT_UINT16, BASE_HEX, NULL, 0x0, + "", HFILL }}, + + { &hf_ieee802154_dst_addr16, + { "Destination", "ieee802154.dst_addr16", FT_UINT16, BASE_HEX, NULL, 0x0, + "", HFILL }}, + + { &hf_ieee802154_dst_addr64, + { "Destination", "ieee802154.dst_addr64", FT_UINT64, BASE_HEX, NULL, 0x0, + "", HFILL }}, + + { &hf_ieee802154_src_panID, + { "Source PAN", "ieee802154.src_pan", FT_UINT16, BASE_HEX, NULL, 0x0, + "", HFILL }}, + + { &hf_ieee802154_src_addr16, + { "Source", "ieee802154.src_addr16", FT_UINT16, BASE_HEX, NULL, 0x0, + "", HFILL }}, + + { &hf_ieee802154_src_addr64, + { "Source", "ieee802154.src_addr64", FT_UINT64, BASE_HEX, NULL, 0x0, + "", HFILL }}, + + { &hf_ieee802154_crc, + { "CRC", "ieee802154.crc", FT_UINT16, BASE_HEX, NULL, 0x0, + "", HFILL }}, + + { &hf_ieee802154_rssi, + { "RSSI", "ieee802154.rssi", FT_INT8, BASE_DEC, NULL, 0x0, + "Received Signal Strength", HFILL }}, + + { &hf_ieee802154_crc_ok, + { "CRC Valid", "ieee802154.crc_ok", FT_BOOLEAN, 8, NULL, 0x0, + "", HFILL }}, + + { &hf_ieee802154_correlation, + { "LQI Correlation Value", "ieee802154.correlation", FT_UINT8, BASE_DEC, NULL, 0x0, + "", HFILL }}, + + /* Command Frame Specific Fields */ + /*--------------------------------*/ + + { &hf_ieee802154_cmd_frm_id, + { "Command Frame Identifier", "ieee802154.cmd.frm_id", FT_UINT8, BASE_HEX, NULL, 0x0, + "", HFILL }}, + + { &hf_ieee802154_cmd_payload, + { "Command Payload", "ieee802154.cmd.payload", FT_NONE, BASE_NONE, NULL, 0x0, + "", HFILL }}, + + /* Capability Information Fields */ + { &hf_ieee802154_cmd_cinfo_alt_pan_coord, + { "Alternate PAN Coordinator", "ieee802154.cmd.cinfo.alt_pan_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_cmd_cinfo_device_type, + { "Device Type", "ieee802154.cmd.cinfo.device_type", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_DEVICE_TYPE, + "Whether this device is RFD (reduced-function device) or FFD (full-function device).", HFILL }}, + + { &hf_ieee802154_cmd_cinfo_power_src, + { "Power Source", "ieee802154.cmd.cinfo.power_src", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_POWER_SRC, + "Whether this device is operating on AC/mains or battery power.", HFILL }}, + + { &hf_ieee802154_cmd_cinfo_idle_rx, + { "Receive On When Idle", "ieee802154.cmd.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_cmd_cinfo_sec_capable, + { "Security Capability", "ieee802154.cmd.cinfo.sec_capable", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_SEC_CAPABLE, + "Whether this device is capable of receiving encrypted packets.", HFILL }}, + + { &hf_ieee802154_cmd_cinfo_alloc_addr, + { "Allocate Address", "ieee802154.cmd.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_cmd_asrsp_shrt_addr, + { "Short Address", "ieee802154.cmd.asrsp.shrt_addr", FT_UINT16, BASE_HEX, NULL, 0x0, + "The short address that the device should assume.\nAn address of 0xfffe indicates that the device should use its IEEE 64-bit long address.", HFILL }}, + + { &hf_ieee802154_cmd_asrsp_assoc_status, + { "Association Status", "ieee802154.cmd.asrsp.assoc_status", FT_UINT8, BASE_HEX, NULL, 0x0, + "", HFILL }}, + + { &hf_ieee802154_cmd_disas_reason, + { "Disassociation Reason", "ieee802154.cmd.disas.reason", FT_UINT8, BASE_HEX, NULL, 0x0, + "", HFILL }}, + + /* Coordinator Realignment fields */ + { &hf_ieee802154_cmd_coord_panID, + { "PAN ID", "ieee802154.cmd.coord.panID", FT_UINT16, BASE_HEX, NULL, 0x0, + "The PAN identifier the coordinator wishes to use for future communication.", HFILL }}, + + { &hf_ieee802154_cmd_coord_caddr16, + { "Coordinator Short Address", "ieee802154.cmd.coord.caddr16", FT_UINT16, BASE_HEX, NULL, 0x0, + "The 16-bit address the coordinator wishes to use for future communication.", HFILL }}, + + { &hf_ieee802154_cmd_coord_channel, + { "Logical Channel", "ieee802154.cmd.coord.channel", FT_UINT8, BASE_DEC, NULL, 0x0, + "The logical channel the coordinator wishes to use for future communication.", HFILL }}, + + { &hf_ieee802154_cmd_coord_addr16, + { "Short Address", "ieee802154.cmd.coord.addr16", FT_UINT16, BASE_HEX, NULL, 0x0, + "A short-address that the orphaned device shall assume if applicable.", HFILL }}, + + { &hf_ieee802154_cmd_coord_channel_page, + { "Channel Page", "ieee802154.cmd.coord.channel_page", FT_UINT8, BASE_DEC, NULL, 0x0, + "The logical channel page the coordinator wishes to use for future communication.", HFILL }}, + + { &hf_ieee802154_cmd_gts_req_len, + { "GTS Length", "ieee802154.cmd.gts.length", FT_UINT8, BASE_DEC, NULL, IEEE802154_CMD_GTS_REQ_LEN, + "Number of superframe slots the device is requesting.", HFILL }}, + + { &hf_ieee802154_cmd_gts_req_dir, + { "GTS Direction", "ieee802154.cmd.gts.direction", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_GTS_REQ_DIR, + "The direction of traffic in the guaranteed timeslot.", HFILL }}, + + { &hf_ieee802154_cmd_gts_req_type, + { "Characteristic Type", "ieee802154.cmd.gts.char_type", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_GTS_REQ_TYPE, + "Whether this request is to allocate or deallocate a timeslot.", HFILL }}, + + /* Beacon Frame Specific Fields */ + /*-------------------------------*/ + { &hf_ieee802154_bcn_sfrm_bo, + { "Beacon Interval", "ieee802154.bcn.sfrm.bo", FT_UINT8, BASE_DEC, NULL, 0x0, + "Specifies the transmission interval of the beacons.", HFILL }}, + + { &hf_ieee802154_bcn_sfrm_sfo, + { "Superframe Interval", "ieee802154.bcn.sfrm.sfo", FT_UINT8, BASE_DEC, NULL, 0x0, + "Specifies the length of time the coordinator will interact with the PAN.", HFILL }}, + + { &hf_ieee802154_bcn_sfrm_CAP_slot, + { "Final CAP Slot", "ieee802154.bcn.sfrm.CAP_slot", FT_UINT8, BASE_DEC, NULL, 0x0, + "Specifies the final superframe slot used by the CAP.", HFILL }}, + + { &hf_ieee802154_bcn_sfrm_batt_extn, + { "Battery Extension", "ieee802154.bcn.sfrm.batt_extn", FT_BOOLEAN, 8, NULL, IEEE802154_BCN_BATT_EXTN_MASK, + "Whether transmissions may not extend past the length of the beacon frame.", HFILL }}, + + { &hf_ieee802154_bcn_sfrm_coord, + { "PAN Coordinator", "ieee802154.bcn.sfrm.coord", FT_BOOLEAN, 8, NULL, IEEE802154_BCN_COORD_MASK, + "Whether this beacon frame is being transmitted by the PAN coordinator or not.", HFILL }}, + + { &hf_ieee802154_bcn_sfrm_assoc_perm, + { "Association Permit", "ieee802154.bcn.sfrm.assoc_perm", FT_BOOLEAN, 8, NULL, IEEE802154_BCN_ASSOC_PERM_MASK, + "Whether this PAN is accepting association requests or not.", HFILL }}, + + { &hf_ieee802154_bcn_gts_desc_count, + { "GTS Descriptor Count", "ieee802154.bcn.gts.desc_count", FT_UINT8, BASE_DEC, NULL, 0x0, + "The number of GTS descriptors present in this beacon frame.", HFILL }}, + + { &hf_ieee802154_bcn_gts_permit, + { "GTS Permit", "ieee802154.bcn.gts.permit", FT_BOOLEAN, 8, NULL, 0x0, + "Whether the PAN coordinator is accepting GTS requests or not.", HFILL }}, + + { &hf_ieee802154_bcn_gts_direction[0], + { "GTS Slot 1", "ieee802154.bcn.gts.slot_1", FT_BOOLEAN, 8, NULL, IEEE802154_BCN_GTS_DIRECTION_SLOT1, + "A flag defining the direction of the first GTS Slot.", HFILL }}, + + { &hf_ieee802154_bcn_gts_direction[1], + { "GTS Slot 2", "ieee802154.bcn.gts.slot_1", FT_BOOLEAN, 8, NULL, IEEE802154_BCN_GTS_DIRECTION_SLOT2, + "A flag defining the direction of the second GTS Slot.", HFILL }}, + + { &hf_ieee802154_bcn_gts_direction[2], + { "GTS Slot 3", "ieee802154.bcn.gts.slot_1", FT_BOOLEAN, 8, NULL, IEEE802154_BCN_GTS_DIRECTION_SLOT3, + "A flag defining the direction of the third GTS Slot.", HFILL }}, + + { &hf_ieee802154_bcn_gts_direction[3], + { "GTS Slot 4", "ieee802154.bcn.gts.slot_1", FT_BOOLEAN, 8, NULL, IEEE802154_BCN_GTS_DIRECTION_SLOT4, + "A flag defining the direction of the fourth GTS Slot.", HFILL }}, + + { &hf_ieee802154_bcn_gts_direction[4], + { "GTS Slot 5", "ieee802154.bcn.gts.slot_1", FT_BOOLEAN, 8, NULL, IEEE802154_BCN_GTS_DIRECTION_SLOT5, + "A flag defining the direction of the fifth GTS Slot.", HFILL }}, + + { &hf_ieee802154_bcn_gts_direction[5], + { "GTS Slot 6", "ieee802154.bcn.gts.slot_1", FT_BOOLEAN, 8, NULL, IEEE802154_BCN_GTS_DIRECTION_SLOT6, + "A flag defining the direction of the sixth GTS Slot.", HFILL }}, + + { &hf_ieee802154_bcn_gts_direction[6], + { "GTS Slot 7", "ieee802154.bcn.gts.slot_1", FT_BOOLEAN, 8, NULL, IEEE802154_BCN_GTS_DIRECTION_SLOT7, + "A flag defining the direction of the seventh GTS Slot.", HFILL }} + }; + + static gint *ett[] = { + &ett_ieee802154, + &ett_ieee802154_fcf, + &ett_ieee802154_fcs, + &ett_ieee802154_cmd, + &ett_ieee802154_cmd_cinfo, + &ett_ieee802154_bcn, + &ett_ieee802154_bcn_sfrm_spec, + &ett_ieee802154_bcn_gts_spec, + &ett_ieee802154_bcn_gts_direct, + &ett_ieee802154_bcn_gts_device[0], + &ett_ieee802154_bcn_gts_device[1], + &ett_ieee802154_bcn_gts_device[2], + &ett_ieee802154_bcn_gts_device[3], + &ett_ieee802154_bcn_gts_device[4], + &ett_ieee802154_bcn_gts_device[5], + &ett_ieee802154_bcn_gts_device[6], + &ett_ieee802154_bcn_paddrs + }; + + static enum_val_t enum_crc_handler[] = { + {"ignore_error", "Ignore bad CRC, and process the packet as though the CRC is valid.", 0}, + {"accept_packet", "Display IEEE 802.15.4 packet, but disable any further sub-dissection. (Default)", 1}, + {"ignore_packet", "Ignore packet altogether.", 2}, + {NULL, NULL, -1} + }; + + /* Register Protocol name and description. */ + proto_ieee802154 = proto_register_protocol("IEEE 802.15.4 Protocol", "IEEE 802.15.4", "ieee802154"); + + /* Register header fields and subtrees. */ + proto_register_field_array(proto_ieee802154, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + /* Register the subdissector list */ + register_heur_dissector_list("ieee802154", &ieee802154_heur_subdissector_list); + + /* Register Preferences Module */ + ieee802154_module = prefs_register_protocol(proto_ieee802154, proto_reg_handoff_ieee802154); + + prefs_register_bool_preference(ieee802154_module, "ignore_bad_crc", + "Ignore Bad CRC", + "Allow further sub-dissection of packets with bad CRC values.", + &gPREF_ignore_bad_crc); + + /* Register dissectors with Ethereal. */ + register_dissector("ieee802154", dissect_ieee802154, proto_ieee802154); + register_dissector("ieee802154_maybefcs", dissect_ieee802154_maybefcs, proto_ieee802154); + register_dissector("ieee802154_nofcs", dissect_ieee802154_nofcs, proto_ieee802154); + register_dissector("ieee802154_ccfcs", dissect_ieee802154_ccfcs, proto_ieee802154); +} /* proto_register_ieee802154 */ + +/*FUNCTION:------------------------------------------------------ + * NAME + * proto_reg_handoff_ieee802154 + * DESCRIPTION + * Registers the zigbee dissector with Ethereal. + * Will be called every time 'apply' is pressed in the preferences menu. + * PARAMETERS + * none + * RETURNS + * void + *--------------------------------------------------------------- + */ +void proto_reg_handoff_ieee802154(void) +{ + dissector_handle_t ieee802154_handle; + + /* Get the dissector handles. */ + ieee802154_handle = find_dissector("ieee802154_maybefcs"); + data_handle = find_dissector("data"); + + /* Register dissector handles. */ + dissector_add("wtap_encap", WTAP_ENCAP_IEEE802_15_4, ieee802154_handle); +} /* proto_reg_handoff_ieee802154 */ + Index: epan/dissectors/packet-ieee802154.h =================================================================== --- epan/dissectors/packet-ieee802154.h (revision 0) +++ epan/dissectors/packet-ieee802154.h (revision 0) @@ -0,0 +1,191 @@ +/* packet-ieee802154.h + * + * $Id: $ + * + * IEEE 802.15.4 Dissectors for Wireshark + * By Owen Kirby <osk@xxxxxxxxxx> + * Copyright 2007 Exegin Technologies Limited + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@xxxxxxxxxxxxx> + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef PACKET_IEEE802154_H +#define PACKET_IEEE802154_H + +/* Structure containing information regarding all necessary packet feilds */ +typedef struct { + guint fcs_mode; + + gint32 payload_length; + gint32 payload_offset; + + /* Frame control field. */ + guint16 fcf; + gint32 version; + gint32 frame_type; + gint32 dst_addr_mode; + gint32 src_addr_mode; + gboolean security_enable; + gboolean frame_pending; + gboolean ack_request; + gboolean intra_pan; + + guint8 seqno; + + /* Addressing Info. */ + guint16 dst_panID; + union { + guint16 dst_addr16; + guint64 dst_addr64; + }; + guint16 src_panID; + union { + guint16 src_addr16; + guint64 src_addr64; + }; + + /* Frame check sequence. */ + gint8 rssi; + guint8 correlation; + guint16 crc; + gboolean crc_ok; +} ieee802154_packet; + +/* Enumerations of IEEE802.15.4 frame types, and addressing modes */ +enum { + ieee802154_beacon = 0, + ieee802154_data = 1, + ieee802154_ack = 2, + ieee802154_cmd = 3, + ieee802154_reserved = 4 +}; + +enum { + ieee802154_addr_none = 0, + ieee802154_addr16 = 2, + ieee802154_addr64 = 3, + ieee802154_addr_invalid = 1 +}; + +/* Packet Overhead from MAC header + footer (excluding addressing) */ +#define IEEE802154_MAC_HDR_OVRHD 3 +#define IEEE802154_MAC_FTR_OVRHD 2 + +/* Command Frame Identifier Types Definions */ +#define IEEE802154_CMD_ASRQ 0x01 +#define IEEE802154_CMD_ASRSP 0x02 +#define IEEE802154_CMD_DISAS 0x03 +#define IEEE802154_CMD_DATA_RQ 0x04 +#define IEEE802154_CMD_PANID_ERR 0x05 +#define IEEE802154_CMD_ORPH_NOTIF 0x06 +#define IEEE802154_CMD_BCN_RQ 0x07 +#define IEEE802154_CMD_COORD_REAL 0x08 +#define IEEE802154_CMD_GTS_REQ 0x09 +#define IEEE802145_CMD_MAX_ID 0x09 + +/* Definitions for Association Response Command */ +#define IEEE802154_CMD_ASRSP_AS_SUCCESS 0x00 +#define IEEE802154_CMD_ASRSP_PAN_FULL 0x01 +#define IEEE802154_CMD_ASRSP_PAN_DENIED 0x02 + +/* Bit Masks for Capability Information Feild + Included in Association Req. command */ +#define IEEE802154_CMD_CINFO_ALT_PAN_COORD 0x01 +#define IEEE802154_CMD_CINFO_DEVICE_TYPE 0x02 +#define IEEE802154_CMD_CINFO_POWER_SRC 0x04 +#define IEEE802154_CMD_CINFO_IDLE_RX 0x08 +#define IEEE802154_CMD_CINFO_SEC_CAPABLE 0x40 +#define IEEE802154_CMD_CINFO_ALLOC_ADDR 0x80 + +#define IEEE802154_CMD_GTS_REQ_LEN 0x0F +#define IEEE802154_CMD_GTS_REQ_DIR 0x10 +#define IEEE802154_CMD_GTS_REQ_TYPE 0x20 + +/* Bit masks & shifts for various beacon fields */ +#define IEEE802154_BCN_BO_MASK 0x0F +#define IEEE802154_BCN_SFO_MASK 0xF0 +#define IEEE802154_BCN_CAP_MASK 0x0F +#define IEEE802154_BCN_BATT_EXTN_MASK 0x10 +#define IEEE802154_BCN_COORD_MASK 0x40 +#define IEEE802154_BCN_ASSOC_PERM_MASK 0x80 +#define IEEE802154_BCN_SFO_SHIFT 4 + +#define IEEE802154_BCN_GTS_COUNT_MASK 0x03 +#define IEEE802154_BCN_GTS_PERMIT_MASK 0x80 +#define IEEE802154_BCN_GTS_DIRECTION_SLOT(i) (0x01<<(i)) +#define IEEE802154_BCN_GTS_MAX_SLOTS 7 +#define IEEE802154_BCN_GTS_DIRECTION_SLOT1 0x01 +#define IEEE802154_BCN_GTS_DIRECTION_SLOT2 0x02 +#define IEEE802154_BCN_GTS_DIRECTION_SLOT3 0x04 +#define IEEE802154_BCN_GTS_DIRECTION_SLOT4 0x08 +#define IEEE802154_BCN_GTS_DIRECTION_SLOT5 0x10 +#define IEEE802154_BCN_GTS_DIRECTION_SLOT6 0x20 +#define IEEE802154_BCN_GTS_DIRECTION_SLOT7 0x40 +#define IEEE802154_BCN_GTS_SLOT_MASK 0x0F +#define IEEE802154_BCN_GTS_LENGTH_MASK 0xF0 +#define IEEE802154_BCN_GTS_LENGTH_SHIFT 4 + +#define IEEE802154_BCN_PADDR_SHORT_MASK 0x07 +#define IEEE802154_BCN_PADDR_LONG_MASK 0x70 +#define IEEE802154_BCN_PADDR_LONG_SHIFT 4 + +#define IEEE802154_BCN_SFRM_DURATION (IEEE802154_BCN_SLOT_DURATION * IEEE802154_BCN_NUM_SLOTS) +#define IEEE802154_BCN_SLOT_DURATION 60 +#define IEEE802154_BCN_NUM_SLOTS 16 + +/* Bit-masks for the FCF + * Note: bit order of FCF is little-endian, but + * byte-order is big-endian. + */ +#define IEEE802154_FCF_BEACON 0x0000 //Frame Types; +#define IEEE802154_FCF_DATA 0x0100 +#define IEEE802154_FCF_ACK 0x0200 +#define IEEE802154_FCF_CMD 0x0300 + +#define IEEE802154_FCF_TYPE_MASK 0x0700 +#define IEEE802154_FCF_SEC_EN 0x0800 +#define IEEE802154_FCF_FRAME_PND 0x1000 +#define IEEE802154_FCF_ACK_REQ 0x2000 +#define IEEE802154_FCF_INTRA_PAN 0x4000 +#define IEEE802154_FCF_VERSION 0x0030 + +#define IEEE802154_FCF_SADDR 0x00C0 /* destination addressing mask */ +#define IEEE802154_FCF_SADDR0 0x0000 /* destination addr field contains no PAN or source */ +#define IEEE802154_FCF_SADDR16 0x0080 /* destination addr field contains 16-bit addr */ +#define IEEE802154_FCF_SADDR64 0x00C0 /* destination addr field contains 64-bit addr */ + +#define IEEE802154_FCF_DADDR 0x000C /* source addressing mask */ +#define IEEE802154_FCF_DADDR0 0x0000 /* source addr field contains no PAN or source */ +#define IEEE802154_FCF_DADDR16 0x0008 /* source addr field contsins 16-bit addr */ +#define IEEE802154_FCF_DADDR64 0x000C /* source addr field contains 64-bit addr */ + +/* Bit-masks for CC24xx style FCS */ +#define CC2420_FCS_CORR_MASK 0x7F +#define CC2420_FCS_CRC_OK 0x80 + +/* Special IEEE802.15.4 Addresses */ +#define IEEE802154_NO_ADDR16 0xFFFE +#define IEEE802154_BCAST_ADDR 0xFFFF +#define IEEE802154_BCAST_PAN 0xFFFF + +/* FCS modes. */ +#define IEEE802154_FCS_NONE 0x00 +#define IEEE802154_FCS_CRC 0x01 +#define IEEE802154_FCS_CHIPCON 0x02 + +#endif /* PACKET_IEEE802154_H */ Index: wiretap/libpcap.c =================================================================== --- wiretap/libpcap.c (revision 22248) +++ wiretap/libpcap.c (working copy) @@ -99,6 +99,13 @@ #define LAPD_SLL_PROTOCOL_OFFSET 14 /* protocol, should be ETH_P_LAPD - 2 bytes */ #define LAPD_SLL_LEN 16 /* length of the header */ +/* + * A header containing additional IEEE 802.15.4 information. + */ +#define IEEE802154_SLL_LENGTH_OFFSET 0 /* Offset of the length byte. */ +#define IEEE802154_SLL_LENGTH_MASK 0x7f /* Mask that should be applied to the length byte. */ +#define IEEE802154_SLL_LEN 1 /* Length of the header. */ + /* See source to the "libpcap" library for information on the "libpcap" file format. */ @@ -143,6 +150,10 @@ union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info); static gboolean libpcap_read_linux_usb_pseudoheader(wtap *wth, FILE_T fh, union wtap_pseudo_header *pseudo_header, int *err); +static gboolean libpcap_get_ieee802154_pseudoheader(const guint8 *ieee802154_phdr, + union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info); +static gboolean libpcap_read_ieee802154_pseudoheader(FILE_T fh, + union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info); static gboolean libpcap_read_rec_data(FILE_T fh, guchar *pd, int length, int *err); static void libpcap_close(wtap *wth); @@ -429,6 +440,8 @@ { 189, WTAP_ENCAP_USB_LINUX }, /* Per-Packet Information header */ { 192, WTAP_ENCAP_PPI }, + /* IEEE 802.15.4 Packets. */ + { 195, WTAP_ENCAP_IEEE802_15_4}, /* * To repeat: @@ -1388,6 +1401,29 @@ packet_size -= sizeof (struct linux_usb_phdr); wth->data_offset += sizeof (struct linux_usb_phdr); break; + + case WTAP_ENCAP_IEEE802_15_4: + if (packet_size < IEEE802154_SLL_LEN) { + /* + * Uh-oh, the packet isn't big enough to even + * have a pseudo-header. + */ + *err = WTAP_ERR_BAD_RECORD; + *err_info = g_strdup_printf("libpcap: IEEE 802.15.4 file has a %u-byte packet, too small to have even an IEEE 802.15.4 pseudo-header\n", + packet_size); + return FALSE; + } + if (!libpcap_read_ieee802154_pseudoheader(wth->fh, &wth->pseudo_header, + err, err_info)) + return FALSE; /* Read error */ + + /* + * Don't count the pseudo-header as part of the packet. + */ + orig_size -= IEEE802154_SLL_LEN; + packet_size -= IEEE802154_SLL_LEN; + wth->data_offset += IEEE802154_SLL_LEN; + break; } buffer_assure_space(wth->frame_buffer, packet_size); @@ -1513,6 +1549,12 @@ pseudo_header, err)) return FALSE; /* Read error */ break; + + case WTAP_ENCAP_IEEE802_15_4: + if (!libpcap_read_ieee802154_pseudoheader(wth->random_fh, pseudo_header, + err, err_info)) + return FALSE; /* Read error */ + break; } /* @@ -1931,6 +1973,34 @@ } static gboolean +libpcap_get_ieee802154_pseudoheader(const guint8 *ieee802154_phdr, + union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info) +{ + pseudo_header->ieee802154.length = ieee802154_phdr[IEEE802154_SLL_LENGTH_OFFSET] & IEEE802154_SLL_LENGTH_MASK; + return TRUE; +} + +static gboolean +libpcap_read_ieee802154_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header, + int *err, gchar **err_info) +{ + guint8 ieee802154_phdr[IEEE802154_SLL_LEN]; + int bytes_read; + + errno = WTAP_ERR_CANT_READ; + bytes_read = file_read(ieee802154_phdr, 1, IEEE802154_SLL_LEN, fh); + if (bytes_read != IEEE802154_SLL_LEN) { + *err = file_error(fh); + if (*err == 0) + *err = WTAP_ERR_SHORT_READ; + return FALSE; + } + + return libpcap_get_ieee802154_pseudoheader(ieee802154_phdr, pseudo_header, err, + err_info); +} + +static gboolean libpcap_read_rec_data(FILE_T fh, guchar *pd, int length, int *err) { int bytes_read; @@ -2159,6 +2229,28 @@ whdr->caplen -= sizeof (struct linux_usb_phdr); pd += sizeof (struct linux_usb_phdr); break; + + case WTAP_ENCAP_IEEE802_15_4: + if (whdr->caplen < IEEE802154_SLL_LEN) { + /* + * Uh-oh, the packet isn't big enough to even + * have a pseudo-header. + */ + g_message("libpcap: IEEE 802.15.4 capture has a %u-byte packet, too small to have even an IEEE 802.15.4 pseudo-header\n", + whdr->caplen); + *err = WTAP_ERR_BAD_RECORD; + return NULL; + } + if (!libpcap_get_ieee802154_pseudoheader(pd, pseudo_header, err, NULL)) + return NULL; + + /* + * Don't count the pseudo-header as part of the packet. + */ + whdr->len -= IEEE802154_SLL_LEN; + whdr->caplen -= IEEE802154_SLL_LEN; + pd += IEEE802154_SLL_LEN; + break; } return pd; } @@ -2274,6 +2366,7 @@ guint8 irda_hdr[IRDA_SLL_LEN]; guint8 lapd_hdr[LAPD_SLL_LEN]; guint8 mtp2_hdr[MTP2_HDR_LEN]; + guint8 ieee802154_hdr[IEEE802154_SLL_LEN]; int hdrsize; switch (wdh->encap) { @@ -2298,6 +2391,10 @@ hdrsize = sizeof (struct linux_usb_phdr); break; + case WTAP_ENCAP_IEEE802_15_4: + hdrsize = IEEE802154_SLL_LEN; + break; + default: hdrsize = 0; break; @@ -2507,6 +2604,23 @@ } wdh->bytes_dumped += sizeof(lapd_hdr); break; + + case WTAP_ENCAP_IEEE802_15_4: + /* + * Write the IEEE 802.15.4 header. + */ + memset(ieee802154_hdr, 0, sizeof(ieee802154_hdr)); + ieee802154_hdr[IEEE802154_SLL_LENGTH_OFFSET] = pseudo_header->ieee802154.length; + nwritten = wtap_dump_file_write(wdh, ieee802154_hdr, sizeof(ieee802154_hdr)); + if (nwritten != sizeof(ieee802154_hdr)) { + if (nwritten == 0 && wtap_dump_file_ferror(wdh)) + *err = wtap_dump_file_ferror(wdh); + else + *err = WTAP_ERR_SHORT_WRITE; + return FALSE; + } + wdh->bytes_dumped += sizeof(ieee802154_hdr); + break; } nwritten = wtap_dump_file_write(wdh, pd, phdr->caplen); Index: wiretap/wtap.c =================================================================== --- wiretap/wtap.c (revision 22248) +++ wiretap/wtap.c (working copy) @@ -375,11 +375,17 @@ /* WTAP_ENCAP_NETTL_RAW_TELNET */ { "Raw telnet with nettl headers", "raw-telnet-nettl" }, + /* WTAP_ENCAP_USB_LINUX */ + { "USB-Linux packets", "usb" }, + /* WTAP_ENCAP_MPEG */ { "MPEG", "mpeg" }, /* WTAP_ENCAP_PPI */ { "Per-Packet Information header", "ppi" }, + + /* WTAP_ENCAP_IEEE802_15_4 */ + { "IEEE 802.15.4", "ieee802154" }, }; gint wtap_num_encap_types = sizeof(encap_table_base) / sizeof(struct encap_type_info); Index: wiretap/wtap.h =================================================================== --- wiretap/wtap.h (revision 22248) +++ wiretap/wtap.h (working copy) @@ -192,6 +192,7 @@ #define WTAP_ENCAP_USB_LINUX 95 #define WTAP_ENCAP_MPEG 96 #define WTAP_ENCAP_PPI 97 +#define WTAP_ENCAP_IEEE802_15_4 98 #define WTAP_NUM_ENCAP_TYPES wtap_get_num_encap_types() @@ -606,6 +607,12 @@ guint32 data_len; /* amount of urb data really present in this event*/ }; +/* Packet "pseudo-header" for IEEE 802.15.4. */ +/* This is actually the IEEE 802.15.4 PHY header, and is nothing more than a length byte. */ +struct ieee802154_phdr { + guint8 length; +}; + union wtap_pseudo_header { struct eth_phdr eth; struct x25_phdr x25; @@ -622,6 +629,7 @@ struct lapd_phdr lapd; struct catapult_dct2000_phdr dct2000; struct linux_usb_phdr linux_usb; + struct ieee802154_phdr ieee802154; }; struct wtap_nstime {
- Follow-Ups:
- Re: [Wireshark-dev] [PATCH] IEEE 802.15.4 dissectors and libpcap support.
- From: Richard van der Hoff
- Re: [Wireshark-dev] [PATCH] IEEE 802.15.4 dissectors and libpcap support.
- Prev by Date: Re: [Wireshark-dev] [PATCH]: New packet disscetor for IEEE1588v2 / PTPv2
- Next by Date: Re: [Wireshark-dev] [Wireshark-commits] rev 22259: /trunk/packaging/nsis/ /trunk/packaging/nsis/: wireshark.nsi
- Previous by thread: Re: [Wireshark-dev] TCP Reassembly issues
- Next by thread: Re: [Wireshark-dev] [PATCH] IEEE 802.15.4 dissectors and libpcap support.
- Index(es):