Wireshark-dev: [Wireshark-dev] [PATCH] IEEE 802.15.4 dissector and libpcap support
From: Owen Kirby <[email protected]>
Date: Thu, 21 Jun 2007 16:34:09 -0700
I work at Exegin Technologies, and we have for a few years now, had some dissector plugins for the IEEE 802.15.4 protocol. We have recently decided to move them into the open-source community. Furthermore, a few weeks ago, a DLT_ value was assigned to IEEE 802.15.4 networks, we have also added support for capturing from libpcap with this DLT network type.
This patch includes the dissector code and modifications to wiretap in 
order to support IEEE 802.15.4, and this is set up to compile the IEEE 
802.15.4 dissectors into libwireshark.
Thanks,
Owen Kirby
Index: epan/dissectors/Makefile.common
===================================================================
--- epan/dissectors/Makefile.common	(revision 22151)
+++ 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		\
@@ -876,6 +877,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,1799 @@
+/* packet-ieee802154.c
+ * 2007  Owen Kirby <[email protected]>
+ *
+ * $Id: $
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <[email protected]>
+ * 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_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_channel = -1;
+static int hf_ieee802154_lqi = -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_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_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. This is also the entry point for
+ *      raw wiretap captures.
+ *
+ *  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;
+
+    /* Check to see if this is a raw capture (not encapsulated by some
+     * other layer). Checking the link-layer type should detect this unless
+     * we have IEEE 802.15.4 encapsulated within another IEEE 802.15.4 packet
+     * which is a little bit weird... Ideally we should just check to see if
+     * we are the first dissector called after the frame dissector, but I can't
+     * find any method to do this which works consistantly. */
+    if (pinfo->fd->lnk_t == WTAP_ENCAP_IEEE802_15_4) {
+        /* Raw wiretap capture. */
+        packet.have_phdr = TRUE;
+        packet.channel = pinfo->pseudo_header->ieee802154.channel;
+        packet.lqi = pinfo->pseudo_header->ieee802154.lqi;
+        packet.fcs_mode = pinfo->pseudo_header->ieee802154.fcs_mode;
+    }
+    else {
+        /* This was encapsulated by another layer. */
+        packet.have_phdr = FALSE;
+        packet.fcs_mode = IEEE802154_FCS_CRC;
+    }
+
+    /* Call the common dissector. */
+    dissect_ieee802154_common(tvb, pinfo, tree);
+} /* dissect_ieee802154 */
+
+/*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 pseudo header and no FCS. */
+    packet.have_phdr = FALSE;
+    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 no pseudo header and a ChipCon/TI FCS. */
+    packet.have_phdr = FALSE;
+    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));
+    }
+
+    /* If present, add the radio capture info. */
+    if ((packet->have_phdr) && (packet->channel != -1)) {
+        if (tree) {
+            proto_tree_add_uint(ieee802154_tree, hf_ieee802154_channel, tvb, 0, 0, packet->channel);
+            proto_tree_add_uint(ieee802154_tree, hf_ieee802154_lqi, tvb, 0, 0, packet->lqi);
+        }
+        if (check_col(pinfo->cinfo, COL_RSSI)) {
+            col_clear(pinfo->cinfo, COL_RSSI);
+            col_add_fstr(pinfo->cinfo, COL_RSSI, "%u%%", (100 * packet->lqi)/0xff);
+        }
+        if (check_col(pinfo->cinfo, COL_TX_RATE)) {
+            if (packet->channel == 0) {
+                /* 898MHz: EU band: Channel 0 */
+                col_set_str(pinfo->cinfo, COL_TX_RATE, "20kbps");
+            }
+            else if (packet->channel < 11) {
+                /* 900MHz: NA bands: Channels 1-10 */
+                col_set_str(pinfo->cinfo, COL_TX_RATE, "40kbps");
+            }
+            else {
+                /* 2.4GHz worldwide bands: Channels 11-26 */
+                col_set_str(pinfo->cinfo, COL_TX_RATE, "250kbps");
+            }
+        }
+    }
+
+    /******************************************************
+     * 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");
+            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;
+    /* 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);
+
+        /* Addressing Modes. */
+        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");
+        }
+        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_CAPTURE_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:
+                /* Fall-through. */
+            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);
+
+            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_channel,
+        { "Channel",                    "ieee802.15.4.channel", FT_UINT8, BASE_DEC, NULL, 0x0,
+            "", HFILL }},
+
+        { &hf_ieee802154_lqi,
+        { "Link Quality Indication",    "ieee802.15.4.lqi", FT_UINT8, BASE_DEC, NULL, 0x0,
+            "", HFILL }},
+
+        { &hf_ieee802154_frame_type,
+        { "Frame Type",                 "ieee802.15.4.frame_type", FT_UINT16, BASE_DEC, NULL, IEEE802154_FCF_TYPE_MASK,
+            "", HFILL }},
+
+        { &hf_ieee802154_security_enable,
+        { "Security Enabled",           "ieee802.15.4.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",              "ieee802.15.4.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",        	"ieee802.15.4.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",           			"ieee802.15.4.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",            	"ieee802.15.4.seq_no", FT_UINT8, BASE_DEC, NULL, 0x0,
+            "", HFILL }},
+
+        { &hf_ieee802154_src_addr_mode,
+        { "Source Addressing Mode",     	"ieee802.15.4.src_addr_mode", FT_UINT16, BASE_DEC, NULL, IEEE802154_FCF_SADDR,
+            "", HFILL }},
+
+        { &hf_ieee802154_dst_addr_mode,
+        { "Destination Addressing Mode",    "ieee802.15.4.dst_addr_mode", FT_UINT16, BASE_DEC, NULL, IEEE802154_FCF_DADDR,
+            "", HFILL }},
+
+        { &hf_ieee802154_dst_panID,
+        { "Destination PAN",         		"ieee802.15.4.dst_pan", FT_UINT16, BASE_HEX, NULL, 0x0,
+            "", HFILL }},
+
+        { &hf_ieee802154_dst_addr16,
+        { "Destination",   					"ieee802.15.4.dst_addr16", FT_UINT16, BASE_HEX, NULL, 0x0,
+            "", HFILL }},
+
+        { &hf_ieee802154_dst_addr64,
+        { "Destination",   					"ieee802.15.4.dst_addr64", FT_UINT64, BASE_HEX, NULL, 0x0,
+            "", HFILL }},
+
+        { &hf_ieee802154_src_panID,
+        { "Source PAN",              		"ieee802.15.4.src_pan", FT_UINT16, BASE_HEX, NULL, 0x0,
+            "", HFILL }},
+
+        { &hf_ieee802154_src_addr16,
+        { "Source",    						"ieee802.15.4.src_addr16", FT_UINT16, BASE_HEX, NULL, 0x0,
+            "", HFILL }},
+
+        { &hf_ieee802154_src_addr64,
+        { "Source",    						"ieee802.15.4.src_addr64", FT_UINT64, BASE_HEX, NULL, 0x0,
+            "", HFILL }},
+
+        { &hf_ieee802154_crc,
+        { "CRC",                        	"ieee802.15.4.crc", FT_UINT16, BASE_HEX, NULL, 0x0,
+            "", HFILL }},
+
+        { &hf_ieee802154_rssi,
+        { "RSSI",                       	"ieee802.15.4.rssi", FT_INT8, BASE_DEC, NULL, 0x0,
+            "Received Signal Strength", HFILL }},
+
+        { &hf_ieee802154_crc_ok,
+        { "CRC Valid",                  	"ieee802.15.4.crc_ok", FT_BOOLEAN, 8, NULL, 0x0,
+            "", HFILL }},
+
+        { &hf_ieee802154_correlation,
+        { "LQI Correlation Value",      	"ieee802.15.4.correlation", FT_UINT8, BASE_DEC, NULL, 0x0,
+            "", HFILL }},
+
+            /*  Command Frame Specific Fields */
+            /*--------------------------------*/
+
+        { &hf_ieee802154_cmd_frm_id,
+        { "Command Frame Identifier",   "ieee802.15.4.cmd.frm_id", FT_UINT8, BASE_HEX, NULL, 0x0,
+            "", HFILL }},
+
+        { &hf_ieee802154_cmd_payload,
+        { "Command Payload",            "ieee802.15.4.cmd.payload", FT_NONE, BASE_NONE, NULL, 0x0,
+            "", HFILL }},
+
+            /*  Capability Information Fields */
+        { &hf_ieee802154_cmd_cinfo_alt_pan_coord,
+        { "Alternate PAN Coordinator",  "ieee802.15.4.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",                "ieee802.15.4.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",               "ieee802.15.4.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",       "ieee802.15.4.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",        "ieee802.15.4.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",           "ieee802.15.4.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",              "ieee802.15.4.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",         "ieee802.15.4.cmd.asrsp.assoc_status", FT_UINT8, BASE_HEX, NULL, 0x0,
+            "", HFILL }},
+
+        { &hf_ieee802154_cmd_disas_reason,
+        { "Disassociation Reason",      "ieee802.15.4.cmd.disas.reason", FT_UINT8, BASE_HEX, NULL, 0x0,
+            "", HFILL }},
+
+            /*  Coordinator Realignment fields */
+        { &hf_ieee802154_cmd_coord_panID,
+        { "PAN ID",                     "ieee802.15.4.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",  "ieee802.15.4.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",            "ieee802.15.4.cmd.coord.channel", FT_UINT8, BASE_HEX, NULL, 0x0,
+            "The logical channel the coordinator wishes to use for future communication.", HFILL }},
+
+        { &hf_ieee802154_cmd_coord_addr16,
+        { "Short Address",              "ieee802.15.4.cmd.coord.addr16", FT_UINT16, BASE_HEX, NULL, 0x0,
+            "A short-address that the orphaned device shall assume if applicable.", HFILL }},
+
+        { &hf_ieee802154_cmd_gts_req_len,
+        { "GTS Length",                 "ieee802.15.4.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",              "ieee802.15.4.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",        "ieee802.15.4.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",            "ieee802.15.4.bcn.sfrm.bo", FT_UINT8, BASE_DEC, NULL, 0x0,
+            "Specifies the transmission interval of the beacons.", HFILL }},
+
+        { &hf_ieee802154_bcn_sfrm_sfo,
+        { "Superframe Interval",        "ieee802.15.4.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",             "ieee802.15.4.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",          "ieee802.15.4.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",            "ieee802.15.4.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",         "ieee802.15.4.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",       "ieee802.15.4.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",                 "ieee802.15.4.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",                 "ieee802.15.4.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",                 "ieee802.15.4.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",                 "ieee802.15.4.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",                 "ieee802.15.4.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",                 "ieee802.15.4.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",                 "ieee802.15.4.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",                 "ieee802.15.4.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}
+    };
+
+    static enum_val_t enum_default_fcs[] = {
+        {"none", "None (Default)", IEEE802154_CAPTURE_FCS_NONE},
+        {"crc", "IEEE 802.15.4 CRC", IEEE802154_CAPTURE_FCS_CRC},
+        {"cc2420", "ChipCon CC2420", IEEE802154_CAPTURE_FCS_CHIPCON},
+        {NULL, NULL, -1}
+    };
+
+    /*  Register Protocol name and description. */
+    proto_ieee802154 = proto_register_protocol("IEEE 802.15.4 Protocol", "IEEE 802.15.4", "ieee802.15.4");
+
+    /*  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_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");
+    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,190 @@
+/* packet-ieee802154.h
+ * 2007  Owen Kirby <[email protected]>
+ *
+ * $Id: $
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <[email protected]>
+ * 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 {
+    /* information provided by the pseudo header. */
+    gboolean    have_phdr;
+    guint8      channel;
+    guint8      lqi;
+    guint       fcs_mode;
+
+    gint32      payload_length;
+    gint32      payload_offset;
+
+    /* Frame control field. */
+    guint16     fcf;
+    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_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_CAPTURE_FCS_NONE     0x00
+#define IEEE802154_CAPTURE_FCS_CRC      0x01
+#define IEEE802154_CAPTURE_FCS_CHIPCON  0x02
+
+#endif /* PACKET_IEEE802154_H */
Index: wiretap/libpcap.c
===================================================================
--- wiretap/libpcap.c	(revision 22151)
+++ wiretap/libpcap.c	(working copy)
@@ -99,6 +99,14 @@
 #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_CHANNEL_OFFSET   0   /* Channel Number - 1 byte */
+#define IEEE802154_SLL_LQI_OFFSET       1   /* Link Quality - 1 byte */
+#define IEEE802154_SLL_FCS_TYPE_OFFSET  2   /* Type of FCS mode used. */
+#define IEEE802154_SLL_LEN              4   /* Length of the header - 3 bytes, pad to 4. */
+
 /* See source to the "libpcap" library for information on the "libpcap"
    file format. */
 
@@ -143,6 +151,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 +441,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 +1402,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 +1550,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 +1974,37 @@
 }
 
 static gboolean
