From Owen Kirby:
authoretxrab <etxrab@f5534014-38df-0310-8fa8-9805f1628bb7>
Sun, 7 Feb 2010 19:39:31 +0000 (19:39 +0000)
committeretxrab <etxrab@f5534014-38df-0310-8fa8-9805f1628bb7>
Sun, 7 Feb 2010 19:39:31 +0000 (19:39 +0000)
Packet decryption for IEEE 802.15.4.
https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=4457

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@31820 f5534014-38df-0310-8fa8-9805f1628bb7

epan/dissectors/packet-ieee802154.c
epan/dissectors/packet-ieee802154.h

index eb306fe1ec08e9fdf80ac987972beb66e995e588..9d2363c20e5ec0c6a70575ce04376e0b959adf6f 100644 (file)
 #include <epan/expert.h>
 #include <epan/addr_resolv.h>
 #include <epan/prefs.h>
+#include <epan/strutil.h>
+
+/* Use libgcrypt for cipher libraries. */
+#ifdef HAVE_LIBGCRYPT
+#include <gcrypt.h>
+#endif /* HAVE_LIBGCRYPT */
 
 #include "packet-ieee802154.h"
 #include "packet-frame.h"   /* For Exception Handling */
@@ -103,6 +109,11 @@ static gboolean ieee802154_cc24xx = FALSE;
 /* boolean value set if the FCS must be oke before data is dissected */
 static gboolean ieee802154_fcs_ok = TRUE;
 
+/* User string with the decryption key. */
+static const gchar *ieee802154_key_str = NULL;
+static gboolean     ieee802154_key_valid;
+static guint8       ieee802154_key[IEEE802154_CIPHER_SIZE];
+
 /*  Function declarations */
 /* Register Functions. Loads the dissector into Wireshark. */
 void proto_reg_handoff_ieee802154   (void);
@@ -115,18 +126,25 @@ static void dissect_ieee802154_nofcs        (tvbuff_t *, packet_info *, proto_tr
 static void dissect_ieee802154_cc24xx       (tvbuff_t *, packet_info *, proto_tree *);
 /*static void dissect_ieee802154_linux        (tvbuff_t *, packet_info *, proto_tree *);  TODO: Implement Me. */
 static void dissect_ieee802154_common       (tvbuff_t *, packet_info *, proto_tree *, guint);
-static void dissect_ieee802154_beacon       (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *);
-static void dissect_ieee802154_cmd          (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *);
+
 /* Sub-dissector helpers. */
 static void dissect_ieee802154_fcf          (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *, guint *);
-static void dissect_ieee802154_cmd_asreq    (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *, guint *);
-static void dissect_ieee802154_cmd_asrsp    (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *, guint *);
-static void dissect_ieee802154_cmd_disas    (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *, guint *);
-static void dissect_ieee802154_cmd_realign  (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *, guint *);
-static void dissect_ieee802154_cmd_gtsrq    (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *, guint *);
+static void dissect_ieee802154_superframe   (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *, guint *);
+static void dissect_ieee802154_gtsinfo      (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *, guint *);
+static void dissect_ieee802154_pendaddr     (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *, guint *);
+static void dissect_ieee802154_assoc_req    (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *);
+static void dissect_ieee802154_assoc_rsp    (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *);
+static void dissect_ieee802154_disassoc     (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *);
+static void dissect_ieee802154_realign      (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *);
+static void dissect_ieee802154_gtsreq       (tvbuff_t *, packet_info *, proto_tree *, ieee802154_packet *);
+
+/* Decryption helpers. */
+static tvbuff_t * dissect_ieee802154_decrypt(tvbuff_t *, guint, packet_info *, ieee802154_packet *);
+static void ccm_init_block                  (gchar * block, gboolean adata, gint M, guint64 addr, guint32 counter, ieee802154_security_level level, gint ctr_val);
+static gboolean ccm_ctr_encrypt             (const gchar *key, const gchar *iv, gchar *mic, gchar *data, gint length);
+static gboolean ccm_cbc_mac                 (const gchar * key, const gchar *iv, const gchar *a, gint a_len, const gchar *m, gint m_len, gchar *mic);
 
 /*  Initialize Protocol and Registered fields */
-
 static int proto_ieee802154_nonask_phy = -1;
 static int hf_ieee802154_nonask_phy_preamble = -1;
 static int hf_ieee802154_nonask_phy_sfd = -1;
@@ -155,36 +173,36 @@ static int hf_ieee802154_correlation;
 
 /*  Registered fields for Command Packets */
 static int hf_ieee802154_cmd_id = -1;
-static int hf_ieee802154_cmd_cinfo_alt_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_addr = -1;
-static int hf_ieee802154_cmd_asrsp_status = -1;
-static int hf_ieee802154_cmd_disas_reason = -1;
-static int hf_ieee802154_cmd_coord_pan = -1;
-static int hf_ieee802154_cmd_coord_caddr = -1;
-static int hf_ieee802154_cmd_coord_channel = -1;
-static int hf_ieee802154_cmd_coord_addr = -1;
-static int hf_ieee802154_cmd_coord_channel_page = -1;
-static int hf_ieee802154_cmd_gts_req_len = -1;
-static int hf_ieee802154_cmd_gts_req_dir = -1;
-static int hf_ieee802154_cmd_gts_req_type = -1;
+static int hf_ieee802154_cinfo_alt_coord = -1;
+static int hf_ieee802154_cinfo_device_type = -1;
+static int hf_ieee802154_cinfo_power_src = -1;
+static int hf_ieee802154_cinfo_idle_rx = -1;
+static int hf_ieee802154_cinfo_sec_capable = -1;
+static int hf_ieee802154_cinfo_alloc_addr = -1;
+static int hf_ieee802154_assoc_addr = -1;
+static int hf_ieee802154_assoc_status = -1;
+static int hf_ieee802154_disassoc_reason = -1;
+static int hf_ieee802154_realign_pan = -1;
+static int hf_ieee802154_realign_caddr = -1;
+static int hf_ieee802154_realign_channel = -1;
+static int hf_ieee802154_realign_addr = -1;
+static int hf_ieee802154_realign_channel_page = -1;
+static int hf_ieee802154_gtsreq_len = -1;
+static int hf_ieee802154_gtsreq_dir = -1;
+static int hf_ieee802154_gtsreq_type = -1;
 
 /*  Registered fields for Beacon Packets */
-static int hf_ieee802154_bcn_beacon_order = -1;
-static int hf_ieee802154_bcn_superframe_order = -1;
-static int hf_ieee802154_bcn_cap = -1;
-static int hf_ieee802154_bcn_battery_ext = -1;
-static int hf_ieee802154_bcn_coord = -1;
-static int hf_ieee802154_bcn_assoc_permit = -1;
-static int hf_ieee802154_bcn_gts_count = -1;
-static int hf_ieee802154_bcn_gts_permit = -1;
-static int hf_ieee802154_bcn_gts_direction = -1;
-static int hf_ieee802154_bcn_pending16 = -1;
-static int hf_ieee802154_bcn_pending64 = -1;
+static int hf_ieee802154_beacon_order = -1;
+static int hf_ieee802154_superframe_order = -1;
+static int hf_ieee802154_cap = -1;
+static int hf_ieee802154_superframe_battery_ext = -1;
+static int hf_ieee802154_superframe_coord = -1;
+static int hf_ieee802154_assoc_permit = -1;
+static int hf_ieee802154_gts_count = -1;
+static int hf_ieee802154_gts_permit = -1;
+static int hf_ieee802154_gts_direction = -1;
+static int hf_ieee802154_pending16 = -1;
+static int hf_ieee802154_pending64 = -1;
 
 /*  Registered fields for Auxiliary Security Header */
 static int hf_ieee802154_security_level = -1;
@@ -204,13 +222,11 @@ static gint ett_ieee802154_aux_sec_control = -1;
 static gint ett_ieee802154_aux_sec_key_id = -1;
 static gint ett_ieee802154_fcs = -1;
 static gint ett_ieee802154_cmd = -1;
-static gint ett_ieee802154_cmd_cinfo = -1;
-static gint ett_ieee802154_bcn = -1;
-static gint ett_ieee802154_bcn_superframe_spec = -1;
-static gint ett_ieee802154_bcn_gts_spec = -1;
-static gint ett_ieee802154_bcn_gts_direction = -1;
-static gint ett_ieee802154_bcn_gts_descriptors = -1;
-static gint ett_ieee802154_bcn_pending = -1;
+static gint ett_ieee802154_superframe = -1;
+static gint ett_ieee802154_gts = -1;
+static gint ett_ieee802154_gts_direction = -1;
+static gint ett_ieee802154_gts_descriptors = -1;
+static gint ett_ieee802154_pendaddr = -1;
 
 /*  Dissector handles */
 static dissector_handle_t       data_handle;
@@ -226,9 +242,9 @@ static const value_string ieee802154_frame_types[] = {
 };
 
 static const value_string ieee802154_addr_modes[] = {
-    { IEEE802154_FCF_ADDR_NONE,     "None" },
-    { IEEE802154_FCF_ADDR_SHORT,    "Short/16-bit" },
-    { IEEE802154_FCF_ADDR_EXT,      "Long/64-bit" },
+    { IEEE802154_FCF_ADDR_NONE, "None" },
+    { IEEE802154_FCF_ADDR_SHORT,"Short/16-bit" },
+    { IEEE802154_FCF_ADDR_EXT,  "Long/64-bit" },
     { 0, NULL }
 };
 
@@ -265,6 +281,14 @@ static const value_string ieee802154_key_id_mode_names[] = {
     { 0, NULL }
 };
 
+static const true_false_string ieee802154_gts_direction_tfs = {
+    "Receive Only",
+    "Transmit Only"
+};
+
+/* Macro to check addressing, and throw a warning flag if incorrect. */
+#define IEEE802154_CMD_ADDR_CHECK(_pinfo_, _item_, _cmdid_, _x_) if (!(_x_)) expert_add_info_format(_pinfo_, _item_, PI_MALFORMED, PI_WARN, "Invalid Addressing for %s", val_to_str(_cmdid_, ieee802154_cmd_names, "Unknown Command"))
+
 /* CRC definitions. IEEE 802.15.4 CRCs vary from CCITT by using an initial value of
  * 0x0000, and no XOR out. IEEE802154_CRC_XOR is defined as 0xFFFF in order to un-XOR
  * the output from the CCITT CRC routines in Wireshark.
@@ -387,25 +411,24 @@ dissect_ieee802154_fcf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee
     /* Add the FCF to the protocol tree. */
     if (tree) {
         /*  Create the FCF subtree. */
-        ti = proto_tree_add_text(tree, tvb, *offset, sizeof(guint16), "Frame Control Field: %s (0x%04x)",
+        ti = proto_tree_add_text(tree, tvb, *offset, 2, "Frame Control Field: %s (0x%04x)",
                 val_to_str(packet->frame_type, ieee802154_frame_types, "Unknown"), fcf);
         field_tree = proto_item_add_subtree(ti, ett_ieee802154_fcf);
 
         /* FCF Fields. */
-        proto_tree_add_uint(field_tree, hf_ieee802154_frame_type, tvb, *offset, sizeof(guint8), fcf & IEEE802154_FCF_TYPE_MASK);
-        proto_tree_add_boolean(field_tree, hf_ieee802154_security, tvb, *offset, sizeof(guint8), fcf & IEEE802154_FCF_SEC_EN);
-        proto_tree_add_boolean(field_tree, hf_ieee802154_pending, tvb, *offset, sizeof(guint8), fcf & IEEE802154_FCF_FRAME_PND);
-        proto_tree_add_boolean(field_tree, hf_ieee802154_ack_request, tvb, *offset, sizeof(guint8), fcf & IEEE802154_FCF_ACK_REQ);
-        proto_tree_add_boolean(field_tree, hf_ieee802154_intra_pan, tvb, *offset, sizeof(guint8), fcf & IEEE802154_FCF_INTRA_PAN);
-        proto_tree_add_uint(field_tree, hf_ieee802154_dst_addr_mode, tvb, (*offset)+sizeof(guint8), sizeof(guint8), fcf & IEEE802154_FCF_DADDR_MASK);
-        proto_tree_add_uint(field_tree, hf_ieee802154_version, tvb, (*offset)+sizeof(guint8), sizeof(guint8), fcf & IEEE802154_FCF_VERSION);
-        proto_tree_add_uint(field_tree, hf_ieee802154_src_addr_mode, tvb, (*offset)+sizeof(guint8), sizeof(guint8), fcf & IEEE802154_FCF_SADDR_MASK);
+        proto_tree_add_uint(field_tree, hf_ieee802154_frame_type, tvb, *offset, 1, fcf & IEEE802154_FCF_TYPE_MASK);
+        proto_tree_add_boolean(field_tree, hf_ieee802154_security, tvb, *offset, 1, fcf & IEEE802154_FCF_SEC_EN);
+        proto_tree_add_boolean(field_tree, hf_ieee802154_pending, tvb, *offset, 1, fcf & IEEE802154_FCF_FRAME_PND);
+        proto_tree_add_boolean(field_tree, hf_ieee802154_ack_request, tvb, *offset, 1, fcf & IEEE802154_FCF_ACK_REQ);
+        proto_tree_add_boolean(field_tree, hf_ieee802154_intra_pan, tvb, *offset, 1, fcf & IEEE802154_FCF_INTRA_PAN);
+        proto_tree_add_uint(field_tree, hf_ieee802154_dst_addr_mode, tvb, (*offset)+1, 1, fcf & IEEE802154_FCF_DADDR_MASK);
+        proto_tree_add_uint(field_tree, hf_ieee802154_version, tvb, (*offset)+1, 1, fcf & IEEE802154_FCF_VERSION);
+        proto_tree_add_uint(field_tree, hf_ieee802154_src_addr_mode, tvb, (*offset)+1, 1, fcf & IEEE802154_FCF_SADDR_MASK);
     }
 
-    *offset += sizeof(guint16);
+    *offset += 2;
 } /* dissect_ieee802154_fcf */
 
-
 /*FUNCTION:------------------------------------------------------
  *  NAME
  *      dissect_ieee802154_nonask_phy
@@ -447,26 +470,26 @@ dissect_ieee802154_nonask_phy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
     }
 
     preamble=tvb_get_letohl(tvb,offset);
-    sfd=tvb_get_guint8(tvb,offset+sizeof(guint32));
-    phr=tvb_get_guint8(tvb,offset+sizeof(guint32)+sizeof(guint8));
+    sfd=tvb_get_guint8(tvb,offset+4);
+    phr=tvb_get_guint8(tvb,offset+4+1);
 
     if(tree) {
         proto_tree *phr_tree;
         proto_item *pi;
         guint loffset=offset;
 
-        proto_tree_add_uint(ieee802154_tree, hf_ieee802154_nonask_phy_preamble, tvb, loffset, sizeof(guint32), preamble);
-        loffset+=sizeof(guint32);
-        proto_tree_add_uint(ieee802154_tree, hf_ieee802154_nonask_phy_sfd, tvb, loffset, sizeof(guint8), sfd);
-        loffset+=sizeof(guint8);
+        proto_tree_add_uint(ieee802154_tree, hf_ieee802154_nonask_phy_preamble, tvb, loffset, 4, preamble);
+        loffset+=4;
+        proto_tree_add_uint(ieee802154_tree, hf_ieee802154_nonask_phy_sfd, tvb, loffset, 1, sfd);
+        loffset+=1;
 
-        pi = proto_tree_add_text(ieee802154_tree, tvb, loffset, sizeof(guint8), "PHR: 0x%02x", phr);
+        pi = proto_tree_add_text(ieee802154_tree, tvb, loffset, 1, "PHR: 0x%02x", phr);
         phr_tree = proto_item_add_subtree(pi, ett_ieee802154_nonask_phy_phr);
 
-        proto_tree_add_uint(phr_tree, hf_ieee802154_nonask_phy_length, tvb, loffset, sizeof(guint8), phr);
+        proto_tree_add_uint(phr_tree, hf_ieee802154_nonask_phy_length, tvb, loffset, 1, phr);
     }
 
-    offset+=sizeof(guint32)+2*sizeof(guint8);
+    offset+=4+2*1;
     mac=tvb_new_subset(tvb,offset,-1, phr & IEEE802154_PHY_LENGTH_MASK);
 
     /* Call the common dissector. */
@@ -624,7 +647,7 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g
             proto_item_append_text(proto_root, ", Sequence Number: %u", packet->seqno);
         }
     }
-    offset += sizeof(guint8);
+    offset += 1;
 
     /*=====================================================
      * ADDRESSING FIELDS
@@ -643,9 +666,9 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g
          (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT) ) {
         packet->dst_pan = tvb_get_letohs(tvb, offset);
         if (tree) {
-            proto_tree_add_uint(ieee802154_tree, hf_ieee802154_dst_pan, tvb, offset, sizeof(guint16), packet->dst_pan);
+            proto_tree_add_uint(ieee802154_tree, hf_ieee802154_dst_pan, tvb, offset, 2, packet->dst_pan);
         }
-        offset += sizeof(guint16);
+        offset += 2;
     }
 
     /* Get destination address. */
@@ -662,17 +685,17 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g
         SET_ADDRESS(&pinfo->dl_dst, AT_STRINGZ, (int)strlen(dst_addr)+1, dst_addr);
         SET_ADDRESS(&pinfo->dst, AT_STRINGZ, (int)strlen(dst_addr)+1, dst_addr);
         if (tree) {
-            proto_tree_add_uint(ieee802154_tree, hf_ieee802154_dst_addr16, tvb, offset, sizeof(guint16), packet->dst.addr16);
+            proto_tree_add_uint(ieee802154_tree, hf_ieee802154_dst_addr16, tvb, offset, 2, packet->dst.addr16);
             proto_item_append_text(proto_root, ", Dst: %s", dst_addr);
         }
         if (check_col(pinfo->cinfo, COL_INFO)) {
             col_append_fstr(pinfo->cinfo, COL_INFO, ", Dst: %s", dst_addr);
         }
-        offset += sizeof(guint16);
+        offset += 2;
     }
     else if (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT) {
         /* Dynamic (not stack) memory required for address column. */
-        gchar    *addr = ep_alloc(sizeof(guint64));
+        gchar    *addr = ep_alloc(8);
         gchar    *dst, *dst_oui;
 
         /* Get the address */
@@ -690,16 +713,16 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g
          *          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);
+        SET_ADDRESS(&pinfo->dl_dst, AT_EUI64, 8, addr);
+        SET_ADDRESS(&pinfo->dst, AT_EUI64, 8, addr);
         if (tree) {
-            proto_tree_add_uint64_format_value(ieee802154_tree, hf_ieee802154_dst_addr64, tvb, offset, sizeof(guint64), packet->dst.addr64, "%s (%s)", dst_oui, dst);
+            proto_tree_add_uint64_format_value(ieee802154_tree, hf_ieee802154_dst_addr64, tvb, offset, 8, packet->dst.addr64, "%s (%s)", dst_oui, dst);
             proto_item_append_text(proto_root, ", Dst: %s", dst_oui);
         }
         if (check_col(pinfo->cinfo, COL_INFO)) {
             col_append_fstr(pinfo->cinfo, COL_INFO, ", Dst: %s", dst_oui);
         }
-        offset += sizeof(guint64);
+        offset += 8;
     }
     else if (packet->dst_addr_mode != IEEE802154_FCF_ADDR_NONE) {
         /* Invalid Destination Address Mode. Abort Dissection. */
@@ -717,9 +740,9 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g
         /* Source PAN is present, extract it and add it to the tree. */
         packet->src_pan = tvb_get_letohs(tvb, offset);
         if (tree) {
-            proto_tree_add_uint(ieee802154_tree, hf_ieee802154_src_panID, tvb, offset, sizeof(guint16), packet->src_pan);
+            proto_tree_add_uint(ieee802154_tree, hf_ieee802154_src_panID, tvb, offset, 2, packet->src_pan);
         }
-        offset += sizeof(guint16);
+        offset += 2;
     }
     else {
         /* Set the panID field in case the intra-pan condition was met. */
@@ -742,17 +765,17 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g
 
         /* Add the addressing info to the tree. */
         if (tree) {
-            proto_tree_add_uint(ieee802154_tree, hf_ieee802154_src_addr16, tvb, offset, sizeof(guint16), packet->src.addr16);
+            proto_tree_add_uint(ieee802154_tree, hf_ieee802154_src_addr16, tvb, offset, 2, packet->src.addr16);
             proto_item_append_text(proto_root, ", Src: %s", src_addr);
         }
         if (check_col(pinfo->cinfo, COL_INFO)) {
             col_append_fstr(pinfo->cinfo, COL_INFO, ", Src: %s", src_addr);
         }
-        offset += sizeof(guint16);
+        offset += 2;
     }
     else if (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) {
         /* Dynamic (not stack) memory required for address column. */
-        gchar   *addr = ep_alloc(sizeof(guint64));
+        gchar   *addr = ep_alloc(8);
         gchar   *src, *src_oui;
 
         /* Get the address. */
@@ -770,16 +793,16 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g
          *          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);
+        SET_ADDRESS(&pinfo->dl_src, AT_EUI64, 8, addr);
+        SET_ADDRESS(&pinfo->src, AT_EUI64, 8, addr);
         if (tree) {
-            proto_tree_add_uint64_format_value(ieee802154_tree, hf_ieee802154_src_addr64, tvb, offset, sizeof(guint64), packet->src.addr64, "%s (%s)", src_oui, src);
+            proto_tree_add_uint64_format_value(ieee802154_tree, hf_ieee802154_src_addr64, tvb, offset, 8, packet->src.addr64, "%s (%s)", src_oui, src);
             proto_item_append_text(proto_root, ", Src: %s", src_oui);
         }
         if (check_col(pinfo->cinfo, COL_INFO)) {
             col_append_fstr(pinfo->cinfo, COL_INFO, ", Src: %s", src_oui);
         }
-        offset += sizeof(guint64);
+        offset += 8;
     }
     else if (packet->src_addr_mode != IEEE802154_FCF_ADDR_NONE) {
         /* Invalid Destination Address Mode. Abort Dissection. */
@@ -789,7 +812,7 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g
     }
 
     /*=====================================================
-     * FRAME CHECK SEQUENCE VERIFICATION
+     * VERIFY FRAME CHECK SEQUENCE
      *=====================================================
      */
     /* Check, but don't display the FCS yet, otherwise the payload dissection
@@ -815,101 +838,111 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g
      */
     /* The Auxiliary Security Header only exists in IEEE 802.15.4-2006 */
     if (packet->security_enable && (packet->version == 1)) {
-      proto_item *tii;
       proto_tree *header_tree, *field_tree;
-
-      guint                     key_length = 0;
       guint8                    security_control;
-      ieee802154_security_level sec_level;
-      ieee802154_key_id_mode    key_id_mode;
-      guint32                   frame_counter;
-
-      guint64 key_source = 0;
-      guint8  key_index;
+      guint                     aux_length = 5; /* Minimum length of the auxilliary header. */
 
+      /* Parse the security control field. */
       security_control = tvb_get_guint8(tvb, offset);
+      packet->security_level = (security_control & IEEE802154_AUX_SEC_LEVEL_MASK);
+      packet->key_id_mode = (security_control & IEEE802154_AUX_KEY_ID_MODE_MASK) >> IEEE802154_AUX_KEY_ID_MODE_SHIFT;
 
-      sec_level = (security_control & IEEE802154_AUX_SEC_LEVEL_MASK);
-      key_id_mode = (security_control & IEEE802154_AUX_KEY_ID_MODE_MASK);
-      switch ((key_id_mode >> 3)) {
-      case KEY_ID_MODE_IMPLICIT:
-        break;
-      case KEY_ID_MODE_KEY_INDEX:
-        key_length++;
-        break;
-      case KEY_ID_MODE_KEY_EXPLICIT_4:
-        key_length += 5;
-        break;
-      case KEY_ID_MODE_KEY_EXPLICIT_8:
-        key_length += 9;
-        break;
-      }
-
-      tii = proto_tree_add_text(ieee802154_tree, tvb, offset, 5 + key_length, "Auxiliary Security Header");
-      header_tree = proto_item_add_subtree(tii, ett_ieee802154_auxiliary_security);
+      /* Compute the length of the auxilliar header and create a subtree.  */
+      if (packet->key_id_mode != KEY_ID_MODE_IMPLICIT) aux_length++;
+      if (packet->key_id_mode == KEY_ID_MODE_KEY_EXPLICIT_4) aux_length += 4;
+      if (packet->key_id_mode == KEY_ID_MODE_KEY_EXPLICIT_8) aux_length += 8;
+      ti = proto_tree_add_text(ieee802154_tree, tvb, offset, aux_length, "Auxiliary Security Header");
+      header_tree = proto_item_add_subtree(ti, ett_ieee802154_auxiliary_security);
 
       /* Security Control Field */
-      tii = proto_tree_add_text(header_tree, tvb, offset, sizeof (guint8), "Security Control Field (0x%02x)", security_control);
-      field_tree = proto_item_add_subtree(tii, ett_ieee802154_aux_sec_control);
-
-      proto_tree_add_uint(field_tree, hf_ieee802154_security_level, tvb, offset, sizeof(guint8), sec_level);
-      proto_tree_add_uint(field_tree, hf_ieee802154_key_id_mode, tvb, offset, sizeof(guint8), key_id_mode);
-      proto_tree_add_uint(field_tree, hf_ieee802154_aux_sec_reserved, tvb, offset, sizeof(guint8), 0);
-
+      ti = proto_tree_add_text(header_tree, tvb, offset, 1, "Security Control Field (0x%02x)", security_control);
+      field_tree = proto_item_add_subtree(ti, ett_ieee802154_aux_sec_control);
+      proto_tree_add_uint(field_tree, hf_ieee802154_security_level, tvb, offset, 1, security_control & IEEE802154_AUX_SEC_LEVEL_MASK);
+      proto_tree_add_uint(field_tree, hf_ieee802154_key_id_mode, tvb, offset, 1, security_control & IEEE802154_AUX_KEY_ID_MODE_MASK);
+      proto_tree_add_uint(field_tree, hf_ieee802154_aux_sec_reserved, tvb, offset, 1, security_control & IEEE802154_AUX_KEY_RESERVED_MASK);
       offset++;
 
       /* Frame Counter Field */
-      frame_counter = tvb_get_letohl (tvb, offset);
-
-      proto_tree_add_uint(header_tree, hf_ieee802154_aux_sec_frame_counter, tvb, offset, sizeof(guint32), frame_counter);
-
-      offset += sizeof (guint32);
-
-      /* Key Identifier Fields */
-      switch ((key_id_mode >> 3)) {
-      case KEY_ID_MODE_IMPLICIT:
-      case KEY_ID_MODE_KEY_INDEX:
-        break;
-      case KEY_ID_MODE_KEY_EXPLICIT_4:
-        key_source = (guint64) tvb_get_ntohl(tvb, offset);
-        break;
-      case KEY_ID_MODE_KEY_EXPLICIT_8:
-        key_source = tvb_get_ntoh64(tvb, offset);
-        break;
+      packet->frame_counter = tvb_get_letohl (tvb, offset);
+      proto_tree_add_uint(header_tree, hf_ieee802154_aux_sec_frame_counter, tvb, offset,4, packet->frame_counter);
+      offset +=4;
+
+      /* Key identifier field(s). */
+      if (packet->key_id_mode != KEY_ID_MODE_IMPLICIT) {
+        /* Create a subtree. */
+        ti = proto_tree_add_text(header_tree, tvb, offset, 1, "Key Identifier Field"); /* Will fix length later. */
+        field_tree = proto_item_add_subtree(ti, ett_ieee802154_aux_sec_key_id);
+        /* Add key source, if it exists. */
+        if (packet->key_id_mode == KEY_ID_MODE_KEY_EXPLICIT_4) {
+          packet->key_source.addr32 = (guint64) tvb_get_ntohl(tvb, offset);
+          proto_tree_add_uint64(field_tree, hf_ieee802154_aux_sec_key_source, tvb, offset, 4, packet->key_source.addr32);
+          proto_item_set_len(ti, 1 + 4);
+          offset += sizeof (guint32);
+        }
+        if (packet->key_id_mode == KEY_ID_MODE_KEY_EXPLICIT_8) {
+          packet->key_source.addr64 = tvb_get_ntoh64(tvb, offset);
+          proto_tree_add_uint64(field_tree, hf_ieee802154_aux_sec_key_source, tvb, offset, 8, packet->key_source.addr64);
+          proto_item_set_len(ti,1 + 8);
+          offset += 4;
+        }
+        /* Add key identifier. */
+        packet->key_index = tvb_get_guint8(tvb, offset);
+        proto_tree_add_uint(field_tree, hf_ieee802154_aux_sec_key_index, tvb, offset,1, packet->key_index);
+        offset++;
       }
+    }
 
-      tii = proto_tree_add_text(header_tree, tvb, offset, key_length, "Key Identifier Field");
-      field_tree = proto_item_add_subtree(tii, ett_ieee802154_aux_sec_key_id);
-
-      /* Key Source Field */
-      if ((key_id_mode >> 3) > KEY_ID_MODE_KEY_INDEX) {
-        proto_tree_add_uint64(field_tree, hf_ieee802154_aux_sec_key_source, tvb, offset, sizeof (guint64), key_source);
-        offset += key_length - 1;
-      }
+    /*=====================================================
+     * NONPAYLOAD FIELDS
+     *=====================================================
+     */
+    /* All of the beacon fields, except the beacon payload are considered nonpayload. */
+    if (packet->frame_type == IEEE802154_FCF_BEACON) {
+        /* Parse the superframe spec. */
+        dissect_ieee802154_superframe(tvb, pinfo, ieee802154_tree, packet, &offset);
+        /* Parse the GTS information fields. */
+        dissect_ieee802154_gtsinfo(tvb, pinfo, ieee802154_tree, packet, &offset);
+        /* Parse the Pending address list. */
+        dissect_ieee802154_pendaddr(tvb, pinfo, ieee802154_tree, packet, &offset);
+    }
+    /* Only the Command ID is considered nonpayload. */
+    if (packet->frame_type == IEEE802154_FCF_CMD) {
+        packet->command_id = tvb_get_guint8(tvb, offset);
+        if (tree) {
+            proto_tree_add_uint(ieee802154_tree, hf_ieee802154_cmd_id, tvb, offset, 1, packet->command_id);
+        }
+        offset++;
 
-      /* Key Index Field */
-      key_index = tvb_get_guint8(tvb, offset);
-      proto_tree_add_uint(field_tree, hf_ieee802154_aux_sec_key_index, tvb, offset, sizeof (guint8), key_index);
-      offset++;
+        /* Display the command identifier in the info column. */
+        if(check_col(pinfo->cinfo, COL_INFO)) {
+            col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(packet->command_id, ieee802154_cmd_names, "Unknown Command"));
+        }
     }