+libpcap_get_ieee802154_pseudoheader(const guint8 *ieee802154_phdr,
+    union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info)
+{
+    pseudo_header->ieee802154.channel = ieee802154_phdr[IEEE802154_SLL_CHANNEL_OFFSET];
+    pseudo_header->ieee802154.lqi = ieee802154_phdr[IEEE802154_SLL_LQI_OFFSET];
+    pseudo_header->ieee802154.fcs_mode = ieee802154_phdr[IEEE802154_SLL_FCS_TYPE_OFFSET];
+
+    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 +2233,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 +2370,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 +2395,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 +2608,25 @@
 		}
 		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_CHANNEL_OFFSET] = pseudo_header->ieee802154.channel;
+		ieee802154_hdr[IEEE802154_SLL_LQI_OFFSET] = pseudo_header->ieee802154.lqi;
+		ieee802154_hdr[IEEE802154_SLL_FCS_TYPE_OFFSET] = pseudo_header->ieee802154.fcs_mode;
+		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 22151)
+++ 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 22151)
+++ 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,16 @@
     guint32 data_len;       /* amount of urb data really present in this event*/
 };
 
+/* Packet "pseudo-header" for IEEE 802.15.4. */
+struct ieee802154_phdr {
+	gint8  channel;     /* Logical channel number. Re: IEEE 802.15.4 spec for definition, use -1 if unknown. */
+	guint8  lqi;        /* LQI value. Re: IEEE 802.15.4 spec for definition. */
+	gint8  fcs_mode;    /* Type of FCS present in encapsulated packet. */
+};
+#define IEEE802154_FCS_NONE		0x00    /* FCS field omitted. */
+#define IEEE802154_FCS_CRC		0x01    /* FCS field contains IEEE 802.15.4 compliant CRC value. */
+#define IEEE802154_FCS_CHIPCON		0x02    /* FCS field contains ChipCon/TI formatted information. */
+
 union wtap_pseudo_header {
 	struct eth_phdr		eth;
 	struct x25_phdr		x25;
@@ -622,6 +633,7 @@
 	struct lapd_phdr	lapd;
 	struct catapult_dct2000_phdr dct2000;
 	struct linux_usb_phdr	linux_usb;
+	struct ieee802154_phdr	ieee802154;
 };
 
 struct wtap_nstime {