+    /* No other frame types have nonpayload fields. */
 
     /*=====================================================
      * PAYLOAD DISSECTION
      *=====================================================
      */
-    /* Create the payload buffer. */
-    payload_tvb = tvb_new_subset(tvb, offset, -1, tvb_reported_length(tvb)-offset-IEEE802154_FCS_LEN);
-    /* Just being safe to ensure that real_length <= reported_length. The tvbuff
-     * code should ensure this condition when creating the subset, but I don't
-     * think it does. */
-    tvb_set_reported_length(payload_tvb, tvb_reported_length(tvb)-offset-IEEE802154_FCS_LEN);
-    /* We can't handle encryption, so if the packet is encrypted, give up. */
+    /* Encrypted Payload. */
     if (packet->security_enable) {
-        /* Payload is encrypted. We can't handle this. Maybe a future feature? */
-        expert_add_info_format(pinfo, proto_root, PI_UNDECODED, PI_WARN, "Encrypted Payload");
-        call_dissector(data_handle, payload_tvb, pinfo, tree);
-        goto dissect_ieee802154_fcs;
+        payload_tvb = dissect_ieee802154_decrypt(tvb, offset, pinfo, packet);
+        if (!payload_tvb) {
+            /* Set expert info. */
+            expert_add_info_format(pinfo, proto_root, PI_UNDECODED, PI_WARN, "Encrypted Payload");
+            /* Display the remaining payload using the data dissector. */
+            payload_tvb = tvb_new_subset(tvb, offset, -1, tvb_reported_length(tvb)-offset-IEEE802154_FCS_LEN);
+            tvb_set_reported_length(payload_tvb, tvb_reported_length(tvb)-offset-IEEE802154_FCS_LEN);
+            call_dissector(data_handle, payload_tvb, pinfo, tree);
+            goto dissect_ieee802154_fcs;
+        }
+    }
+    /* Plaintext Payload. */
+    else {
+        payload_tvb = tvb_new_subset(tvb, offset, -1, tvb_reported_length(tvb)-offset-IEEE802154_FCS_LEN);
+        tvb_set_reported_length(payload_tvb, tvb_reported_length(tvb)-offset-IEEE802154_FCS_LEN);
     }
+
     /*
      * Wrap the sub-dissection in a try/catch block in case the payload is
      * broken. First we store the current protocol so we can fix it if an
@@ -918,36 +951,105 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g
     saved_proto = pinfo->current_proto;
     /* Try to dissect the payload. */
     TRY {
-        switch (packet->frame_type) {
-            case IEEE802154_FCF_BEACON:
-                dissect_ieee802154_beacon(payload_tvb, pinfo, ieee802154_tree, packet);
-                break;
-            case IEEE802154_FCF_CMD:
-                dissect_ieee802154_cmd(payload_tvb, pinfo, ieee802154_tree, packet);
-                break;
-            case IEEE802154_FCF_DATA:
-                if ((fcs_ok || !ieee802154_fcs_ok) && (tvb_reported_length(payload_tvb)>0)) {
-                    /* Attempt heuristic subdissection. */
-                    if (dissector_try_heuristic(ieee802154_heur_subdissector_list, payload_tvb, pinfo, tree)) {
-                        /* found a sub-dissector! */
-                        break;
-                    }
+        if ((packet->frame_type == IEEE802154_FCF_BEACON) ||
+            (packet->frame_type == IEEE802154_FCF_DATA)) {
+            /* Beacon and Data packets contain a payload. */
+            if ((fcs_ok || !ieee802154_fcs_ok) && (tvb_reported_length(payload_tvb)>0)) {
+                /* Attempt heuristic subdissection. */
+                if (!dissector_try_heuristic(ieee802154_heur_subdissector_list, payload_tvb, pinfo, tree)) {
+                    /* Could not subdissect, call the data dissector instead. */
+                    call_dissector(data_handle, payload_tvb, pinfo, tree);
                 }
+            }
+            else {
                 /* If no sub-dissector was called, call the data dissector. */
                 call_dissector(data_handle, payload_tvb, pinfo, tree);
+            }
+        }
+        /* If the packet is a command, try to dissect the payload. */
+        else if (packet->frame_type == IEEE802154_FCF_CMD) {
+            switch (packet->command_id) {
+              case IEEE802154_CMD_ASRQ:
+                IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id,
+                    (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) &&
+                    (packet->dst_addr_mode != IEEE802154_FCF_ADDR_NONE));
+                dissect_ieee802154_assoc_req(payload_tvb, pinfo, ieee802154_tree, packet);
+                break;
+
+              case IEEE802154_CMD_ASRSP:
+                IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id,
+                    (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) &&
+                    (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT));
+                dissect_ieee802154_assoc_rsp(payload_tvb, pinfo, ieee802154_tree, packet);
                 break;
-            case IEEE802154_FCF_ACK:
-                /* Ack should not contain a payload. */
-                if (tvb_reported_length(payload_tvb) > 0) {
-                    expert_add_info_format(pinfo, proto_root, PI_MALFORMED, PI_WARN, "Unexpected Payload in Acknowledgement");
+
+              case IEEE802154_CMD_DISAS:
+                IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id,
+                    (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) &&
+                    (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT));
+                dissect_ieee802154_disassoc(payload_tvb, pinfo, ieee802154_tree, packet);
+                break;
+
+              case IEEE802154_CMD_DATA_RQ:
+                IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id, packet->src_addr_mode != IEEE802154_FCF_ADDR_NONE);
+                break;
+
+              case IEEE802154_CMD_PANID_ERR:
+                IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id,
+                    (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) &&
+                    (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT));
+                break;
+
+              case IEEE802154_CMD_ORPH_NOTIF:
+                IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id,
+                    (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) &&
+                    (packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) &&
+                    (packet->dst.addr16 == IEEE802154_BCAST_ADDR) &&
+                    (packet->src_pan == IEEE802154_BCAST_PAN) &&
+                    (packet->dst_pan == IEEE802154_BCAST_PAN));
+                break;
+
+              case IEEE802154_CMD_BCN_RQ:
+                IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id,
+                    (packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) &&
+                    (packet->src_addr_mode == IEEE802154_FCF_ADDR_NONE) &&
+                    (packet->dst.addr16 == IEEE802154_BCAST_ADDR) &&
+                    (packet->dst_pan == IEEE802154_BCAST_PAN));
+                break;
+
+              case IEEE802154_CMD_COORD_REAL:
+                IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id,
+                    (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) &&
+                    (packet->dst_pan == IEEE802154_BCAST_PAN) &&
+                    (packet->dst_addr_mode != IEEE802154_FCF_ADDR_NONE));
+                if (packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) {
+                    /* If directed to a 16-bit address, check that it is being broadcast. */
+                    IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id, packet->dst.addr16 == IEEE802154_BCAST_ADDR);
                 }
-                call_dissector(data_handle, payload_tvb, pinfo, tree);
+                dissect_ieee802154_realign(payload_tvb, pinfo, ieee802154_tree, packet);
                 break;
-            default:
-                /* Unknown frame type! */
-                call_dissector(data_handle, payload_tvb, pinfo, tree);
+
+              case IEEE802154_CMD_GTS_REQ:
+                /* Check that the addressing is correct for this command type. */
+                IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id,
+                    (packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT) &&
+                    (packet->dst_addr_mode == IEEE802154_FCF_ADDR_NONE) &&
+                    (packet->src.addr16 != IEEE802154_BCAST_ADDR) &&
+                    (packet->src.addr16 != IEEE802154_NO_ADDR16));
+                dissect_ieee802154_gtsreq(payload_tvb, pinfo, ieee802154_tree, packet);
                 break;
-        } /* switch */
+
+              default:
+                /* Unknown Command */
+                call_dissector(data_handle, payload_tvb, pinfo, ieee802154_tree);
+                break;
+            } /* switch */
+
+        }
+        /* Otherwise, dump whatever is left over to the data dissector. */
+        else {
+            call_dissector(data_handle, payload_tvb, pinfo, tree);
+        }
     }
     CATCH_ALL {
         /*
@@ -981,16 +1083,16 @@ dissect_ieee802154_fcs:
         /* Display the FCS depending on expected FCS format */
         if ((options & DISSECT_IEEE802154_OPTION_CC24xx)) {
             /* Create a subtree for the FCS. */
-            ti = proto_tree_add_text(ieee802154_tree, tvb, offset, sizeof(guint16), "Frame Check Sequence (TI CC24xx format): FCS %s", (fcs_ok) ? "OK" : "Bad");
+            ti = proto_tree_add_text(ieee802154_tree, tvb, offset, 2, "Frame Check Sequence (TI CC24xx format): FCS %s", (fcs_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, offset++, sizeof(gint8), (gint8) (fcs & IEEE802154_CC24xx_RSSI));
+            ti = proto_tree_add_int(field_tree, hf_ieee802154_rssi, tvb, offset++, 1, (gint8) (fcs & IEEE802154_CC24xx_RSSI));
             proto_item_append_text(ti, " dBm"); /*  Displaying Units */
-            proto_tree_add_boolean(field_tree, hf_ieee802154_fcs_ok, tvb, offset, sizeof(gint8), (gboolean) (fcs & IEEE802154_CC24xx_CRC_OK));
-            proto_tree_add_uint(field_tree, hf_ieee802154_correlation, tvb, offset, sizeof(gint8), (guint8) ((fcs & IEEE802154_CC24xx_CORRELATION) >> 8));
+            proto_tree_add_boolean(field_tree, hf_ieee802154_fcs_ok, tvb, offset, 1, (gboolean) (fcs & IEEE802154_CC24xx_CRC_OK));
+            proto_tree_add_uint(field_tree, hf_ieee802154_correlation, tvb, offset, 1, (guint8) ((fcs & IEEE802154_CC24xx_CORRELATION) >> 8));
         }
         else {
-            ti = proto_tree_add_uint(ieee802154_tree, hf_ieee802154_fcs, tvb, offset, sizeof(guint16), fcs);
+            ti = proto_tree_add_uint(ieee802154_tree, hf_ieee802154_fcs, tvb, offset, 2, fcs);
             if (fcs_ok) {
                 proto_item_append_text(ti, " (Correct)");
             }
@@ -998,7 +1100,7 @@ dissect_ieee802154_fcs:
                 proto_item_append_text(ti, " (Incorrect, expected FCS=0x%04x", ieee802154_crc_tvb(tvb, offset));
             }
             /* To Help with filtering, add the fcs_ok field to the tree.  */
-            ti = proto_tree_add_boolean(ieee802154_tree, hf_ieee802154_fcs_ok, tvb, offset, sizeof(guint16), fcs_ok);
+            ti = proto_tree_add_boolean(ieee802154_tree, hf_ieee802154_fcs_ok, tvb, offset, 2, fcs_ok);
             PROTO_ITEM_SET_HIDDEN(ti);
         }
     }
@@ -1006,7 +1108,7 @@ dissect_ieee802154_fcs:
         /* Even if the FCS isn't present, add the fcs_ok field to the tree to
          * help with filter. Be sure not to make it visible though.
          */
-        ti = proto_tree_add_boolean(ieee802154_tree, hf_ieee802154_fcs_ok, tvb, offset, sizeof(guint16), fcs_ok);
+        ti = proto_tree_add_boolean(ieee802154_tree, hf_ieee802154_fcs_ok, tvb, offset, 2, fcs_ok);
         PROTO_ITEM_SET_HIDDEN(ti);
     }
 
@@ -1023,415 +1125,281 @@ dissect_ieee802154_fcs:
 
 /*FUNCTION:------------------------------------------------------
  *  NAME
- *      dissect_ieee802154_beacon
+ *      dissect_ieee802154_superframe
  *  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
+ *      Subdissector command for the Superframe specification
+ *      sub-field within the beacon frame.
  *  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 wireshark uses to display packet.
- *      ieee802154_packet *packet   - IEEE 802.15.4 packet information.
+ *      tvbuff_t    *tvb            - pointer to buffer containing raw packet.
+ *      packet_info *pinfo          - pointer to packet information fields (unused).
+ *      proto_tree  *tree           - pointer to command subtree.
+ *      ieee802154_packet *packet   - IEEE 802.15.4 packet information (unused).
+ *      guint       *offset         - offset into the tvbuff to begin dissection.
  *  RETURNS
  *      void
  *---------------------------------------------------------------
  */
 static void
-dissect_ieee802154_beacon(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet)
+dissect_ieee802154_superframe(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet, guint *offset)
 {
-    proto_tree          *field_tree = NULL;
-    proto_tree          *bcn_tree = NULL;
-    proto_item          *ti;
-
-    guint8      superframe_spec_hi;
-    guint8      superframe_spec_lo;
-    guint8      gts_spec;
-    guint8      gts_desc_count;
-    guint8      paddr_spec;
-    guint8      paddr_num16;
-    guint8      paddr_num64;
-    guint8      bcn_payload_len;
-
-    gint        i;
-    gint        offset = 0;
+    proto_tree  *field_tree = NULL;
+    proto_item  *ti;
+    guint16     superframe;
 
     /* 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_FCF_ADDR_NONE) {
-            expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_WARN, "Missing Source Address in Beacon" );
-        }
-
+    superframe = tvb_get_letohs(tvb, *offset);
+    if (tree) {
         /*  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_superframe_spec);
+        ti = proto_tree_add_text(tree, tvb, *offset, 2, "Superframe Specification");
+        field_tree = proto_item_add_subtree(ti, ett_ieee802154_superframe);
 
         /*  Add Beacon Order to the superframe spec. */
-        ti = proto_tree_add_uint_format(field_tree, hf_ieee802154_bcn_beacon_order, 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_superframe_order, 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_cap, tvb, offset+1, 1, superframe_spec_lo & IEEE802154_BCN_CAP_MASK);
-        proto_tree_add_boolean(field_tree, hf_ieee802154_bcn_battery_ext, tvb, offset+1, 1, superframe_spec_lo & IEEE802154_BCN_BATT_EXTN_MASK);
-        proto_tree_add_boolean(field_tree, hf_ieee802154_bcn_coord, tvb, offset+1, 1, superframe_spec_lo & IEEE802154_BCN_COORD_MASK);
-        proto_tree_add_boolean(field_tree, hf_ieee802154_bcn_assoc_permit, tvb, offset+1, 1, superframe_spec_lo & IEEE802154_BCN_ASSOC_PERM_MASK);
+        proto_tree_add_uint(field_tree, hf_ieee802154_beacon_order, tvb, *offset, 2, superframe & IEEE802154_BEACON_ORDER_MASK);
+        proto_tree_add_uint(field_tree, hf_ieee802154_superframe_order, tvb, *offset, 2, superframe & IEEE802154_SUPERFRAME_ORDER_MASK);
+        proto_tree_add_uint(field_tree, hf_ieee802154_cap, tvb, *offset, 2, (superframe & IEEE802154_SUPERFRAME_CAP_MASK) >> IEEE802154_SUPERFRAME_CAP_SHIFT);
+        proto_tree_add_boolean(field_tree, hf_ieee802154_superframe_battery_ext, tvb, *offset, 2, superframe & IEEE802154_BATT_EXTENSION_MASK);
+        proto_tree_add_boolean(field_tree, hf_ieee802154_superframe_coord, tvb, *offset, 2, superframe & IEEE802154_SUPERFRAME_COORD_MASK);
+        proto_tree_add_boolean(field_tree, hf_ieee802154_assoc_permit, tvb, *offset, 2, superframe & IEEE802154_ASSOC_PERMIT_MASK);
     }
-    offset += sizeof(guint16);
+    (*offset) += 2;
+} /* dissect_ieee802154_superframe */
+
+/*FUNCTION:------------------------------------------------------
+ *  NAME
+ *      dissect_ieee802154_gtsinfo
+ *  DESCRIPTION
+ *      Subdissector command for the GTS information fields within
+ *      the beacon frame.
+ *  PARAMETERS
+ *      tvbuff_t    *tvb            - pointer to buffer containing raw packet.
+ *      packet_info *pinfo          - pointer to packet information fields (unused).
+ *      proto_tree  *tree           - pointer to command subtree.
+ *      ieee802154_packet *packet   - IEEE 802.15.4 packet information (unused).
+ *      guint       *offset         - offset into the tvbuff to begin dissection.
+ *  RETURNS
+ *      void
+ *---------------------------------------------------------------
+ */
+static void
+dissect_ieee802154_gtsinfo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet, guint *offset)
+{
+    proto_tree  *field_tree = NULL;
+    proto_tree  *subtree = NULL;
+    proto_item  *ti;
+    guint8      gts_spec;
+    guint8      gts_count;
 
     /*  Get and display the GTS specification field */
-    gts_spec = tvb_get_guint8(tvb, offset);
-    gts_desc_count = gts_spec & IEEE802154_BCN_GTS_COUNT_MASK;
-    if(tree){
-        proto_tree_add_uint(bcn_tree, hf_ieee802154_bcn_gts_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);
+    gts_spec = tvb_get_guint8(tvb, *offset);
+    gts_count = gts_spec & IEEE802154_GTS_COUNT_MASK;
+    if (tree) {
+        /*  Add Subtree for GTS information. */
+        if (gts_count) {
+            ti = proto_tree_add_text(tree, tvb, *offset, 2 + (gts_count * 3), "GTS");
+        }
+        else {
+            ti = proto_tree_add_text(tree, tvb, *offset, 1, "GTS");
+        }
+        field_tree = proto_item_add_subtree(ti, ett_ieee802154_gts);
+
+        proto_tree_add_uint(field_tree, hf_ieee802154_gts_count, tvb, *offset, 1, gts_count);
+        proto_tree_add_boolean(field_tree, hf_ieee802154_gts_permit, tvb, *offset, 1, gts_spec & IEEE802154_GTS_PERMIT_MASK);
     }
-    offset += sizeof(guint8);
+    (*offset) += 1;
 
     /* If the GTS descriptor count is nonzero, then the GTS directions mask and descriptor list are present. */
-    if(gts_desc_count){
-        guint8  gts_directions = tvb_get_guint8(tvb, offset + 1);
-        guint   gts_numRx = 0;
+    if (gts_count) {
+        guint8  gts_directions = tvb_get_guint8(tvb, *offset);
+        guint   gts_rx = 0;
+        int     i;
 
         /* Display the directions mask. */
         if (tree) {
+            proto_tree  *dir_tree = NULL;
+
             /* Create a subtree. */
-            ti = proto_tree_add_text(bcn_tree, tvb, offset, sizeof(guint8), "GTS Directions");
-            field_tree = proto_item_add_subtree(ti, ett_ieee802154_bcn_gts_direction);
+            ti = proto_tree_add_text(field_tree, tvb, *offset, 1, "GTS Directions");
+            dir_tree = proto_item_add_subtree(ti, ett_ieee802154_gts_direction);
 
             /* Add the directions to the subtree. */
-            for (i=0; i<gts_desc_count; i++) {
-                gboolean    dir = gts_directions & IEEE802154_BCN_GTS_DIRECTION_SLOT(i);
-
-                proto_tree_add_boolean_format(field_tree, hf_ieee802154_bcn_gts_direction, tvb, offset, sizeof(guint8), dir, "GTS Slot %i: %s", i+1, dir?"Receive Only":"Transmit Only");
-                if (dir) gts_numRx++;
+            for (i=0; i<gts_count; i++) {
+                gboolean    dir = gts_directions & IEEE802154_GTS_DIRECTION_SLOT(i);
+                proto_tree_add_boolean_format(dir_tree, hf_ieee802154_gts_direction, tvb, *offset, 1, dir, "GTS Slot %i: %s", i+1, dir?"Receive Only":"Transmit Only");
+                if (dir) gts_rx++;
             } /* for */
-            proto_item_append_text(ti, ": %i Receive & %i Transmit", gts_numRx, gts_desc_count-gts_numRx);
+            proto_item_append_text(ti, ": %i Receive & %i Transmit", gts_rx, gts_count - gts_rx);
         }
-        offset += sizeof(guint8);
+        (*offset) += 1;
 
         /* Create a subtree for the GTS descriptors. */
         if (tree) {
-            ti = proto_tree_add_text(bcn_tree, tvb, offset, (sizeof(guint16)+sizeof(guint8))*gts_desc_count, "GTS Descriptors");
-            field_tree = proto_item_add_subtree(ti, ett_ieee802154_bcn_gts_descriptors);
+            ti = proto_tree_add_text(field_tree, tvb, *offset, gts_count * 3, "GTS Descriptors");
+            subtree = proto_item_add_subtree(ti, ett_ieee802154_gts_descriptors);
         }
 
         /* 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;
+        for (i=0; i<gts_count; i++) {
+            guint16 gts_addr        = tvb_get_letohs(tvb, (*offset));
+            guint8  gts_slot        = tvb_get_guint8(tvb, (*offset)+2);
+            guint8  gts_length      = (gts_slot & IEEE802154_GTS_LENGTH_MASK) >> IEEE802154_GTS_LENGTH_SHIFT;
 
             if (tree) {
                 /* Add address, slot, and time length fields. */
-                ti = proto_tree_add_text(field_tree, tvb, offset, 2, "{Address: 0x%04x", gts_addr);
+                ti = proto_tree_add_text(subtree, tvb, (*offset), 3, "{Address: 0x%04x", gts_addr);
                 proto_item_append_text(ti, ", Slot: %i", gts_slot);
-                proto_item_append_text(ti, ", Length: %i}", gts_slot_len);
+                proto_item_append_text(ti, ", Length: %i}", gts_length);
             }
-            offset += sizeof(guint16)+sizeof(guint8);
+            (*offset) += 3;
         } /* 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_pending);
-    }
-    offset += sizeof(guint8);
-
-    for (i=0; i<paddr_num16; i++) {
-        guint16 addr = tvb_get_letohs(tvb, offset);
-        if (tree) {
-            proto_tree_add_uint(field_tree, hf_ieee802154_bcn_pending16, tvb, offset, sizeof(guint16), addr);
-        }
-        offset += sizeof(guint16);
-    }
-    for (i=0; i<paddr_num64; i++) {
-        guint64 addr = tvb_get_letoh64(tvb, offset);
-        if (tree) {
-            proto_tree_add_uint64_format_value(field_tree, hf_ieee802154_bcn_pending64, tvb, offset, sizeof(guint64), addr, "%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 */
+} /* dissect_ieee802154_gtsinfo */
 
 /*FUNCTION:------------------------------------------------------
  *  NAME
- *      dissect_ieee802154_cmd
+ *      dissect_ieee802154_pendaddr
  *  DESCRIPTION
- *      IEEE 802.15.4 packet dissection routine for command packets
+ *      Subdissector command for the pending address list fields
+ *      within the beacon frame.
  *  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 Wireshark uses to display packet.
- *      ieee802154_packet *packet   - IEEE 802.15.4 packet information.
+ *      tvbuff_t    *tvb            - pointer to buffer containing raw packet.
+ *      packet_info *pinfo          - pointer to packet information fields (unused).
+ *      proto_tree  *tree           - pointer to command subtree.
+ *      ieee802154_packet *packet   - IEEE 802.15.4 packet information (unused).
+ *      guint       *offset         - offset into the tvbuff to begin dissection.
  *  RETURNS
  *      void
  *---------------------------------------------------------------
- *  MAC Command Frames have a MAC Payload organized as follows:
- *  |Command Frame Identifier|   Command Payload    |
- *  |       1 Byte           |dependant upon command|
- *---------------------------------------------------------------
  */
 static void
-dissect_ieee802154_cmd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet   *packet)
+dissect_ieee802154_pendaddr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet, guint *offset)
 {
-    guint8              cmd_id;
-    guint               offset = 0;
-    proto_tree          *cmd_tree = NULL;
-    proto_item          *ti;
-    proto_item          *cmd_root = NULL;
-
-#define CMD_ADDR_CHECK(x)    if (!(x)) expert_add_info_format(pinfo, cmd_root, PI_MALFORMED, PI_WARN, "Invalid Addressing for %s", val_to_str(cmd_id, ieee802154_cmd_names, "Unknown Command"))
+    proto_tree  *subtree = NULL;
+    proto_item  *ti;
+    guint8      pend_spec;
+    guint8      pend_num16;
+    guint8      pend_num64;
+    int         i;
 
-    /* Get and display the command frame identifier. */
-    cmd_id = tvb_get_guint8(tvb, offset);
-    if(check_col(pinfo->cinfo, COL_INFO)) {
-        col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(cmd_id, ieee802154_cmd_names, "Unknown Command"));
-    }
+    /*  Get the Pending Addresses specification fields */
+    pend_spec = tvb_get_guint8(tvb, *offset);
+    pend_num16 = pend_spec & IEEE802154_PENDADDR_SHORT_MASK;
+    pend_num64 = (pend_spec & IEEE802154_PENDADDR_LONG_MASK) >> IEEE802154_PENDADDR_LONG_SHIFT;
     if (tree) {
-        /* Create a subtree for this command frame. */
-        cmd_root = proto_tree_add_text(tree, tvb, 0, tvb_length(tvb), "Command Frame, %s", val_to_str(cmd_id, ieee802154_cmd_names, "Unknown Command"));
-        cmd_tree = proto_item_add_subtree(cmd_root, ett_ieee802154_cmd);
-
-        /* Add the command ID to the subtree. */
-        ti = proto_tree_add_uint(cmd_tree, hf_ieee802154_cmd_id, tvb, offset, sizeof(guint8), cmd_id);
-    }
-
-    /* Increment the offset field. */
-    offset += sizeof(guint8);
-
-    /* Parse the Command Payloads. */
-    switch(cmd_id){
-        case IEEE802154_CMD_ASRQ:
-            /* Check that the addressing is correct for this command type. */
-            CMD_ADDR_CHECK((packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT)
-                        && (packet->dst_addr_mode != IEEE802154_FCF_ADDR_NONE));
-
-            dissect_ieee802154_cmd_asreq(tvb, pinfo, cmd_tree, packet, &offset);
-            break;
-
-        case IEEE802154_CMD_ASRSP:
-            /* Check that the addressing is correct for this command type. */
-            CMD_ADDR_CHECK((packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT)
-                        && (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT));
-
-            dissect_ieee802154_cmd_asrsp(tvb, pinfo, cmd_tree, packet, &offset);
-            break;
-
-        case IEEE802154_CMD_DISAS:
-            /* Check that the addressing is correct for this command type. */
-            CMD_ADDR_CHECK((packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT)
-                        && (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT));
-
-            dissect_ieee802154_cmd_disas(tvb, pinfo, cmd_tree, packet, &offset);
-            break;
-
-        case IEEE802154_CMD_DATA_RQ:
-            /* Check that the addressing is correct for this command type. */
-            CMD_ADDR_CHECK(packet->src_addr_mode != IEEE802154_FCF_ADDR_NONE);
-
-            /* 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_FCF_ADDR_EXT)
-                        && (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT));
-
-            /* 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_FCF_ADDR_EXT)
-                        && (packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT)
-                        && (packet->dst.addr16 == IEEE802154_BCAST_ADDR)
-                        && (packet->src_pan == IEEE802154_BCAST_PAN)
-                        && (packet->dst_pan == IEEE802154_BCAST_PAN));
-
-            /* 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_FCF_ADDR_SHORT)
-                        && (packet->src_addr_mode == IEEE802154_FCF_ADDR_NONE)
-                        && (packet->dst.addr16 == IEEE802154_BCAST_ADDR)
-                        && (packet->dst_pan == IEEE802154_BCAST_PAN));
-
-            /* Beacon Request contains no payload. */
-            break;
-
-        case IEEE802154_CMD_COORD_REAL:
-            /* Check that the addressing is correct for this command type. */
-            CMD_ADDR_CHECK((packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT)
-                        && (packet->dst_pan == IEEE802154_BCAST_PAN)
-                        && (packet->dst_addr_mode != IEEE802154_FCF_ADDR_NONE));
-
-            if (packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) {
-                /* If directed to a 16-bit address, check that it is being broadcast. */
-                CMD_ADDR_CHECK(packet->dst.addr16 == IEEE802154_BCAST_ADDR);
-            }
-
-            dissect_ieee802154_cmd_realign(tvb, pinfo, cmd_tree, packet, &offset);
-            break;
-
-        case IEEE802154_CMD_GTS_REQ:
-            /* Check that the addressing is correct for this command type. */
-            CMD_ADDR_CHECK((packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT)
-                        && (packet->dst_addr_mode == IEEE802154_FCF_ADDR_NONE)
-                        && (packet->src.addr16 != IEEE802154_BCAST_ADDR)
-                        && (packet->src.addr16 != IEEE802154_NO_ADDR16));
-
-            dissect_ieee802154_cmd_gtsrq(tvb, pinfo, cmd_tree, packet, &offset);
-            break;
-
-        default:
-            break;
-    } /* switch */
-
-#undef CMD_ADDR_CHECK
-
-    /* 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);
+        /*  Add Subtree for the addresses */
+        ti = proto_tree_add_text(tree, tvb, *offset, 1 + 2*pend_num16 + 8*pend_num64, "Pending Addresses: %i Short and %i Long", pend_num16, pend_num64);
+        subtree = proto_item_add_subtree(ti, ett_ieee802154_pendaddr);
     }
-} /* dissect_ieee802154_cmd */
+    (*offset) += 1;
+
+    for (i=0; i<pend_num16; i++) {
+        guint16 addr = tvb_get_letohs(tvb, *offset);
+        proto_tree_add_uint(subtree, hf_ieee802154_pending16, tvb, *offset, 2, addr);
+        (*offset) += 2;
+    } /* for */
+    for (i=0; i<pend_num64; i++) {
+        guint64 addr = tvb_get_letoh64(tvb, *offset);
+        proto_tree_add_uint64_format_value(subtree, hf_ieee802154_pending64, tvb, *offset, 8, addr, "%s (%s)", print_eui64_oui(addr), print_eui64(addr));
+        (*offset) += 8;
+    } /* for */
+} /* dissect_ieee802154_pendaddr */
 
 /*FUNCTION:------------------------------------------------------
  *  NAME
- *      dissect_ieee802154_cmd_asreq
+ *      dissect_ieee802154_assoc_req
  *  DESCRIPTION
  *      Command subdissector routine for the Association request
  *      command.
- *
- *      Assumes that COL_INFO will be set to the command name,
- *      command name will already be appended to the command subtree
- *      and protocol root. In addition, assumes that the command ID
- *      has already been parsed.
  *  PARAMETERS
  *      tvbuff_t    *tvb            - pointer to buffer containing raw packet.
- *      packet_info *pinfo          - pointer to packet information fields (unused).
- *      proto_tree  *tree           - pointer to command subtree.
- *      ieee802154_packet *packet   - IEEE 802.15.4 packet information (unused).
- *      guint       *offset         - offset into the tvbuff to begin dissection.
+ *      packet_info *pinfo          - pointer to packet information fields.
+ *      proto_tree  *tree           - pointer to protocol tree.
+ *      ieee802154_packet *packet   - IEEE 802.15.4 packet information.
  *  RETURNS
  *      void
  *---------------------------------------------------------------
  */
 static void
-dissect_ieee802154_cmd_asreq(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, ieee802154_packet *packet _U_, guint *offset)
+dissect_ieee802154_assoc_req(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet)
 {
-    proto_item          *ti;
-    proto_tree          *field_tree;
-    guint8              capability_info;
+    proto_tree          *subtree;
+    proto_item *        ti;
+    guint8              capability;
 
-    /* Get the capability info. */
-    capability_info = tvb_get_guint8(tvb, *offset);
-
-    /* Display capability info. */
+    /* Create a subtree for this command frame. */
     if (tree) {
-        ti = proto_tree_add_text(tree, tvb, *offset, sizeof(guint8), "Capability Information");
-        field_tree = proto_item_add_subtree(ti, ett_ieee802154_cmd_cinfo);
+        ti = proto_tree_add_text(tree, tvb, 0, 1, "%s", val_to_str(packet->command_id, ieee802154_cmd_names, "Unknown Command"));
+        subtree = proto_item_add_subtree(ti, ett_ieee802154_cmd);
+    }
 
+    /* Get and display capability info. */
+    capability = tvb_get_guint8(tvb, 0);
+    if (tree) {
         /* Enter the capability bits. */
-        proto_tree_add_boolean(field_tree, hf_ieee802154_cmd_cinfo_alt_coord, tvb, *offset, sizeof(guint8), capability_info & IEEE802154_CMD_CINFO_ALT_PAN_COORD);
-        ti = proto_tree_add_boolean(field_tree, hf_ieee802154_cmd_cinfo_device_type, tvb, *offset, sizeof(guint8), capability_info & IEEE802154_CMD_CINFO_DEVICE_TYPE);
-        if (capability_info & IEEE802154_CMD_CINFO_DEVICE_TYPE) proto_item_append_text(ti, " (FFD)");
+        proto_tree_add_boolean(subtree, hf_ieee802154_cinfo_alt_coord, tvb, 0, 1, capability & IEEE802154_CMD_CINFO_ALT_PAN_COORD);
+        ti = proto_tree_add_boolean(subtree, hf_ieee802154_cinfo_device_type, tvb, 0, 1, capability & IEEE802154_CMD_CINFO_DEVICE_TYPE);
+        if (capability & 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, sizeof(guint8), capability_info & IEEE802154_CMD_CINFO_POWER_SRC);
-        if (capability_info & IEEE802154_CMD_CINFO_POWER_SRC) proto_item_append_text(ti, " (AC/Mains Power)");
+        ti = proto_tree_add_boolean(subtree, hf_ieee802154_cinfo_power_src, tvb, 0, 1, capability & IEEE802154_CMD_CINFO_POWER_SRC);
+        if (capability & 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, sizeof(guint8), capability_info & IEEE802154_CMD_CINFO_IDLE_RX);
-        proto_tree_add_boolean(field_tree, hf_ieee802154_cmd_cinfo_sec_capable, tvb, *offset, sizeof(guint8), capability_info & IEEE802154_CMD_CINFO_SEC_CAPABLE);
-        proto_tree_add_boolean(field_tree, hf_ieee802154_cmd_cinfo_alloc_addr, tvb, *offset, sizeof(guint8), capability_info & IEEE802154_CMD_CINFO_ALLOC_ADDR);
+        proto_tree_add_boolean(subtree, hf_ieee802154_cinfo_idle_rx, tvb, 0, 1, capability & IEEE802154_CMD_CINFO_IDLE_RX);
+        proto_tree_add_boolean(subtree, hf_ieee802154_cinfo_sec_capable, tvb, 0, 1, capability & IEEE802154_CMD_CINFO_SEC_CAPABLE);
+        proto_tree_add_boolean(subtree, hf_ieee802154_cinfo_alloc_addr, tvb, 0, 1, capability & IEEE802154_CMD_CINFO_ALLOC_ADDR);
     }
 
-    /* Increase the offset. */
-    (*offset) += sizeof(guint8);
-} /* dissect_ieee802154_cmd_asreq */
+    /* Call the data dissector for any leftover bytes. */
+    if (tvb_length(tvb) > 1) {
+        call_dissector(data_handle, tvb_new_subset(tvb, 1, -1, -1), pinfo, tree);
+    }
+} /* dissect_ieee802154_assoc_req */
 
 /*FUNCTION:------------------------------------------------------
  *  NAME
- *      dissect_ieee802154_cmd_asrsp
+ *      dissect_ieee802154_assoc_rsp
  *  DESCRIPTION
  *      Command subdissector routine for the Association response
  *      command.
- *
- *      Assumes that COL_INFO will be set to the command name,
- *      command name will already be appended to the command subtree
- *      and protocol root. In addition, assumes that the command ID
- *      has already been parsed.
  *  PARAMETERS
  *      tvbuff_t    *tvb            - pointer to buffer containing raw packet.
- *      packet_info *pinfo          - pointer to packet information fields
- *      proto_tree  *tree           - pointer to command subtree.
- *      ieee802154_packet *packet   - IEEE 802.15.4 packet information (unused).
- *      guint       *offset         - offset into the tvbuff to begin dissection.
+ *      packet_info *pinfo          - pointer to packet information fields.
+ *      proto_tree  *tree           - pointer to protocol tree.
+ *      ieee802154_packet *packet   - IEEE 802.15.4 packet information.
  *  RETURNS
  *      void
  *---------------------------------------------------------------
  */
 static void
-dissect_ieee802154_cmd_asrsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet _U_, guint *offset)
+dissect_ieee802154_assoc_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet)
 {
+    proto_tree          *subtree;
     proto_item          *ti;
     guint16             short_addr;
     guint8              status;
+    guint               offset = 0;
+
+    /* Create a subtree for this command frame. */
+    if (tree) {
+        ti = proto_tree_add_text(tree, tvb, offset, 3, "%s", val_to_str(packet->command_id, ieee802154_cmd_names, "Unknown Command"));
+        subtree = proto_item_add_subtree(ti, ett_ieee802154_cmd);
+    }
 
     /* Get and display the short address. */
-    short_addr = tvb_get_letohs(tvb, *offset);
+    short_addr = tvb_get_letohs(tvb, offset);
     if (tree) {
-        proto_tree_add_uint(tree, hf_ieee802154_cmd_asrsp_addr, tvb, *offset, sizeof(guint16), short_addr);
+        proto_tree_add_uint(subtree, hf_ieee802154_assoc_addr, tvb, offset, 2, short_addr);
     }
-    (*offset) += sizeof(guint16);
+    offset += 2;
 
     /* Get and display the status. */
-    status = tvb_get_guint8(tvb, *offset);
+    status = tvb_get_guint8(tvb, offset);
     if (tree) {
-        ti = proto_tree_add_uint(tree, hf_ieee802154_cmd_asrsp_status, tvb, *offset, sizeof(guint8), status);
+        ti = proto_tree_add_uint(subtree, hf_ieee802154_assoc_status, tvb, offset, 1, status);
         if (status == IEEE802154_CMD_ASRSP_AS_SUCCESS) proto_item_append_text(ti, " (Association Successful)");
         else if (status == IEEE802154_CMD_ASRSP_PAN_FULL) proto_item_append_text(ti, " (PAN Full)");
         else if (status == IEEE802154_CMD_ASRSP_PAN_DENIED) proto_item_append_text(ti, " (Association Denied)");
         else proto_item_append_text(ti, " (Reserved)");
     }
-    (*offset) += sizeof(guint8);
+    offset += 1;
 
     /* Update the info column. */
     if (check_col(pinfo->cinfo, COL_INFO)) {
@@ -1449,38 +1417,44 @@ dissect_ieee802154_cmd_asrsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
             col_append_fstr(pinfo->cinfo, COL_INFO, ", Unsuccessful");
         }
     }
-} /* dissect_ieee802154_cmd_asrsp */
+
+    /* Call the data dissector for any leftover bytes. */
+    if (tvb_length(tvb) > offset) {
+        call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
+    }
+} /* dissect_ieee802154_assoc_rsp */
 
 /*FUNCTION:------------------------------------------------------
  *  NAME
- *      dissect_ieee802154_cmd_disas
+ *      dissect_ieee802154_disassoc
  *  DESCRIPTION
  *      Command subdissector routine for the Disassociate command.
- *
- *      Assumes that COL_INFO will be set to the command name,
- *      command name will already be appended to the command subtree
- *      and protocol root. In addition, assumes that the command ID
- *      has already been parsed.
  *  PARAMETERS
  *      tvbuff_t    *tvb            - pointer to buffer containing raw packet.
- *      packet_info *pinfo          - pointer to packet information fields (unused).
- *      proto_tree  *tree           - pointer to command subtree.
- *      ieee802154_packet *packet   - IEEE 802.15.4 packet information (unused).
- *      guint       *offset         - offset into the tvbuff to begin dissection.
+ *      packet_info *pinfo          - pointer to packet information fields.
+ *      proto_tree  *tree           - pointer to protocol tree.
+ *      ieee802154_packet *packet   - IEEE 802.15.4 packet information.
  *  RETURNS
  *      void
  *---------------------------------------------------------------
  */
 static void
-dissect_ieee802154_cmd_disas(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, ieee802154_packet *packet _U_, guint *offset)
+dissect_ieee802154_disassoc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet)
 {
+    proto_tree          *subtree;
     proto_item          *ti;
     guint8              reason;
 
+    /* Create a subtree for this command frame. */
+    if (tree) {
+        ti = proto_tree_add_text(tree, tvb, 0, 1, "%s", val_to_str(packet->command_id, ieee802154_cmd_names, "Unknown Command"));
+        subtree = proto_item_add_subtree(ti, ett_ieee802154_cmd);
+    }
+
     /* Get and display the dissasociation reason. */
-    reason = tvb_get_guint8(tvb, *offset);
+    reason = tvb_get_guint8(tvb, 0);
     if (tree) {
-        ti = proto_tree_add_uint(tree, hf_ieee802154_cmd_disas_reason, tvb, *offset, sizeof(guint8), reason);
+        ti = proto_tree_add_uint(subtree, hf_ieee802154_disassoc_reason, tvb, 0, 1, reason);
         switch(reason) {
             case 0x01:
                 proto_item_append_text(ti, " (Coordinator requests device to leave)");
@@ -1496,79 +1470,93 @@ dissect_ieee802154_cmd_disas(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *
         } /* switch */
     }
 
-    /* Adjust offset */
-    (*offset) += sizeof(guint8);
-} /* dissect_ieee802154_cmd_disas */
+    /* Call the data dissector for any leftover bytes. */
+    if (tvb_length(tvb) > 1) {
+        call_dissector(data_handle, tvb_new_subset(tvb, 1, -1, -1), pinfo, tree);
+    }
+} /* dissect_ieee802154_disassoc */
 
 /*FUNCTION:------------------------------------------------------
  *  NAME
- *      dissect_ieee802154_cmd_gtsrq
+ *      dissect_ieee802154_realign
  *  DESCRIPTION
  *      Command subdissector routine for the Coordinator Realignment
  *      command.
- *
- *      Assumes that COL_INFO will be set to the command name,
- *      command name will already be appended to the command subtree
- *      and protocol root. In addition, assumes that the command ID
- *      has already been parsed.
  *  PARAMETERS
  *      tvbuff_t    *tvb            - pointer to buffer containing raw packet.
- *      packet_info *pinfo          - pointer to packet information fields
- *      proto_tree  *tree           - pointer to command subtree.
+ *      packet_info *pinfo          - pointer to packet information fields.
+ *      proto_tree  *tree           - pointer to protocol tree.
  *      ieee802154_packet *packet   - IEEE 802.15.4 packet information.
- *      guint       *offset         - offset into the tvbuff to begin dissection.
  *  RETURNS
  *      void
  *---------------------------------------------------------------
  */
 static void
-dissect_ieee802154_cmd_realign(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet, guint *offset)
+dissect_ieee802154_realign(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet)
 {
-    guint16 pan_id;
-    guint16 coord_addr;
-    guint8  channel;
-    guint16 short_addr;
+    proto_tree          *subtree;
+    proto_item          *ti;
+    guint16             pan_id;
+    guint16             coord_addr;
+    guint8              channel;
+    guint16             short_addr;
+    guint               offset = 0;
+
+    /* Create a subtree for this command frame. */
+    if (tree) {
+        ti = proto_tree_add_text(tree, tvb, offset, 0, "%s", val_to_str(packet->command_id, ieee802154_cmd_names, "Unknown Command"));
+        subtree = proto_item_add_subtree(ti, ett_ieee802154_cmd);
+    }
 
     /* Get and display the command PAN ID. */
-    pan_id = tvb_get_letohs(tvb, *offset);
-    if (tree) proto_tree_add_uint(tree, hf_ieee802154_cmd_coord_pan, tvb, *offset, sizeof(guint16), pan_id);
+    pan_id = tvb_get_letohs(tvb, offset);
+    if (tree) proto_tree_add_uint(subtree, hf_ieee802154_realign_pan, 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);
+    offset += 2;
 
     /* Get and display the coordinator address. */
-    coord_addr = tvb_get_letohs(tvb, *offset);
-    if (tree) proto_tree_add_uint(tree, hf_ieee802154_cmd_coord_caddr, tvb, *offset, sizeof(guint16), coord_addr);
+    coord_addr = tvb_get_letohs(tvb, offset);
+    if (tree) proto_tree_add_uint(subtree, hf_ieee802154_realign_caddr, 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);
+    offset += 2;
 
     /* Get and display the channel. */
-    channel = tvb_get_guint8(tvb, *offset);
-    if (tree) proto_tree_add_uint(tree, hf_ieee802154_cmd_coord_channel, tvb, *offset, sizeof(guint8), channel);
+    channel = tvb_get_guint8(tvb, offset);
+    if (tree) proto_tree_add_uint(subtree, hf_ieee802154_realign_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);
+    offset += 1;
 
     /* Get and display the short address. */
-    short_addr = tvb_get_letohs(tvb, *offset);
-    if (tree) proto_tree_add_uint(tree, hf_ieee802154_cmd_coord_addr, tvb, *offset, sizeof(guint16), short_addr);
+    short_addr = tvb_get_letohs(tvb, offset);
+    if (tree) proto_tree_add_uint(subtree, hf_ieee802154_realign_addr, tvb, offset, 2, short_addr);
     if (   (check_col(pinfo->cinfo, COL_INFO))
         && (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT)
         && (short_addr != IEEE802154_NO_ADDR16)) {
         col_append_fstr(pinfo->cinfo, COL_INFO, ", Addr: 0x%04x", short_addr);
     }
-    (*offset) += sizeof(guint16);
+    offset += 2;
 
     /* Get and display the channel page, if it exists. Added in IEEE802.15.4-2006 */
-    if (tvb_bytes_exist(tvb, *offset, sizeof(guint8))) {
-        guint8  channel_page = tvb_get_guint8(tvb, *offset);
+    if (tvb_bytes_exist(tvb, offset, 1)) {
+        guint8  channel_page = tvb_get_guint8(tvb, offset);
+        if (tree) proto_tree_add_uint(subtree, hf_ieee802154_realign_channel_page, tvb, offset, 1, channel_page);
+        offset += 1;
+    }
+
+    /* Fix the length of the command subtree. */
+    if (tree) {
+        proto_item_set_len(subtree, offset);
+    }
 
-        if (tree) proto_tree_add_uint(tree, hf_ieee802154_cmd_coord_channel_page, tvb, *offset, sizeof(guint8), channel_page);
-        (*offset) += sizeof(guint8);
+    /* Call the data dissector for any leftover bytes. */
+    if (tvb_length(tvb) > offset) {
+        call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
     }
-} /* dissect_ieee802154_cmd_realign */
+} /* dissect_ieee802154_realign */
 
 /*FUNCTION:------------------------------------------------------
  *  NAME
- *      dissect_ieee802154_cmd_gtsrq
+ *      dissect_ieee802154_gtsreq
  *  DESCRIPTION
  *      Command subdissector routine for the GTS request command.
  *
@@ -1579,43 +1567,413 @@ dissect_ieee802154_cmd_realign(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tr
  *  PARAMETERS
  *      tvbuff_t    *tvb            - pointer to buffer containing raw packet.
  *      packet_info *pinfo          - pointer to packet information fields (unused).
- *      proto_tree  *tree           - pointer to command subtree.
+ *      proto_tree  *tree           - pointer to protocol tree.
  *      ieee802154_packet *packet   - IEEE 802.15.4 packet information (unused).
- *      guint       *offset         - offset into the tvbuff to begin dissection.
  *  RETURNS
  *      void
  *---------------------------------------------------------------
  */
 static void
-dissect_ieee802154_cmd_gtsrq(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, ieee802154_packet *packet _U_, guint *offset)
+dissect_ieee802154_gtsreq(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee802154_packet *packet)
 {
-    proto_item  *ti;
+    proto_tree          *subtree;
+    proto_item          *ti;
+    guint8              characteristics;
+    guint8              length;
+    guint8              direction;
+    guint8              type;
 
-    guint8  characteristics;
-    guint8  length;
-    guint8  direction;
-    guint8  type;
+    /* Create a subtree for this command frame. */
+    if (tree) {
+        ti = proto_tree_add_text(tree, tvb, 0, 1, "%s", val_to_str(packet->command_id, ieee802154_cmd_names, "Unknown Command"));
+        subtree = proto_item_add_subtree(ti, ett_ieee802154_cmd);
+    }
 
     /* Get the characteristics field. */
-    characteristics = tvb_get_guint8(tvb, *offset);
+    characteristics = tvb_get_guint8(tvb, 0);
     length = characteristics & IEEE802154_CMD_GTS_REQ_LEN;
     direction = characteristics & IEEE802154_CMD_GTS_REQ_DIR;
     type = characteristics & IEEE802154_CMD_GTS_REQ_TYPE;
 
     /* Display the characteristics field. */
     if (tree) {
-        proto_tree_add_uint(tree, hf_ieee802154_cmd_gts_req_len, tvb, *offset, sizeof(guint8), length);
-        ti = proto_tree_add_boolean(tree, hf_ieee802154_cmd_gts_req_dir, tvb, *offset, sizeof(guint8), direction);
+        proto_tree_add_uint(subtree, hf_ieee802154_gtsreq_len, tvb, 0, 1, length);
+        ti = proto_tree_add_boolean(subtree, hf_ieee802154_gtsreq_dir, tvb, 0, 1, direction);
         if (direction) proto_item_append_text(ti, " (Receive)");
         else proto_item_append_text(ti, " (Transmit)");
-        ti = proto_tree_add_boolean(tree, hf_ieee802154_cmd_gts_req_type, tvb, *offset, sizeof(guint8), type);
+        ti = proto_tree_add_boolean(subtree, hf_ieee802154_gtsreq_type, tvb, 0, 1, type);
         if (type) proto_item_append_text(ti, " (Allocate GTS)");
         else proto_item_append_text(ti, " (Deallocate GTS)");
     }
 
-    /* Adjust offset */
-    (*offset) += sizeof(guint8);
-} /* dissect_ieee802154_cmd_gtsrq */
+    /* Call the data dissector for any leftover bytes. */
+    if (tvb_length(tvb) > 1) {
+        call_dissector(data_handle, tvb_new_subset(tvb, 1, -1, -1), pinfo, tree);
+    }
+} /* dissect_ieee802154_gtsreq */
+
+/*FUNCTION:------------------------------------------------------
+ *  NAME
+ *      dissect_ieee802154_decrypt
+ *  DESCRIPTION
+ *      IEEE 802.15.4 decryption algorithm. Tries to find the
+ *      appropriate key from the information in the IEEE 802.15.4
+ *      packet structure and dissector config.
+ *
+ *      This function implements the security proceedures for the
+ *      2006 version of the spec only. IEEE 802.15.4-2003 is
+ *      unsupported.
+ *  PARAMETERS
+ *      tvbuff_t *tvb               - IEEE 802.15.4 packet.
+ *      packet_info * pinfo         - Packet info structure.
+ *      guint offset                - Offset where the ciphertext 'c' starts.
+ *      ieee802154_packet *packet   - IEEE 802.15.4 packet information.
+ *  RETURNS
+ *      tvbuff_t *                  - Decrypted payload, or NULL on decryption failure.
+ *---------------------------------------------------------------
+ */
+static tvbuff_t *
+dissect_ieee802154_decrypt(tvbuff_t * tvb, guint offset, packet_info * pinfo, ieee802154_packet * packet)
+{
+    tvbuff_t *          dec_tvb;
+    gboolean            have_mic = FALSE;
+    guint64             srcAddr;
+    unsigned char       key[16];
+    unsigned char       tmp[16];
+    unsigned char       rx_mic[16];
+    guint               M;
+    void *              text;
+    gint                real_len;
+    gint                reported_len;
+
+    /* Check the version, we only support IEEE 802.15.4-2006 */
+    if (packet->version < IEEE802154_VERSION_2006) return NULL;
+
+    /* Compute the length of the MIC from the security level. */
+    M = IEEE802154_MIC_LENGTH(packet->security_level);
+    /* If the last 'M' bytes of the payload exist, then parse the MIC. */
+    have_mic = M && tvb_bytes_exist(tvb, tvb_reported_length(tvb)-M-IEEE802154_FCS_LEN, M);
+    if (have_mic) {
+        tvb_memcpy(tvb, rx_mic, tvb_reported_length(tvb)-M-IEEE802154_FCS_LEN, M);
+    }
+    /* Compute the real and reported length of the payload (since it might be truncated). */
+    real_len = tvb_length(tvb) - offset - IEEE802154_FCS_LEN - M;
+    reported_len = tvb_reported_length(tvb) - offset - IEEE802154_FCS_LEN - M;
+    if (real_len < 0) return NULL;
+    if (reported_len < 0) return NULL;
+
+    /*
+     * If the payload is not encrypted, then we can get out now.
+     *
+     * NOTE: even though the payload may not be encrypted, it might still
+     * be verified by an authentication tag. By exiting early we are
+     * skipping the message verification proceedure.
+     *
+     * I'm not sure if we really care or not whether the tag is valid. If
+     * anyone feels strongly about it, you're welcome to modify the code to
+     * implement it. If you do go down that route, don't forget that l(m)==0
+     * and 'a' includes the payload when security_level < encryption.
+     */
+    if (!IEEE802154_IS_ENCRYPTED(packet->security_level)) {
+        return tvb_new_subset(tvb, offset, real_len, reported_len);
+    }
+
+    /*=====================================================
+     * Key Lookup - Need to find the appropriate key.
+     *=====================================================
+     */
+    /*
+     * Oh God! The specification is so bad. This is the worst
+     * case of design-by-committee I've ever seen in my life.
+     * The IEEE has created an unintelligable mess in order
+     * to decipher which key is used for which message.
+     *
+     * Let's hope it's simpler to implement for dissecting only.
+     *
+     * Also need to find the extended address of the sender.
+     */
+    /* Get the extended source address. */
+    if (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) {
+        srcAddr = packet->src.addr64;
+    }
+    else {
+        /* TODO: Implement a lookup table or something. */
+        return NULL;
+    }
+
+    /* Lookup the key. */
+    /*
+     * TODO: What this dissector really needs is a UAT to store multiple keys
+     * and a variety of key configuration data. However, a single shared key
+     * should be sufficient to get packet encryption off to a start.
+     */
+    if (!ieee802154_key_valid) return NULL;
+    memcpy(key, ieee802154_key, IEEE802154_CIPHER_SIZE);
+
+    /* Make a copy of the ciphertext w/o the MIC. */
+    /* We will decrypt the message in-place and then use this for the new tvb. */
+    text = tvb_memdup(tvb, offset, real_len);
+
+    /*=====================================================
+     * CCM* - CTR mode payload encryption
+     *=====================================================
+     */
+    /* Create the CCM* initial block for decryption (Adata=0, M=0, counter=0). */
+    ccm_init_block(tmp, FALSE, 0, srcAddr, packet->frame_counter, packet->security_level, 0);
+    /* Perform CTR-mode transformation. */
+    if (!ccm_ctr_encrypt(key, tmp, rx_mic, text, real_len)) {
+        g_free(text);
+        return NULL;
+    }
+
+    /*=====================================================
+     * CCM* - CBC-mode message authentication
+     *=====================================================
+     */
+    /* We can only verify the message if the MIC wasn't truncated. */
+    if (have_mic) {
+        unsigned char           dec_mic[16];
+
+        /* Create the CCM* initial block for authentication (Adata!=0, M!=0, counter=l(m)). */
+        ccm_init_block(tmp, TRUE, M, srcAddr, packet->frame_counter, packet->security_level, real_len);
+        /* Compute CBC-MAC authentication tag. */
+        if (!ccm_cbc_mac(key, tmp, ep_tvb_memdup(tvb, 0, offset), offset, text, real_len, dec_mic)) {
+            g_free(text);
+            return NULL;
+        }
+
+        /* Compare the received MIC with the one we generated. */
+        if (memcmp(rx_mic, dec_mic, M) != 0) {
+            g_free(text);
+            return NULL;
+        }
+    }
+
+    /* Done! */
+    dec_tvb = tvb_new_real_data(text, real_len, reported_len);
+    tvb_set_child_real_data_tvbuff(tvb, dec_tvb);
+    add_new_data_source(pinfo, dec_tvb, "IEEE 802.15.4 decryption");
+    return dec_tvb;
+} /* dissect_ieee802154_decrypt */
+
+/*FUNCTION:------------------------------------------------------
+ *  NAME
+ *      ccm_init_block
+ *  DESCRIPTION
+ *      Creates the CCM* initial block value for IEEE 802.15.4.
+ *  PARAMETERS
+ *      gchar *block        - Output pointer for the initial block.
+ *      gboolean adata      - TRUE if additional auth data is present
+ *      gint M              - CCM* parameter M.
+ *      guint64 addr        - Source extended address.
+ *      guint32 counter     - Frame counter.
+ *      ieee802154_security_level level - Security leve being used.
+ *      guint16 ctr_val     - Value in the last L bytes of the block.
+ *  RETURNS
+ *      void
+ *---------------------------------------------------------------
+ */
+static void
+ccm_init_block(gchar *block, gboolean adata, gint M, guint64 addr, guint32 counter, ieee802154_security_level level, gint ctr_val)
+{
+    gint                i = 0;
+
+    /* Flags: Reserved(0) || Adata || (M-2)/2 || (L-1) */
+    block[i] = (0x2 - 1); /* (L-1) */
+    if (M > 0) block[i] |= (((M-2)/2) << 3); /* (M-2)/2 */
+    if (adata) block[i] |= (1 << 6); /* Adata */
+    i++;
+    /* Nonce: Source Address || Frame Counter || Security Level */
+    block[i++] = (addr >> 56) & 0xff;
+    block[i++] = (addr >> 48) & 0xff;
+    block[i++] = (addr >> 40) & 0xff;
+    block[i++] = (addr >> 32) & 0xff;
+    block[i++] = (addr >> 24) & 0xff;
+    block[i++] = (addr >> 16) & 0xff;
+    block[i++] = (addr >> 8) & 0xff;
+    block[i++] = (addr >> 0) & 0xff;
+    block[i++] = (counter >> 24) & 0xff;
+    block[i++] = (counter >> 16) & 0xff;
+    block[i++] = (counter >> 8) & 0xff;
+    block[i++] = (counter >> 0) & 0xff;
+    block[i++] = level;
+    /* Plaintext length. */
+    block[i++] = (ctr_val >> 8) & 0xff;
+    block[i++] = (ctr_val >> 0) & 0xff;
+} /* ccm_init_block */
+
+/*FUNCTION:------------------------------------------------------
+ *  NAME
+ *      ccm_ctr_encrypt
+ *  DESCRIPTION
+ *      Performs an in-place CTR-mode encryption/decryption.
+ *  PARAMETERS
+ *      const gchar *key    - Encryption Key.
+ *      const gchar *iv     - Counter initial value.
+ *      gchar *mic          - MIC to encrypt/decrypt.
+ *      gchar *data         - Buffer to encrypt/decrypt.
+ *      gint length         - Length of the buffer.
+ *  RETURNS
+ *      gboolean            - TRUE on SUCCESS, FALSE on error.
+ *---------------------------------------------------------------
+ */
+static gboolean
+ccm_ctr_encrypt(const gchar *key, const gchar *iv, gchar *mic, gchar *data, gint length)
+{
+#ifdef HAVE_LIBGCRYPT
+    gcry_cipher_hd_t    cipher_hd;
+
+    /* Open the cipher. */
+    if (gcry_cipher_open(&cipher_hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR, 0)) {
+        return FALSE;
+    }
+
+    /* Set the key and initial value. */
+    if (gcry_cipher_setkey(cipher_hd, key, 16)) {
+        gcry_cipher_close(cipher_hd);
+        return FALSE;
+    }
+    if (gcry_cipher_setctr(cipher_hd, iv, 16)) {
+        gcry_cipher_close(cipher_hd);
+        return FALSE;
+    }
+
+    /* Decrypt the MIC. */
+    if (gcry_cipher_encrypt(cipher_hd, mic, 16, NULL, 0)) {
+        gcry_cipher_close(cipher_hd);
+        return FALSE;
+    }
+    /* Decrypt the payload. */
+    if (gcry_cipher_encrypt(cipher_hd, data, length, NULL, 0)) {
+        gcry_cipher_close(cipher_hd);
+        return FALSE;
+    }
+
+    /* Done with the cipher. */
+    gcry_cipher_close(cipher_hd);
+    return TRUE;
+#else
+    return FALSE;
+#endif
+} /* ccm_ctr_encrypt */
+
+/*FUNCTION:------------------------------------------------------
+ *  NAME
+ *      ccm_cbc_mac
+ *  DESCRIPTION
+ *      Generates a CBC-MAC of the decrypted payload and additional
+ *      authentication headers.
+ *  PARAMETERS
+ *      const gchar key     - Encryption Key.
+ *      const gchar iv      - Counter initial value.
+ *      const gchar a       - Additional auth headers.
+ *      gint a_len                  - Length of the additional headers.
+ *      const gchar m       - Plaintext message.
+ *      gint m_len                  - Length of plaintext message.
+ *      gchar *mic          - Output for CBC-MAC.
+ *  RETURNS
+ *      gboolean            - TRUE on SUCCESS, FALSE on error.
+ *---------------------------------------------------------------
+ */
+static gboolean
+ccm_cbc_mac(const gchar *key, const gchar *iv, const gchar *a, gint a_len, const gchar *m, gint m_len, gchar *mic)
+{
+#ifdef HAVE_LIBGCRYPT
+    gcry_cipher_hd_t    cipher_hd;
+    int                 i = 0;
+    unsigned char       block[16];
+
+    /* Open the cipher. */
+    if (gcry_cipher_open(&cipher_hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_CBC_MAC)) return FALSE;
+
+    /* Set the key. */
+    if (gcry_cipher_setkey(cipher_hd, key, 16)) {
+        gcry_cipher_close(cipher_hd);
+        return FALSE;
+    }
+
+    /* Process the initial value. */
+    if (gcry_cipher_encrypt(cipher_hd, mic, 16, iv, 16)) {
+        gcry_cipher_close(cipher_hd);
+        return FALSE;
+    }
+
+    /* Encode L(a) */
+    i = 0;
+#if (GINT_MAX >= (1LL << 32))
+    if (a_len >= (1LL << 32)) {
+        block[i++] = 0xff;
+        block[i++] = 0xff;
+        block[i++] = (a_len >> 56) & 0xff;
+        block[i++] = (a_len >> 48) & 0xff;
+        block[i++] = (a_len >> 40) & 0xff;
+        block[i++] = (a_len >> 32) & 0xff;
+        block[i++] = (a_len >> 24) & 0xff;
+        block[i++] = (a_len >> 16) & 0xff;
+        block[i++] = (a_len >> 8) & 0xff;
+        block[i++] = (a_len >> 0) & 0xff;
+    }
+    else
+#endif
+    if (a_len >= ((1 << 16) - (1 << 8))) {
+        block[i++] = 0xff;
+        block[i++] = 0xfe;
+        block[i++] = (a_len >> 24) & 0xff;
+        block[i++] = (a_len >> 16) & 0xff;
+        block[i++] = (a_len >> 8) & 0xff;
+        block[i++] = (a_len >> 0) & 0xff;
+    }
+    else {
+        block[i++] = (a_len >> 8) & 0xff;
+        block[i++] = (a_len >> 0) & 0xff;
+    }
+    /* Append a to get the first block of input (pad if we encounter the end of a). */
+    while ((i < sizeof(block)) && (a_len-- > 0)) block[i++] = *a++;
+    while (i < sizeof(block)) block[i++] = 0;
+
+    /* Process the first block of AuthData. */
+    if (gcry_cipher_encrypt(cipher_hd, mic, 16, block, 16)) {
+        gcry_cipher_close(cipher_hd);
+        return FALSE;
+    }
+
+    /* Transform and process the remainder of a. */
+    while (a_len > 0) {
+        /* Copy and pad. */
+        if (a_len >= sizeof(block)) memcpy(block, a, sizeof(block));
+        else {memcpy(block, a, a_len); memset(block+a_len, 0, sizeof(block)-a_len);}
+        /* Adjust pointers. */
+        a += sizeof(block);
+        a_len -= sizeof(block);
+        /* Execute the CBC-MAC algorithm. */
+        if (gcry_cipher_encrypt(cipher_hd, mic, 16, block, sizeof(block))) {
+            gcry_cipher_close(cipher_hd);
+            return FALSE;
+        }
+    } /* while */
+
+    /* Process the message, m. */
+    while (m_len > 0) {
+        /* Copy and pad. */
+        if (m_len >= sizeof(block)) memcpy(block, m, sizeof(block));
+        else {memcpy(block, m, m_len); memset(block+m_len, 0, sizeof(block)-m_len);}
+        /* Adjust pointers. */
+        m += sizeof(block);
+        m_len -= sizeof(block);
+        /* Execute the CBC-MAC algorithm. */
+        if (gcry_cipher_encrypt(cipher_hd, mic, 16, block, sizeof(block))) {
+            gcry_cipher_close(cipher_hd);
+            return FALSE;
+        }
+    }
+
+    /* Done with the cipher. */
+    gcry_cipher_close(cipher_hd);
+    return TRUE;
+#else
+    return FALSE;
+#endif
+} /* ccm_cbc_mac */
 
 /*FUNCTION:------------------------------------------------------
  *  NAME
@@ -1728,125 +2086,126 @@ void proto_register_ieee802154(void)
             /*--------------------------------*/
 
         { &hf_ieee802154_cmd_id,
-        { "Command Identifier",         "wpan.cmd.id", FT_UINT8, BASE_HEX, VALS(ieee802154_cmd_names), 0x0,
+        { "Command Identifier",         "wpan.cmd", FT_UINT8, BASE_HEX, VALS(ieee802154_cmd_names), 0x0,
             NULL, HFILL }},
 
             /*  Capability Information Fields */
-        { &hf_ieee802154_cmd_cinfo_alt_coord,
-        { "Alternate PAN Coordinator",  "wpan.cmd.cinfo.alt_coord", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_ALT_PAN_COORD,
+        { &hf_ieee802154_cinfo_alt_coord,
+        { "Alternate PAN Coordinator",  "wpan.cinfo.alt_coord", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_ALT_PAN_COORD,
             "Whether this device can act as a PAN coordinator or not.", HFILL }},
 
-        { &hf_ieee802154_cmd_cinfo_device_type,
-        { "Device Type",                "wpan.cmd.cinfo.device_type", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_DEVICE_TYPE,
+        { &hf_ieee802154_cinfo_device_type,
+        { "Device Type",                "wpan.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",               "wpan.cmd.cinfo.power_src", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_POWER_SRC,
+        { &hf_ieee802154_cinfo_power_src,
+        { "Power Source",               "wpan.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",       "wpan.cmd.cinfo.idle_rx", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_IDLE_RX,
+        { &hf_ieee802154_cinfo_idle_rx,
+        { "Receive On When Idle",       "wpan.cinfo.idle_rx", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_IDLE_RX,
             "Whether this device can receive packets while idle or not.", HFILL }},
 
-        { &hf_ieee802154_cmd_cinfo_sec_capable,
-        { "Security Capability",        "wpan.cmd.cinfo.sec_capable", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_SEC_CAPABLE,
+        { &hf_ieee802154_cinfo_sec_capable,
+        { "Security Capability",        "wpan.cinfo.sec_capable", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_SEC_CAPABLE,
             "Whether this device is capable of receiving encrypted packets.", HFILL }},
 
-        { &hf_ieee802154_cmd_cinfo_alloc_addr,
-        { "Allocate Address",           "wpan.cmd.cinfo.alloc_addr", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_ALLOC_ADDR,
+        { &hf_ieee802154_cinfo_alloc_addr,
+        { "Allocate Address",           "wpan.cinfo.alloc_addr", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_ALLOC_ADDR,
             "Whether this device wishes to use a 16-bit short address instead of its IEEE 802.15.4 64-bit long address.", HFILL }},
 
             /*  Association response fields */
-        { &hf_ieee802154_cmd_asrsp_addr,
-        { "Short Address",              "wpan.cmd.asrsp.addr", FT_UINT16, BASE_HEX, NULL, 0x0,
+        { &hf_ieee802154_assoc_addr,
+        { "Short Address",              "wpan.asoc.addr", FT_UINT16, BASE_HEX, NULL, 0x0,
             "The short address that the device should assume. An address of 0xfffe indicates that the device should use its IEEE 64-bit long address.", HFILL }},
 
-        { &hf_ieee802154_cmd_asrsp_status,
-        { "Association Status",         "wpan.cmd.asrsp.status", FT_UINT8, BASE_HEX, NULL, 0x0,
+        { &hf_ieee802154_assoc_status,
+        { "Association Status",         "wpan.assoc.status", FT_UINT8, BASE_HEX, NULL, 0x0,
             NULL, HFILL }},
 
-        { &hf_ieee802154_cmd_disas_reason,
-        { "Disassociation Reason",      "wpan.cmd.disas.reason", FT_UINT8, BASE_HEX, NULL, 0x0,
+        { &hf_ieee802154_disassoc_reason,
+        { "Disassociation Reason",      "wpan.disassoc.reason", FT_UINT8, BASE_HEX, NULL, 0x0,
             NULL, HFILL }},
 
             /*  Coordinator Realignment fields */
-        { &hf_ieee802154_cmd_coord_pan,
-        { "PAN ID",                     "wpan.cmd.coord.pan", FT_UINT16, BASE_HEX, NULL, 0x0,
+        { &hf_ieee802154_realign_pan,
+        { "PAN ID",                     "wpan.realign.pan", FT_UINT16, BASE_HEX, NULL, 0x0,
             "The PAN identifier the coordinator wishes to use for future communication.", HFILL }},
 
-        { &hf_ieee802154_cmd_coord_caddr,
-        { "Coordinator Short Address",  "wpan.cmd.coord.addr", FT_UINT16, BASE_HEX, NULL, 0x0,
+        { &hf_ieee802154_realign_caddr,
+        { "Coordinator Short Address",  "wpan.realign.addr", FT_UINT16, BASE_HEX, NULL, 0x0,
             "The 16-bit address the coordinator wishes to use for future communication.", HFILL }},
 
-        { &hf_ieee802154_cmd_coord_channel,
-        { "Logical Channel",            "wpan.cmd.coord.channel", FT_UINT8, BASE_DEC, NULL, 0x0,
+        { &hf_ieee802154_realign_channel,
+        { "Logical Channel",            "wpan.realign.channel", FT_UINT8, BASE_DEC, NULL, 0x0,
             "The logical channel the coordinator wishes to use for future communication.", HFILL }},
 
-        { &hf_ieee802154_cmd_coord_addr,
-        { "Short Address",              "wpan.cmd.coord.addr", FT_UINT16, BASE_HEX, NULL, 0x0,
+        { &hf_ieee802154_realign_addr,
+        { "Short Address",              "wpan.realign.addr", FT_UINT16, BASE_HEX, NULL, 0x0,
             "A short-address that the orphaned device shall assume if applicable.", HFILL }},
 
-        { &hf_ieee802154_cmd_coord_channel_page,
-        { "Channel Page",               "wpan.cmd.coord.channel_page", FT_UINT8, BASE_DEC, NULL, 0x0,
+        { &hf_ieee802154_realign_channel_page,
+        { "Channel Page",               "wpan.realign.channel_page", FT_UINT8, BASE_DEC, NULL, 0x0,
             "The logical channel page the coordinator wishes to use for future communication.", HFILL }},
 
-        { &hf_ieee802154_cmd_gts_req_len,
-        { "GTS Length",                 "wpan.cmd.gts.length", FT_UINT8, BASE_DEC, NULL, IEEE802154_CMD_GTS_REQ_LEN,
+        { &hf_ieee802154_gtsreq_len,
+        { "GTS Length",                 "wpan.gtsreq.length", FT_UINT8, BASE_DEC, NULL, IEEE802154_CMD_GTS_REQ_LEN,
             "Number of superframe slots the device is requesting.", HFILL }},
 
-        { &hf_ieee802154_cmd_gts_req_dir,
-        { "GTS Direction",              "wpan.cmd.gts.direction", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_GTS_REQ_DIR,
+        { &hf_ieee802154_gtsreq_dir,
+        { "GTS Direction",              "wpan.gtsreq.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",        "wpan.cmd.gts.type", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_GTS_REQ_TYPE,
+        { &hf_ieee802154_gtsreq_type,
+        { "Characteristic Type",        "wpan.gtsreq.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_beacon_order,
-        { "Beacon Interval",            "wpan.bcn.beacon_order", FT_UINT8, BASE_DEC, NULL, 0x0,
+        { &hf_ieee802154_beacon_order,
+        { "Beacon Interval",            "wpan.beacon_order", FT_UINT16, BASE_DEC, NULL, IEEE802154_BEACON_ORDER_MASK,
             "Specifies the transmission interval of the beacons.", HFILL }},
 
-        { &hf_ieee802154_bcn_superframe_order,
-        { "Superframe Interval",        "wpan.bcn.superframe_order", FT_UINT8, BASE_DEC, NULL, 0x0,
+        { &hf_ieee802154_superframe_order,
+        { "Superframe Interval",        "wpan.superframe_order", FT_UINT16, BASE_DEC, NULL, IEEE802154_SUPERFRAME_ORDER_MASK,
             "Specifies the length of time the coordinator will interact with the PAN.", HFILL }},
 
-        { &hf_ieee802154_bcn_cap,
-        { "Final CAP Slot",             "wpan.bcn.cap", FT_UINT8, BASE_DEC, NULL, 0x0,
+        { &hf_ieee802154_cap,
+        { "Final CAP Slot",             "wpan.cap", FT_UINT16, BASE_DEC, NULL, IEEE802154_SUPERFRAME_CAP_MASK,
             "Specifies the final superframe slot used by the CAP.", HFILL }},
 
-        { &hf_ieee802154_bcn_battery_ext,
-        { "Battery Extension",          "wpan.bcn.battery_ext", FT_BOOLEAN, 8, NULL, IEEE802154_BCN_BATT_EXTN_MASK,
+        { &hf_ieee802154_superframe_battery_ext,
+        { "Battery Extension",          "wpan.battery_ext", FT_BOOLEAN, 16, NULL, IEEE802154_BATT_EXTENSION_MASK,
             "Whether transmissions may not extend past the length of the beacon frame.", HFILL }},
 
-        { &hf_ieee802154_bcn_coord,
-        { "PAN Coordinator",            "wpan.bcn.coord", FT_BOOLEAN, 8, NULL, IEEE802154_BCN_COORD_MASK,
+        { &hf_ieee802154_superframe_coord,
+        { "PAN Coordinator",            "wpan.bcn_coord", FT_BOOLEAN, 16, NULL, IEEE802154_SUPERFRAME_COORD_MASK,
             "Whether this beacon frame is being transmitted by the PAN coordinator or not.", HFILL }},
 
-        { &hf_ieee802154_bcn_assoc_permit,
-        { "Association Permit",         "wpan.bcn.assoc_permit", FT_BOOLEAN, 8, NULL, IEEE802154_BCN_ASSOC_PERM_MASK,
+        { &hf_ieee802154_assoc_permit,
+        { "Association Permit",         "wpan.assoc_permit", FT_BOOLEAN, 16, NULL, IEEE802154_ASSOC_PERMIT_MASK,
             "Whether this PAN is accepting association requests or not.", HFILL }},
 
-        { &hf_ieee802154_bcn_gts_count,
-        { "GTS Descriptor Count",       "wpan.bcn.gts.count", FT_UINT8, BASE_DEC, NULL, 0x0,
+        { &hf_ieee802154_gts_count,
+        { "GTS Descriptor Count",       "wpan.gts.count", FT_UINT8, BASE_DEC, NULL, 0x0,
             "The number of GTS descriptors present in this beacon frame.", HFILL }},
 
-        { &hf_ieee802154_bcn_gts_permit,
-        { "GTS Permit",                 "wpan.bcn.gts.permit", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+        { &hf_ieee802154_gts_permit,
+        { "GTS Permit",                 "wpan.gts.permit", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
             "Whether the PAN coordinator is accepting GTS requests or not.", HFILL }},
 
-        { &hf_ieee802154_bcn_gts_direction,
-        { "Direction",                  "wpan.bcn.gts.direction", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+        { &hf_ieee802154_gts_direction,
+        { "Direction",                  "wpan.gts.direction", FT_BOOLEAN, 8, TFS(&ieee802154_gts_direction_tfs), 0x0,
             "A flag defining the direction of the GTS Slot.", HFILL }},
 
-        { &hf_ieee802154_bcn_pending16,
-        { "Address",                    "wpan.bcn.pending16", FT_UINT16, BASE_HEX, NULL, 0x0,
+        { &hf_ieee802154_pending16,
+        { "Address",                    "wpan.pending16", FT_UINT16, BASE_HEX, NULL, 0x0,
             "Device with pending data to receive.", HFILL }},
 
-        { &hf_ieee802154_bcn_pending64,
-        { "Address",                    "wpan.bcn.pending64", FT_UINT64, BASE_HEX, NULL, 0x0,
+        { &hf_ieee802154_pending64,
+        { "Address",                    "wpan.pending64", FT_UINT64, BASE_HEX, NULL, 0x0,
             "Device with pending data to receive.", HFILL }},
+
             /* Auxiliary Security Header Fields */
             /*----------------------------------*/
         { &hf_ieee802154_security_level,
@@ -1884,13 +2243,11 @@ void proto_register_ieee802154(void)
         &ett_ieee802154_aux_sec_key_id,
         &ett_ieee802154_fcs,
         &ett_ieee802154_cmd,
-        &ett_ieee802154_cmd_cinfo,
-        &ett_ieee802154_bcn,
-        &ett_ieee802154_bcn_superframe_spec,
-        &ett_ieee802154_bcn_gts_spec,
-        &ett_ieee802154_bcn_gts_direction,
-        &ett_ieee802154_bcn_gts_descriptors,
-        &ett_ieee802154_bcn_pending
+        &ett_ieee802154_superframe,
+        &ett_ieee802154_gts,
+        &ett_ieee802154_gts_direction,
+        &ett_ieee802154_gts_descriptors,
+        &ett_ieee802154_pendaddr
     };
 
     module_t *ieee802154_module;
@@ -1921,6 +2278,11 @@ void proto_register_ieee802154(void)
                                    "Dissect data only if FCS is ok.",
                                    &ieee802154_fcs_ok);
 
+    /* Register preferences for a decryption key */
+    /* TODO: Implement a UAT for multiple keys, and with more advanced key management. */
+    prefs_register_string_preference(ieee802154_module, "802154_key", "Decryption key",
+            "128-bit decryption key in hexadecimal format", (const char **)&ieee802154_key_str);
+
     /* Register the subdissector list */
     register_heur_dissector_list("wpan", &ieee802154_heur_subdissector_list);
 
@@ -1935,7 +2297,7 @@ void proto_register_ieee802154(void)
  *  NAME
  *      proto_reg_handoff_ieee802154
  *  DESCRIPTION
- *      Registers the zigbee dissector with Wireshark.
+ *      Registers the IEEE 802.15.4 dissector with Wireshark.
  *      Will be called every time 'apply' is pressed in the preferences menu.
  *       as well as during Wireshark initialization
  *  PARAMETERS
@@ -1950,6 +2312,8 @@ void proto_reg_handoff_ieee802154(void)
     static dissector_handle_t  ieee802154_handle;
     static dissector_handle_t  ieee802154_nonask_phy_handle;
     static unsigned int old_ieee802154_ethertype;
+    GByteArray *bytes;
+    gboolean    res;
 
     if (!prefs_initialized){
         /* Get the dissector handles. */
@@ -1967,8 +2331,16 @@ void proto_reg_handoff_ieee802154(void)
 
     old_ieee802154_ethertype = ieee802154_ethertype;
 
+    /* Get the IEEE 802.15.4 decryption key. */
+    bytes = g_byte_array_new();
+    res = hex_str_to_bytes(ieee802154_key_str, bytes, FALSE);
+    ieee802154_key_valid =  (res && bytes->len >= IEEE802154_CIPHER_SIZE);
+    if (ieee802154_key_valid) {
+        memcpy(ieee802154_key, bytes->data, IEEE802154_CIPHER_SIZE);
+    }
+    g_byte_array_free(bytes, TRUE);
+
     /* Register dissector handles. */
     dissector_add("ethertype", ieee802154_ethertype, ieee802154_handle);
-
 } /* proto_reg_handoff_ieee802154 */
 
index b41b28ed065809fc310059c946e9d9da94f54bb8..428f5733592f73cc1d9561477c8e3927b8602406 100644 (file)
 #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
+#define IEEE802154_BEACON_ORDER_MASK        0x000F
+#define IEEE802154_SUPERFRAME_ORDER_MASK    0x00F0
+#define IEEE802154_SUPERFRAME_CAP_MASK      0x0F00
+#define IEEE802154_BATT_EXTENSION_MASK      0x1000
+#define IEEE802154_SUPERFRAME_COORD_MASK    0x4000
+#define IEEE802154_ASSOC_PERMIT_MASK        0x8000
+#define IEEE802154_SUPERFRAME_ORDER_SHIFT   4
+#define IEEE802154_SUPERFRAME_CAP_SHIFT     8
+
+#define IEEE802154_GTS_COUNT_MASK           0x03
+#define IEEE802154_GTS_PERMIT_MASK          0x80
+#define IEEE802154_GTS_DIRECTION_SLOT(i)    (0x01<<(i))
+#define IEEE802154_GTS_MAX_SLOTS            7
+#define IEEE802154_GTS_DIRECTION_SLOT1      0x01
+#define IEEE802154_GTS_DIRECTION_SLOT2      0x02
+#define IEEE802154_GTS_DIRECTION_SLOT3      0x04
+#define IEEE802154_GTS_DIRECTION_SLOT4      0x08
+#define IEEE802154_GTS_DIRECTION_SLOT5      0x10
+#define IEEE802154_GTS_DIRECTION_SLOT6      0x20
+#define IEEE802154_GTS_DIRECTION_SLOT7      0x40
+#define IEEE802154_GTS_SLOT_MASK            0x0F
+#define IEEE802154_GTS_LENGTH_MASK          0xF0
+#define IEEE802154_GTS_LENGTH_SHIFT         4
+
+#define IEEE802154_PENDADDR_SHORT_MASK      0x07
+#define IEEE802154_PENDADDR_LONG_MASK       0x70
+#define IEEE802154_PENDADDR_LONG_SHIFT      4
+
+#define IEEE802154_SUPERFRAME_DURATION      (IEEE802154_BASE_SLOT_DURATION * IEEE802154_SUPERFRAME_SLOTS)
+#define IEEE802154_BASE_SLOT_DURATION       60
+#define IEEE802154_SUPERFRAME_SLOTS         16
 
 /*  Bit-masks for the FCF */
 #define IEEE802154_FCF_TYPE_MASK            0x0007  /* Frame Type Mask */
 #define IEEE802154_FCF_ACK                  0x0002  /* Acknowlegement Frame */
 #define IEEE802154_FCF_CMD                  0x0003  /* Command Frame */
 
+/* Frame version definitions. */
+#define IEEE802154_VERSION_2003             0x0
+#define IEEE802154_VERSION_2006             0x1
+
 /* Address Mode Definitions */
 #define IEEE802154_FCF_ADDR_NONE            0x0000
 #define IEEE802154_FCF_ADDR_SHORT           0x0002
 /* Auxiliary Security Header */
 #define IEEE802154_AUX_SEC_LEVEL_MASK       0x07  /* Security Level */
 #define IEEE802154_AUX_KEY_ID_MODE_MASK     0x18  /* Key Identifier Mode */
+#define IEEE802154_AUX_KEY_ID_MODE_SHIFT    3
 #define IEEE802154_AUX_KEY_RESERVED_MASK    0xE0  /* Reserved */
 
 typedef enum {
@@ -150,6 +156,14 @@ typedef enum {
     KEY_ID_MODE_KEY_EXPLICIT_8 = 0x03
 } ieee802154_key_id_mode;
 
+/* IEEE 802.15.4 cipher block size. */
+#define IEEE802154_CIPHER_SIZE              16
+
+/* Macro to compute the MIC length. */
+#define IEEE802154_MIC_LENGTH(_level_) ((0x2 << ((_level_) & 0x3)) & ~0x3)
+/* Macro to check for payload encryption. */
+#define IEEE802154_IS_ENCRYPTED(_level_) ((_level_) & 0x4)
+
 /*  Structure containing information regarding all necessary packet feilds. */
 typedef struct {
     /* Frame control field. */
@@ -175,6 +189,19 @@ typedef struct {
         guint16 addr16;
         guint64 addr64;
     } src;
+
+    /* Security Info. */
+    ieee802154_security_level   security_level;
+    ieee802154_key_id_mode      key_id_mode;
+    guint32     frame_counter;
+    union {
+        guint32 addr32;
+        guint64 addr64;
+    } key_source;
+    guint8      key_index;
+
+    /* Command ID (only if frame_type == 0x3) */
+    guint8      command_id;
 } ieee802154_packet;