Clean up the descriptions of reassembly preferences.
[obnox/wireshark/wip.git] / packet-ieee80211.c
index 30e0fe102deb6432c945f8bd56f8e803c0bf0b55..28ec7b8f440fa6d840ff7e73df87b90b7e8f21af 100644 (file)
@@ -3,10 +3,10 @@
  * Copyright 2000, Axis Communications AB 
  * Inquiries/bugreports should be sent to Johan.Jorgensen@axis.com
  *
- * $Id: packet-ieee80211.c,v 1.5 2000/11/30 03:19:27 guy Exp $
+ * $Id: packet-ieee80211.c,v 1.59 2002/04/22 08:14:12 guy Exp $
  *
  * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@unicom.net>
+ * By Gerald Combs <gerald@ethereal.com>
  * Copyright 1998 Gerald Combs
  *
  * Copied from README.developer
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Credits:
+ * 
+ * The following people helped me by pointing out bugs etc. Thank you!
+ *
+ * Marco Molteni
+ * Lena-Marie Nilsson     
+ * Magnus Hultman-Persson
  */
 
 #ifdef HAVE_CONFIG_H
 
 #include <string.h>
 #include <glib.h>
-#include "bitswap.h"
-#include "proto.h"
-#include "etypes.h"
-#include "packet.h"
+#include <epan/bitswap.h>
+#include <epan/proto.h>
+#include <epan/packet.h>
+#include <epan/resolv.h>
+#include "prefs.h"
+#include "reassemble.h"
+#include "packet-ipx.h"
 #include "packet-llc.h"
 #include "packet-ieee80211.h"
+#include "etypes.h"
+
+/* Defragment fragmented 802.11 datagrams */
+static gboolean wlan_defragment = TRUE;
+
+/* Tables for reassembly of fragments. */
+static GHashTable *wlan_fragment_table = NULL;
+static GHashTable *wlan_reassembled_table = NULL;
 
 /* ************************************************************************* */
 /*                          Miscellaneous Constants                          */
 /* ************************************************************************* */
-#define SHORT_STR 128
-#define MGT_FRAME_LEN 24
+#define SHORT_STR 256
 
 /* ************************************************************************* */
 /*  Define some very useful macros that are used to analyze frame types etc. */
 /* ************************************************************************* */
 #define COMPOSE_FRAME_TYPE(x) (((x & 0x0C)<< 2)+((x & 0xF0) >> 4))     /* Create key to (sub)type */
-#define COOK_PROT_VERSION(x)  ((x & 0x3))
-#define COOK_FRAME_TYPE(x)    ((x & 0xC) >> 2)
-#define COOK_FRAME_SUBTYPE(x) ((x & 0xF0) >> 4)
-#define COOK_ADDR_SELECTOR(x) (((x & 0x200) >> 8) + ((x & 0x100) >> 8))
-
-#define COOK_FRAGMENT_NUMBER(x) (x & 0x000F)
-#define COOK_SEQUENCE_NUMBER(x) ((x & 0xFFF0) >> 4)
-#define COOK_FLAGS(x)           ((x & 0xFF00) >> 8)
-#define COOK_DS_STATUS(x)       (x & 0x3)
-#define COL_SHOW_INFO(fd,info) if (check_col(fd,COL_INFO)) \
-col_add_str(fd,COL_INFO,info);
-
-#define IS_TO_DS(x)            ((x & 0x100) >> 8)
-#define IS_FROM_DS(x)          ((x & 0x200) >> 9)
-#define HAVE_FRAGMENTS(x)      ((x & 0x400) >> 10)
-#define IS_RETRY(x)            ((x & 0x800) >> 11)
-#define POWER_MGT_STATUS(x)    ((x & 0x1000))
-#define HAS_MORE_DATA(x)       ((x & 0x2000))
-#define IS_WEP(x)              ((x & 0x4000))
-#define IS_STRICTLY_ORDERED(x) ((x & 0x8000))
-
-#define MGT_RESERVED_RANGE(x) (((x>=0x06)&&(x<=0x07))||((x>=0x0D)&&(x<=0x0F)))
+#define COOK_PROT_VERSION(x)  ((x) & 0x3)
+#define COOK_FRAME_TYPE(x)    (((x) & 0xC) >> 2)
+#define COOK_FRAME_SUBTYPE(x) (((x) & 0xF0) >> 4)
+#define COOK_ADDR_SELECTOR(x) ((x) & 0x300)
+#define COOK_ASSOC_ID(x)      ((x) & 0x3FFF)
+#define COOK_FRAGMENT_NUMBER(x) ((x) & 0x000F)
+#define COOK_SEQUENCE_NUMBER(x) (((x) & 0xFFF0) >> 4)
+#define COOK_FLAGS(x)           (((x) & 0xFF00) >> 8)
+#define COOK_DS_STATUS(x)       ((x) & 0x3)
+#define COOK_WEP_KEY(x)       (((x) & 0xC0) >> 6)
+
+#define FLAG_TO_DS             0x01
+#define FLAG_FROM_DS           0x02
+#define FLAG_MORE_FRAGMENTS    0x04
+#define FLAG_RETRY             0x08
+#define FLAG_POWER_MGT         0x10
+#define FLAG_MORE_DATA         0x20
+#define FLAG_WEP               0x40
+#define FLAG_ORDER             0x80
+
+#define IS_TO_DS(x)            ((x) & FLAG_TO_DS)
+#define IS_FROM_DS(x)          ((x) & FLAG_FROM_DS)
+#define HAVE_FRAGMENTS(x)      ((x) & FLAG_MORE_FRAGMENTS)
+#define IS_RETRY(x)            ((x) & FLAG_RETRY)
+#define POWER_MGT_STATUS(x)    ((x) & FLAG_POWER_MGT)
+#define HAS_MORE_DATA(x)       ((x) & FLAG_MORE_DATA)
+#define IS_WEP(x)              ((x) & FLAG_WEP)
+#define IS_STRICTLY_ORDERED(x) ((x) & FLAG_ORDER)
+
+#define MGT_RESERVED_RANGE(x)  (((x>=0x06)&&(x<=0x07))||((x>=0x0D)&&(x<=0x0F)))
 #define CTRL_RESERVED_RANGE(x) ((x>=0x10)&&(x<=0x19))
 #define DATA_RESERVED_RANGE(x) ((x>=0x28)&&(x<=0x2f))
 #define SPEC_RESERVED_RANGE(x) ((x>=0x30)&&(x<=0x3f))
@@ -106,7 +132,7 @@ col_add_str(fd,COL_INFO,info);
 #define DATA_SHORT_HDR_LEN     24
 #define DATA_LONG_HDR_LEN      30
 #define MGT_FRAME_HDR_LEN      24      /* Length of Managment frame-headers */
-#define CTLR
+
 #define MGT_ASSOC_REQ        0x00      /* Management - association request        */
 #define MGT_ASSOC_RESP       0x01      /* Management - association response       */
 #define MGT_REASSOC_REQ      0x02      /* Management - reassociation request      */
@@ -129,22 +155,23 @@ col_add_str(fd,COL_INFO,info);
 #define DATA                 0x20      /* Data - Data                             */
 #define DATA_CF_ACK          0x21      /* Data - Data + CF acknowledge            */
 #define DATA_CF_POLL         0x22      /* Data - Data + CF poll                   */
-#define DATA_CF_ACK_POLL     0x23      /* Data - Data + CF acknowledge & CF poll  */
+#define DATA_CF_ACK_POLL     0x23      /* Data - Data + CF acknowledge + CF poll  */
 #define DATA_NULL_FUNCTION   0x24      /* Data - Null function (no data)          */
 #define DATA_CF_ACK_NOD      0x25      /* Data - CF ack (no data)                 */
-#define DATA_CF_ACK_POLL_NOD 0x26      /* Data - CF ack + CF poll (no data)       */
+#define DATA_CF_POLL_NOD     0x26       /* Data - Data + CF poll (No data)         */
+#define DATA_CF_ACK_POLL_NOD 0x27      /* Data - CF ack + CF poll (no data)       */
 
-#define DATA_ADDR_T1         0x00
-#define DATA_ADDR_T2         0x01
-#define DATA_ADDR_T3         0x02
-#define DATA_ADDR_T4         0x03
+#define DATA_ADDR_T1         0
+#define DATA_ADDR_T2         (FLAG_FROM_DS << 8)
+#define DATA_ADDR_T3         (FLAG_TO_DS << 8)
+#define DATA_ADDR_T4         ((FLAG_TO_DS|FLAG_FROM_DS) << 8)
 
 
 /* ************************************************************************* */
 /*          Macros used to extract information about fixed fields            */
 /* ************************************************************************* */
-#define ESS_SET(x) ((x & 0x0001))
-#define IBSS_SET(x) ((x & 0x0002))
+#define ESS_SET(x) ((x) & 0x0001)
+#define IBSS_SET(x) ((x) & 0x0002)
 
 
 
@@ -174,14 +201,47 @@ col_add_str(fd,COL_INFO,info);
 #define TAG_IBSS_PARAMETER 0x06
 #define TAG_CHALLENGE_TEXT 0x10
 
-
 /* ************************************************************************* */
-/*                Various constants used in this module                      */
+/*                         Frame types, and their names                      */
 /* ************************************************************************* */
-static const char *capture_proto_name = "IEEE 802.11";
-
+static const value_string frame_type_subtype_vals[] = {
+       {MGT_ASSOC_REQ,        "Association Request"},
+       {MGT_ASSOC_RESP,       "Association Response"},
+       {MGT_REASSOC_REQ,      "Reassociation Request"},
+       {MGT_REASSOC_RESP,     "Reassociation Response"},
+       {MGT_PROBE_REQ,        "Probe Request"},
+       {MGT_PROBE_RESP,       "Probe Response"},
+       {MGT_BEACON,           "Beacon frame"},
+       {MGT_ATIM,             "ATIM"},
+       {MGT_DISASS,           "Dissassociate"},
+       {MGT_AUTHENTICATION,   "Authentication"},
+       {MGT_DEAUTHENTICATION, "Deauthentication"},
+       {CTRL_PS_POLL,         "Power-Save poll"},
+       {CTRL_RTS,             "Request-to-send"},
+       {CTRL_CTS,             "Clear-to-send"},
+       {CTRL_ACKNOWLEDGEMENT, "Acknowledgement"},
+       {CTRL_CFP_END,         "CF-End (Control-frame)"},
+       {CTRL_CFP_ENDACK,      "CF-End + CF-Ack (Control-frame)"},
+       {DATA,                 "Data"},
+       {DATA_CF_ACK,          "Data + CF-Acknowledgement"},
+       {DATA_CF_POLL,         "Data + CF-Poll"},
+       {DATA_CF_ACK_POLL,     "Data + CF-Acknowledgement/Poll"},
+       {DATA_NULL_FUNCTION,   "Null function (No data)"},
+       {DATA_CF_ACK_NOD,      "Data + Acknowledgement (No data)"},
+       {DATA_CF_POLL_NOD,     "Data + CF-Poll (No data)"},
+       {DATA_CF_ACK_POLL_NOD, "Data + CF-Acknowledgement/Poll (No data)"},
+       {0,                    NULL}
+};
 
 static int proto_wlan = -1;
+
+/* ************************************************************************* */
+/*                Header field info values for radio information             */
+/* ************************************************************************* */
+static int hf_data_rate = -1;
+static int hf_channel = -1;
+static int hf_signal_strength = -1;
+
 /* ************************************************************************* */
 /*                Header field info values for FC-field                      */
 /* ************************************************************************* */
@@ -189,6 +249,7 @@ static int hf_fc_field = -1;
 static int hf_fc_proto_version = -1;
 static int hf_fc_frame_type = -1;
 static int hf_fc_frame_subtype = -1;
+static int hf_fc_frame_type_subtype = -1;
 
 static int hf_fc_flags = -1;
 static int hf_fc_to_ds = -1;
@@ -207,7 +268,7 @@ static int hf_fc_order = -1;
 /*                   Header values for Duration/ID field                     */
 /* ************************************************************************* */
 static int hf_did_duration = -1;
-
+static int hf_assoc_id = -1;
 
 
 /* ************************************************************************* */
@@ -219,6 +280,7 @@ static int hf_addr_ra = -1; /* Receiver address subfield */
 static int hf_addr_ta = -1;    /* Transmitter address subfield */
 static int hf_addr_bssid = -1; /* address is bssid */
 
+static int hf_addr = -1;       /* Source or destination address subfield */
 
 
 /* ************************************************************************* */
@@ -232,29 +294,44 @@ static int hf_seq_number = -1;
 /* ************************************************************************* */
 static int hf_fcs = -1;
 
+/* ************************************************************************* */
+/*                   Header values for reassembly                            */
+/* ************************************************************************* */
+static int hf_fragments = -1;
+static int hf_fragment = -1;
+static int hf_fragment_overlap = -1;
+static int hf_fragment_overlap_conflict = -1;
+static int hf_fragment_multiple_tails = -1;
+static int hf_fragment_too_long_fragment = -1;
+static int hf_fragment_error = -1;
+
 
+static int proto_wlan_mgt = -1;
 /* ************************************************************************* */
 /*                      Fixed fields found in mgt frames                     */
 /* ************************************************************************* */
-static int ff_auth_alg = -1;   /* Authentication algorithm field          */
-static int ff_auth_seq = -1;   /* Authentication transaction sequence     */
-static int ff_current_ap = -1; /* Current AP MAC address                  */
-static int ff_listen_ival = -1;        /* Listen interval fixed field             */
-static int ff_timestamp = -1;  /* 64 bit timestamp                        */
-static int ff_beacon_interval = -1;    /* 16 bit Beacon interval                  */
-static int ff_assoc_id = -1;   /* 16 bit AID field                        */
-static int ff_reason = -1;     /* 16 bit reason code                      */
-static int ff_status_code = -1;        /* Status code                             */
+static int ff_auth_alg = -1;   /* Authentication algorithm field            */
+static int ff_auth_seq = -1;   /* Authentication transaction sequence       */
+static int ff_current_ap = -1; /* Current AP MAC address                    */
+static int ff_listen_ival = -1;        /* Listen interval fixed field               */
+static int ff_timestamp = -1;  /* 64 bit timestamp                          */
+static int ff_beacon_interval = -1;    /* 16 bit Beacon interval            */
+static int ff_assoc_id = -1;   /* 16 bit AID field                          */
+static int ff_reason = -1;     /* 16 bit reason code                        */
+static int ff_status_code = -1;        /* Status code                               */
 
 /* ************************************************************************* */
 /*            Flags found in the capability field (fixed field)              */
 /* ************************************************************************* */
 static int ff_capture = -1;
-static int ff_cf_sta_poll = -1;        /* CF pollable status for a STA            */
+static int ff_cf_sta_poll = -1; /* CF pollable status for a STA            */
 static int ff_cf_ap_poll = -1; /* CF pollable status for an AP            */
 static int ff_cf_ess = -1;
 static int ff_cf_ibss = -1;
 static int ff_cf_privacy = -1;
+static int ff_cf_preamble = -1;
+static int ff_cf_pbcc = -1;
+static int ff_cf_agility = -1;
 
 /* ************************************************************************* */
 /*                       Tagged value format fields                          */
@@ -267,6 +344,9 @@ static int tag_interpretation = -1;
 
 static int hf_fixed_parameters = -1;   /* Protocol payload for management frames */
 static int hf_tagged_parameters = -1;  /* Fixed payload item */
+static int hf_wep_iv = -1;
+static int hf_wep_key = -1;
+static int hf_wep_crc = -1;
 
 /* ************************************************************************* */
 /*                               Protocol trees                              */
@@ -275,56 +355,107 @@ static gint ett_80211 = -1;
 static gint ett_proto_flags = -1;
 static gint ett_cap_tree = -1;
 static gint ett_fc_tree = -1;
+static gint ett_fragments = -1;
+static gint ett_fragment = -1;
+
+static gint ett_80211_mgt = -1;
 static gint ett_fixed_parameters = -1;
 static gint ett_tagged_parameters = -1;
+static gint ett_wep_parameters = -1;
+
+static dissector_handle_t llc_handle;
+static dissector_handle_t ipx_handle;
+static dissector_handle_t data_handle;
+
 /* ************************************************************************* */
-/*                                                                           */
+/*            Return the length of the current header (in bytes)             */
 /* ************************************************************************* */
-int
-find_header_length (const u_char * pd, int offset)
+static int
+find_header_length (guint16 fcf)
 {
-  guint16 frame_control;
+  switch (COOK_FRAME_TYPE (fcf)) {
+
+  case MGT_FRAME:
+    return MGT_FRAME_HDR_LEN;
+
+  case CONTROL_FRAME:
+    switch (COMPOSE_FRAME_TYPE (fcf)) {
 
-  frame_control = pntohs (pd);
-  return ((IS_FROM_DS (frame_control))
-         && (IS_TO_DS (frame_control))) ? 30 : 24;
+    case CTRL_CTS:
+    case CTRL_ACKNOWLEDGEMENT:
+      return 10;
+
+    case CTRL_RTS:
+    case CTRL_PS_POLL:
+    case CTRL_CFP_END:
+    case CTRL_CFP_ENDACK:
+      return 16;
+    }
+    return 4;  /* XXX */
+
+  case DATA_FRAME:
+    return (COOK_ADDR_SELECTOR(fcf) == DATA_ADDR_T4) ? DATA_LONG_HDR_LEN :
+                                                      DATA_SHORT_HDR_LEN;
+  default:
+    return 4;  /* XXX */
+  }
 }
 
 
 /* ************************************************************************* */
 /*          This is the capture function used to update packet counts        */
 /* ************************************************************************* */
-void
-capture_ieee80211 (const u_char * pd, int offset, packet_counts * ld)
+static void
+capture_ieee80211_common (const u_char * pd, int offset, int len,
+                         packet_counts * ld, gboolean fixed_length_header)
 {
   guint16 fcf, hdr_length;
 
-  fcf = pntohs (*((guint *) pd));
+  if (!BYTES_ARE_IN_FRAME(offset, len, 2)) {
+    ld->other++;
+    return;
+  }
 
+  fcf = pletohs (&pd[0]);
 
-  hdr_length = MGT_FRAME_HDR_LEN;      /* Set the header length of the frame */
+  if (IS_WEP(COOK_FLAGS(fcf)))
+    {
+      ld->other++;
+      return;
+    }
 
   switch (COMPOSE_FRAME_TYPE (fcf))
     {
 
     case DATA:                 /* We got a data frame */
-      hdr_length = find_header_length (pd, offset);
-      capture_llc (pd, offset + hdr_length, ld);
-      break;
-
     case DATA_CF_ACK:          /* Data with ACK */
-      hdr_length = find_header_length (pd, offset);
-      capture_llc (pd, offset + hdr_length, ld);
-      break;
-
     case DATA_CF_POLL:
-      hdr_length = find_header_length (pd, offset);
-      capture_llc (pd, offset + hdr_length, ld);
-      break;
-
     case DATA_CF_ACK_POLL:
-      hdr_length = find_header_length (pd, offset);
-      capture_llc (pd, offset + hdr_length, ld);
+      if (fixed_length_header)
+        hdr_length = DATA_LONG_HDR_LEN;
+      else
+        hdr_length = find_header_length (fcf);
+      /* I guess some bridges take Netware Ethernet_802_3 frames,
+         which are 802.3 frames (with a length field rather than
+         a type field, but with no 802.2 header in the payload),
+         and just stick the payload into an 802.11 frame.  I've seen
+         captures that show frames of that sort.
+
+         This means we have to do the same check for Netware 802.3 -
+         or, if you will, "Netware 802.11" - that we do in the
+         Ethernet dissector, i.e. checking for 0xffff as the first
+         four bytes of the payload and, if we find it, treating it
+         as an IPX frame. */
+      if (!BYTES_ARE_IN_FRAME(offset+hdr_length, len, 2)) {
+        ld->other++;
+        return;
+      }
+      if (pd[offset+hdr_length] == 0xff && pd[offset+hdr_length+1] == 0xff) {
+        capture_ipx (pd, offset + hdr_length, len, ld);
+      }
+      else {
+        capture_llc (pd, offset + hdr_length, len, ld);
+      }
       break;
 
     default:
@@ -333,6 +464,24 @@ capture_ieee80211 (const u_char * pd, int offset, packet_counts * ld)
     }
 }
 
+/*
+ * Handle 802.11 with a variable-length link-layer header.
+ */
+void
+capture_ieee80211 (const u_char * pd, int offset, int len, packet_counts * ld)
+{
+  capture_ieee80211_common (pd, offset, len, ld, FALSE);
+}
+
+/*
+ * Handle 802.11 with a fixed-length link-layer header (padded to the
+ * maximum length).
+ */
+void
+capture_ieee80211_fixed (const u_char * pd, int offset, int len, packet_counts * ld)
+{
+  capture_ieee80211_common (pd, offset, len, ld, TRUE);
+}
 
 
 /* ************************************************************************* */
@@ -371,6 +520,28 @@ get_tagged_parameter_tree (proto_tree * tree, tvbuff_t *tvb, int start, int size
 }
 
 
+/* ************************************************************************* */
+/*            Add the subtree used to store WEP parameters                   */
+/* ************************************************************************* */
+static void
+get_wep_parameter_tree (proto_tree * tree, tvbuff_t *tvb, int start, int size)
+{
+  proto_item *wep_fields;
+  proto_tree *wep_tree;
+  int crc_offset = size - 4;
+
+  wep_fields = proto_tree_add_text(tree, tvb, start, 4, "WEP parameters");
+
+  wep_tree = proto_item_add_subtree (wep_fields, ett_wep_parameters);
+  proto_tree_add_item (wep_tree, hf_wep_iv, tvb, start, 3, TRUE);
+
+  proto_tree_add_uint (wep_tree, hf_wep_key, tvb, start + 3, 1,
+                      COOK_WEP_KEY (tvb_get_guint8 (tvb, start + 3)));
+
+  if (tvb_bytes_exist(tvb, start + crc_offset, 4))
+    proto_tree_add_uint (wep_tree, hf_wep_crc, tvb, start + crc_offset, 4,
+                        tvb_get_ntohl (tvb, start + crc_offset));
+}
 
 /* ************************************************************************* */
 /*              Dissect and add fixed mgmt fields to protocol tree           */
@@ -378,11 +549,12 @@ get_tagged_parameter_tree (proto_tree * tree, tvbuff_t *tvb, int start, int size
 static void
 add_fixed_field (proto_tree * tree, tvbuff_t * tvb, int offset, int lfcode)
 {
-  guint8 *dataptr;
+  const guint8 *dataptr;
   char out_buff[SHORT_STR];
-  guint16 *temp16;
+  guint16 capability;
   proto_item *cap_item;
   static proto_tree *cap_tree;
+  double temp_double;
 
   switch (lfcode)
     {
@@ -390,125 +562,83 @@ add_fixed_field (proto_tree * tree, tvbuff_t * tvb, int offset, int lfcode)
       dataptr = tvb_get_ptr (tvb, offset, 8);
       memset (out_buff, 0, SHORT_STR);
       snprintf (out_buff, SHORT_STR, "0x%02X%02X%02X%02X%02X%02X%02X%02X",
-               BIT_SWAP (dataptr[7]),
-               BIT_SWAP (dataptr[6]),
-               BIT_SWAP (dataptr[5]),
-               BIT_SWAP (dataptr[4]),
-               BIT_SWAP (dataptr[3]),
-               BIT_SWAP (dataptr[2]),
-               BIT_SWAP (dataptr[1]),
-               BIT_SWAP (dataptr[0]));
+               dataptr[7],
+               dataptr[6],
+               dataptr[5],
+               dataptr[4],
+               dataptr[3],
+               dataptr[2],
+               dataptr[1],
+               dataptr[0]);
 
       proto_tree_add_string (tree, ff_timestamp, tvb, offset, 8, out_buff);
       break;
 
-
     case FIELD_BEACON_INTERVAL:
-      dataptr = tvb_get_ptr (tvb, offset, 2);
-      out_buff[0] = BIT_SWAP (dataptr[1]);
-      out_buff[1] = BIT_SWAP (dataptr[0]);
-      temp16 = (guint16 *) out_buff;
-      proto_tree_add_uint (tree, ff_beacon_interval, tvb, offset, 2,
-                          pntohs (temp16));
+      temp_double = (double) tvb_get_letohs (tvb, offset);
+      temp_double = temp_double * 1024 / 1000000;
+      proto_tree_add_double_format (tree, ff_beacon_interval, tvb, offset, 2,
+                                   temp_double,"Beacon Interval: %f [Seconds]",
+                                   temp_double);
       break;
 
 
     case FIELD_CAP_INFO:
-      dataptr = tvb_get_ptr (tvb, offset, 2);
-      out_buff[0] = BIT_SWAP (dataptr[1]);
-      out_buff[0] = BIT_SWAP (dataptr[0]);
-      temp16 = (guint16 *) out_buff;
+      capability = tvb_get_letohs (tvb, offset);
 
       cap_item = proto_tree_add_uint_format (tree, ff_capture, 
                                             tvb, offset, 2,
-                                            pntohs (temp16),
-                                            "Capability Information: %04X",
-                                            pntohs (temp16));
+                                            capability,
+                                            "Capability Information: 0x%04X",
+                                            capability);
       cap_tree = proto_item_add_subtree (cap_item, ett_cap_tree);
       proto_tree_add_boolean (cap_tree, ff_cf_ess, tvb, offset, 1,
-                             pntohs (temp16));
+                             capability);
       proto_tree_add_boolean (cap_tree, ff_cf_ibss, tvb, offset, 1,
-                             pntohs (temp16));
+                             capability);
       proto_tree_add_boolean (cap_tree, ff_cf_privacy, tvb, offset, 1,
-                             pntohs (temp16));
-      if (ESS_SET (pntohs (temp16)) != 0)      /* This is an AP */
+                             capability);
+      proto_tree_add_boolean (cap_tree, ff_cf_preamble, tvb, offset, 1,
+                             capability);
+      proto_tree_add_boolean (cap_tree, ff_cf_pbcc, tvb, offset, 1,
+                             capability);
+      proto_tree_add_boolean (cap_tree, ff_cf_agility, tvb, offset, 1,
+                             capability);
+      if (ESS_SET (capability) != 0)   /* This is an AP */
        proto_tree_add_uint (cap_tree, ff_cf_ap_poll, tvb, offset, 2,
-                            ((pntohs (temp16) & 0xC) >> 2));
+                            ((capability & 0xC) >> 2));
 
       else                     /* This is a STA */
        proto_tree_add_uint (cap_tree, ff_cf_sta_poll, tvb, offset, 2,
-                            ((pntohs (temp16) & 0xC) >> 2));
+                            ((capability & 0xC) >> 2));
       break;
 
-
     case FIELD_AUTH_ALG:
-      dataptr = tvb_get_ptr (tvb, offset, 2);
-      out_buff[0] = BIT_SWAP (dataptr[1]);
-      out_buff[1] = BIT_SWAP (dataptr[0]);
-      temp16 = (guint16 *) out_buff;
-      proto_tree_add_uint (tree, ff_auth_alg, tvb, offset, 2,
-                          pntohs (temp16));
+      proto_tree_add_item (tree, ff_auth_alg, tvb, offset, 2, TRUE);
       break;
 
-
     case FIELD_AUTH_TRANS_SEQ:
-      dataptr = tvb_get_ptr (tvb, offset, 2);
-      out_buff[0] = BIT_SWAP (dataptr[1]);
-      out_buff[1] = BIT_SWAP (dataptr[0]);
-      temp16 = (guint16 *) out_buff;
-      proto_tree_add_uint (tree, ff_auth_seq, tvb, offset, 2,
-                          pntohs (temp16));
+      proto_tree_add_item (tree, ff_auth_seq, tvb, offset, 2, TRUE);
       break;
 
-
     case FIELD_CURRENT_AP_ADDR:
-      dataptr = tvb_get_ptr (tvb, offset, 6);
-      memset (out_buff, 0, SHORT_STR);
-      out_buff[0] = BIT_SWAP (dataptr[5]);
-      out_buff[1] = BIT_SWAP (dataptr[4]);
-      out_buff[2] = BIT_SWAP (dataptr[3]);
-      out_buff[3] = BIT_SWAP (dataptr[2]);
-      out_buff[4] = BIT_SWAP (dataptr[1]);
-      out_buff[5] = BIT_SWAP (dataptr[0]);
-
-      proto_tree_add_string (tree, ff_current_ap, tvb, offset, 6, out_buff);
+      proto_tree_add_item (tree, ff_current_ap, tvb, offset, 6, FALSE);
       break;
 
-
     case FIELD_LISTEN_IVAL:
-      dataptr = tvb_get_ptr (tvb, offset, 2);
-      out_buff[0] = BIT_SWAP (dataptr[1]);
-      out_buff[1] = BIT_SWAP (dataptr[0]);
-      temp16 = (guint16 *) out_buff;
-      proto_tree_add_uint (tree, ff_listen_ival, tvb, offset, 2,
-                          pntohs (temp16));
+      proto_tree_add_item (tree, ff_listen_ival, tvb, offset, 2, TRUE);
       break;
 
-
     case FIELD_REASON_CODE:
-      dataptr = tvb_get_ptr (tvb, offset, 2);
-      out_buff[0] = BIT_SWAP (dataptr[1]);
-      out_buff[1] = BIT_SWAP (dataptr[0]);
-      temp16 = (guint16 *) out_buff;
-      proto_tree_add_uint (tree, ff_reason, tvb, offset, 2, pntohs (temp16));
+      proto_tree_add_item (tree, ff_reason, tvb, offset, 2, TRUE);
       break;
 
-
     case FIELD_ASSOC_ID:
-      dataptr = tvb_get_ptr (tvb, offset, 2);
-      out_buff[0] = BIT_SWAP (dataptr[1]);
-      out_buff[1] = BIT_SWAP (dataptr[0]);
-      temp16 = (guint16 *) out_buff;
-      proto_tree_add_uint (tree, ff_assoc_id, tvb, offset, 2, pntohs (temp16));
+      proto_tree_add_item (tree, ff_assoc_id, tvb, offset, 2, TRUE);
       break;
 
     case FIELD_STATUS_CODE:
-      dataptr = tvb_get_ptr (tvb, offset, 2);
-      out_buff[0] = BIT_SWAP (dataptr[1]);
-      out_buff[1] = BIT_SWAP (dataptr[0]);
-      temp16 = (guint16 *) out_buff;
-      proto_tree_add_uint (tree, ff_status_code, tvb, offset, 2,
-                          pntohs (temp16));
+      proto_tree_add_item (tree, ff_status_code, tvb, offset, 2, TRUE);
       break;
     }
 }
@@ -520,16 +650,15 @@ add_fixed_field (proto_tree * tree, tvbuff_t * tvb, int offset, int lfcode)
 static int
 add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
 {
-  guint8 *tag_info_ptr;
-  guint8 *tag_data_ptr;
+  const guint8 *tag_data_ptr;
   guint32 tag_no, tag_len;
-  int i, n;
+  unsigned int i;
+  int n, ret;
   char out_buff[SHORT_STR];
 
 
-  tag_info_ptr = tvb_get_ptr (tvb, offset, 2);
-  tag_no = tag_info_ptr[0];
-  tag_len = tag_info_ptr[1];
+  tag_no = tvb_get_guint8(tvb, offset);
+  tag_len = tvb_get_guint8(tvb, offset + 1);
 
   tag_data_ptr = tvb_get_ptr (tvb, offset + 2, tag_len);
 
@@ -537,13 +666,13 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
   if ((tag_no >= 17) && (tag_no <= 31))
     {                          /* Reserved for challenge text */
       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
-                                 "Tag Number: %d (Reserved for challenge text)",
+                                 "Tag Number: %u (Reserved for challenge text)",
                                  tag_no);
 
       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
                             tag_len, "Not interpreted");
-      return (int) tag_len;
+      return (int) tag_len + 2;
     }
 
   /* Next See if tag is reserved - if true, skip it! */
@@ -551,24 +680,24 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
       || ((tag_no >= 32) && (tag_no <= 255)))
     {
       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
-                                 "Tag Number: %d (Reserved tag number)",
+                                 "Tag Number: %u (Reserved tag number)",
                                  tag_no);
 
       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
 
       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
                             tag_len, "Not interpreted");
-      return (int) tag_len;
+      return (int) tag_len + 2;
     }
 
 
-  switch (tag_info_ptr[0])
+  switch (tag_no)
     {
 
 
     case TAG_SSID:
       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
-                                 "Tag Number: %d (SSID parameter set)",
+                                 "Tag Number: %u (SSID parameter set)",
                                  tag_no);
 
       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
@@ -586,7 +715,7 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
 
     case TAG_SUPP_RATES:
       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
-                                 "Tag Number: %d (Supported Rates)", tag_no);
+                                 "Tag Number: %u (Supported Rates)", tag_no);
 
       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
 
@@ -594,22 +723,20 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
       strcpy (out_buff, "Supported rates: ");
       n = strlen (out_buff);
 
-      for (i = 0; i < tag_len; i++)
+      for (i = 0; i < tag_len && n < SHORT_STR; i++)
        {
-
-         if (tag_data_ptr[i] >= 128)
-           {
-             tag_data_ptr[i] -= 128;
-             n += snprintf (out_buff + n, SHORT_STR - n, "%2.1f ", (float)
-                            (((float) tag_data_ptr[i]) * 0.5));
+           ret = snprintf (out_buff + n, SHORT_STR - n, "%2.1f%s ",
+                          (tag_data_ptr[i] & 0x7F) * 0.5,
+                          (tag_data_ptr[i] & 0x80) ? "(B)" : "");
+           if (ret == -1) {
+             /* Some versions of snprintf return -1 if they'd truncate
+                the output. */
+             break;
            }
-
-         else
-           n += snprintf (out_buff + n, SHORT_STR - n, "%2.1f ", (float)
-                          (((float) tag_data_ptr[i]) * 0.5));
-
+           n += ret;
        }
-      snprintf (out_buff + n, SHORT_STR - n, "[Mbit/sec]");
+      if (n < SHORT_STR)
+       snprintf (out_buff + n, SHORT_STR - n, "[Mbit/sec]");
 
       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
                             tag_len, out_buff);
@@ -619,7 +746,7 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
 
     case TAG_FH_PARAMETER:
       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
-                                 "Tag Number: %d (FH Parameter set)",
+                                 "Tag Number: %u (FH Parameter set)",
                                  tag_no);
 
       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
@@ -627,7 +754,7 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
 
       snprintf (out_buff, SHORT_STR,
                "Dwell time 0x%04X, Hop Set %2d, Hop Pattern %2d, "
-               "Hop Index %2d", pntohs (tag_data_ptr), tag_data_ptr[2],
+               "Hop Index %2d", pletohs (tag_data_ptr), tag_data_ptr[2],
                tag_data_ptr[3], tag_data_ptr[4]);
 
       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
@@ -638,13 +765,13 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
 
     case TAG_DS_PARAMETER:
       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
-                                 "Tag Number: %d (DS Parameter set)",
+                                 "Tag Number: %u (DS Parameter set)",
                                  tag_no);
 
       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
       memset (out_buff, 0, SHORT_STR);
 
-      snprintf (out_buff, SHORT_STR, "Current Channel: %d", tag_data_ptr[0]);
+      snprintf (out_buff, SHORT_STR, "Current Channel: %u", tag_data_ptr[0]);
       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
                             tag_len, out_buff);
       break;
@@ -652,16 +779,16 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
 
     case TAG_CF_PARAMETER:
       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
-                                 "Tag Number: %d (CF Parameter set)",
+                                 "Tag Number: %u (CF Parameter set)",
                                  tag_no);
 
       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
       memset (out_buff, 0, SHORT_STR);
 
       snprintf (out_buff, SHORT_STR,
-               "CFP count %d, CFP period %d, CFP max duration %d, "
-               "CFP Remaining %d", tag_data_ptr[0], tag_data_ptr[1],
-               pntohs (tag_data_ptr + 2), pntohs (tag_data_ptr + 4));
+               "CFP count %u, CFP period %u, CFP max duration %u, "
+               "CFP Remaining %u", tag_data_ptr[0], tag_data_ptr[1],
+               pletohs (tag_data_ptr + 2), pletohs (tag_data_ptr + 4));
 
       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
                             tag_len, out_buff);
@@ -670,13 +797,13 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
 
     case TAG_TIM:
       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
-                                 "Tag Number: %d (CF Parameter set)",
+                                 "Tag Number: %u ((TIM) Traffic Indication Map)",
                                  tag_no);
 
       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
       memset (out_buff, 0, SHORT_STR);
       snprintf (out_buff, SHORT_STR,
-               "DTIM count %d, DTIM period %d, Bitmap control 0x%X, "
+               "DTIM count %u, DTIM period %u, Bitmap control 0x%X, "
                "(Bitmap suppressed)", tag_data_ptr[0], tag_data_ptr[1],
                tag_data_ptr[2]);
       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
@@ -687,13 +814,13 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
 
     case TAG_IBSS_PARAMETER:
       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
-                                 "Tag Number: %d (IBSS Parameter set)",
+                                 "Tag Number: %u (IBSS Parameter set)",
                                  tag_no);
 
       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
       memset (out_buff, 0, SHORT_STR);
       snprintf (out_buff, SHORT_STR, "ATIM window 0x%X",
-               pntohs (tag_data_ptr));
+               pletohs (tag_data_ptr));
 
       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
                             tag_len, out_buff);
@@ -703,13 +830,13 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
 
     case TAG_CHALLENGE_TEXT:
       proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
-                                 "Tag Number: %d (Challenge text)", tag_no);
+                                 "Tag Number: %u (Challenge text)", tag_no);
 
       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
       memset (out_buff, 0, SHORT_STR);
       snprintf (out_buff, SHORT_STR, "Challenge text: %.47s", tag_data_ptr);
-      proto_tree_add_string (tree, tag_interpretation, tvb, offset, tag_len,
-                            out_buff);
+      proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
+                            tag_len, out_buff);
 
       break;
 
@@ -720,698 +847,966 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
   return tag_len + 2;
 }
 
-
-
 /* ************************************************************************* */
-/*                          Dissect 802.11 frame                             */
+/*                     Dissect 802.11 management frame                       */
 /* ************************************************************************* */
-void
-dissect_ieee80211 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
+static void
+dissect_ieee80211_mgt (guint16 fcf, tvbuff_t * tvb, packet_info * pinfo,
+       proto_tree * tree)
 {
-  guint16 fcf, flags;
-  guint8 *src = NULL, *dst = NULL;
-  proto_item *ti;
-  proto_item *flag_item;
-  proto_item *fc_item;
-  static proto_tree *hdr_tree;
-  static proto_tree *flag_tree;
-  static proto_tree *fixed_tree;
-  static proto_tree *tagged_tree;
-  static proto_tree *fc_tree;
-  guint16 cap_len, hdr_len;
-  tvbuff_t *next_tvb;
+  proto_item *ti = NULL;
+  proto_tree *mgt_tree;
+  proto_tree *fixed_tree;
+  proto_tree *tagged_tree;
   guint32 next_idx;
-  guint32 addr_type;
+  guint32 next_len;
+  int tagged_parameter_tree_len;
 
-  cap_len = pinfo->captured_len;
-  fcf = tvb_get_letohs (tvb, 0);
+  CHECK_DISPLAY_AS_X(data_handle,proto_wlan_mgt, tvb, pinfo, tree);
 
-  pinfo->current_proto = capture_proto_name;
-
-  if (check_col (pinfo->fd, COL_PROTOCOL))
-    col_set_str (pinfo->fd, COL_PROTOCOL, "IEEE 802.11");
-
-  /* Add the FC to the current tree */
   if (tree)
     {
-      hdr_len = find_header_length (tvb_get_ptr (tvb, 0, cap_len), 0);
-      ti = proto_tree_add_protocol_format (tree, proto_wlan, tvb, 0, hdr_len,
-                                          "IEEE 802.11 Header");
-      hdr_tree = proto_item_add_subtree (ti, ett_80211);
-
-      fc_item =
-       proto_tree_add_uint_format (hdr_tree, hf_fc_field, tvb, 0, 2,
-                                   tvb_get_letohs (tvb, 0),
-                                   "Frame Control: 0x%04X",
-                                   tvb_get_letohs (tvb, 0));
-
-      fc_tree = proto_item_add_subtree (fc_item, ett_fc_tree);
+      ti = proto_tree_add_item (tree, proto_wlan_mgt, tvb, 0, -1, FALSE);
+      mgt_tree = proto_item_add_subtree (ti, ett_80211_mgt);
 
+      switch (COMPOSE_FRAME_TYPE(fcf))
+       {
 
-      proto_tree_add_uint (fc_tree, hf_fc_proto_version, tvb, 0, 1,
-                          COOK_PROT_VERSION (tvb_get_letohs (tvb, 0)));
-
-      proto_tree_add_uint (fc_tree, hf_fc_frame_type, tvb, 0, 1,
-                          COOK_FRAME_TYPE (tvb_get_letohs (tvb, 0)));
-
-      proto_tree_add_uint (fc_tree, hf_fc_frame_subtype,
-                          tvb, 0, 1,
-                          COOK_FRAME_SUBTYPE (tvb_get_letohs (tvb, 0)));
+       case MGT_ASSOC_REQ:
+         fixed_tree = get_fixed_parameter_tree (mgt_tree, tvb, 0, 4);
+         add_fixed_field (fixed_tree, tvb, 0, FIELD_CAP_INFO);
+         add_fixed_field (fixed_tree, tvb, 2, FIELD_LISTEN_IVAL);
 
-      flags = COOK_FLAGS (tvb_get_letohs (tvb, 0));
+         next_idx = 4; /* Size of fixed fields */
+         tagged_parameter_tree_len =
+             tvb_reported_length_remaining(tvb, next_idx);
+         tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx,
+                                                  tagged_parameter_tree_len);
 
-      flag_item =
-       proto_tree_add_uint_format (fc_tree, hf_fc_flags, tvb, 1, 1,
-                                   flags, "Flags: 0x%X", flags);
+         while (tagged_parameter_tree_len > 0) {
+           if ((next_len=add_tagged_field (tagged_tree, tvb, next_idx))==0)
+             break;
+           next_idx +=next_len;
+           tagged_parameter_tree_len -= next_len;
+         }
+         break;
 
-      flag_tree = proto_item_add_subtree (flag_item, ett_proto_flags);
 
-      proto_tree_add_uint (flag_tree, hf_fc_data_ds, tvb, 1, 1,
-                          COOK_DS_STATUS (flags));
+       case MGT_ASSOC_RESP:
+         fixed_tree = get_fixed_parameter_tree (mgt_tree, tvb, 0, 6);
+         add_fixed_field (fixed_tree, tvb, 0, FIELD_CAP_INFO);
+         add_fixed_field (fixed_tree, tvb, 2, FIELD_STATUS_CODE);
+         add_fixed_field (fixed_tree, tvb, 4, FIELD_ASSOC_ID);
 
-      /*      proto_tree_add_boolean(flag_tree,hf_fc_to_ds,tvb,1,1,
-         flags);
+         next_idx = 6; /* Size of fixed fields */
 
-         proto_tree_add_boolean(flag_tree,hf_fc_from_ds,tvb,1,1,
-         flags); */
+         tagged_parameter_tree_len =
+             tvb_reported_length_remaining(tvb, next_idx);
+         tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx,
+                                                  tagged_parameter_tree_len);
 
-      proto_tree_add_boolean (flag_tree, hf_fc_more_frag, tvb, 1, 1,
-                             flags);
+         while (tagged_parameter_tree_len > 0) {
+           if ((next_len=add_tagged_field (tagged_tree, tvb, next_idx))==0)
+             break;
+           next_idx +=next_len;
+           tagged_parameter_tree_len -= next_len;
+         }
+         break;
 
-      proto_tree_add_boolean (flag_tree, hf_fc_retry, tvb, 1, 1, flags);
 
-      proto_tree_add_boolean (flag_tree, hf_fc_pwr_mgt, tvb, 1, 1, flags);
+       case MGT_REASSOC_REQ:
+         fixed_tree = get_fixed_parameter_tree (mgt_tree, tvb, 0, 10);
+         add_fixed_field (fixed_tree, tvb, 0, FIELD_CAP_INFO);
+         add_fixed_field (fixed_tree, tvb, 2, FIELD_LISTEN_IVAL);
+         add_fixed_field (fixed_tree, tvb, 4, FIELD_CURRENT_AP_ADDR);
 
-      proto_tree_add_boolean (flag_tree, hf_fc_more_data, tvb, 1, 1,
-                             flags);
+         next_idx = 10;        /* Size of fixed fields */
+         tagged_parameter_tree_len =
+             tvb_reported_length_remaining(tvb, next_idx);
+         tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx,
+                                                  tagged_parameter_tree_len);
 
-      proto_tree_add_boolean (flag_tree, hf_fc_wep, tvb, 1, 1, flags);
+         while (tagged_parameter_tree_len > 0) {
+           if ((next_len=add_tagged_field (tagged_tree, tvb, next_idx))==0)
+             break;
+           next_idx +=next_len;
+           tagged_parameter_tree_len -= next_len;
+         }
+         break;
 
-      proto_tree_add_boolean (flag_tree, hf_fc_order, tvb, 1, 1, flags);
+       case MGT_REASSOC_RESP:
+         fixed_tree = get_fixed_parameter_tree (mgt_tree, tvb, 0, 10);
+         add_fixed_field (fixed_tree, tvb, 0, FIELD_CAP_INFO);
+         add_fixed_field (fixed_tree, tvb, 2, FIELD_STATUS_CODE);
+         add_fixed_field (fixed_tree, tvb, 4, FIELD_ASSOC_ID);
 
-      proto_tree_add_uint (hdr_tree, hf_did_duration, tvb, 2, 2,
-                          tvb_get_ntohs (tvb, 2));
+         next_idx = 6; /* Size of fixed fields */
+         tagged_parameter_tree_len =
+             tvb_reported_length_remaining(tvb, next_idx);
+         tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx,
+                                                  tagged_parameter_tree_len);
 
-    }
-
-  /* Perform Tasks which are common to a certain frame type */
-  switch (COOK_FRAME_TYPE (fcf))
-    {
+         while (tagged_parameter_tree_len > 0) {
+           if ((next_len=add_tagged_field (tagged_tree, tvb, next_idx))==0)
+             break;
+           next_idx +=next_len;
+           tagged_parameter_tree_len -= next_len;
+         }
+         break;
 
-    case MGT_FRAME:            /* All management frames share a common header */
-      src = tvb_get_ptr (tvb, 10, 6);
-      dst = tvb_get_ptr (tvb, 4, 6);
 
+       case MGT_PROBE_REQ:
+         next_idx = 0;
+         tagged_parameter_tree_len =
+             tvb_reported_length_remaining(tvb, next_idx);
+         tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx,
+                                                  tagged_parameter_tree_len);
 
-      if (check_col (pinfo->fd, COL_DEF_SRC))
-       col_add_fstr (pinfo->fd, COL_DEF_SRC, "%X:%X:%X:%X:%X:%X",
-                     src[0], src[1], src[2], src[3], src[4], src[5]);
+         while (tagged_parameter_tree_len > 0) {
+           if ((next_len=add_tagged_field (tagged_tree, tvb, next_idx))==0)
+             break;
+           next_idx +=next_len;
+           tagged_parameter_tree_len -= next_len;
+         }
+         break;
 
-      if (check_col (pinfo->fd, COL_DEF_DST))
-       col_add_fstr (pinfo->fd, COL_DEF_DST, "%X:%X:%X:%X:%X:%X",
-                     dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]);
 
-      if (tree)
-       {
-         proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 4, 6,
-                               tvb_get_ptr (tvb, 4, 6));
+       case MGT_PROBE_RESP:
+         fixed_tree = get_fixed_parameter_tree (mgt_tree, tvb, 0, 12);
+         add_fixed_field (fixed_tree, tvb, 0, FIELD_TIMESTAMP);
+         add_fixed_field (fixed_tree, tvb, 8, FIELD_BEACON_INTERVAL);
+         add_fixed_field (fixed_tree, tvb, 10, FIELD_CAP_INFO);
 
-         proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 10, 6,
-                               tvb_get_ptr (tvb, 10, 6));
+         next_idx = 12;        /* Size of fixed fields */
+         tagged_parameter_tree_len =
+             tvb_reported_length_remaining(tvb, next_idx);
+         tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx,
+                                                  tagged_parameter_tree_len);
 
-         proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 16, 6,
-                               tvb_get_ptr (tvb, 16, 6));
+         while (tagged_parameter_tree_len > 0) {
+           if ((next_len=add_tagged_field (tagged_tree, tvb, next_idx))==0)
+             break;
+           next_idx +=next_len;
+           tagged_parameter_tree_len -= next_len;
+         }
+         break;
 
-         proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2,
-                              COOK_FRAGMENT_NUMBER (tvb_get_ntohs
-                                                    (tvb, 22)));
 
-         proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
-                              COOK_SEQUENCE_NUMBER (tvb_get_ntohs
-                                                    (tvb, 22)));
-         cap_len = cap_len - MGT_FRAME_LEN - 4;
-       }
-      break;
+       case MGT_BEACON:                /* Dissect protocol payload fields  */
+         fixed_tree = get_fixed_parameter_tree (mgt_tree, tvb, 0, 12);
 
+         add_fixed_field (fixed_tree, tvb, 0, FIELD_TIMESTAMP);
+         add_fixed_field (fixed_tree, tvb, 8, FIELD_BEACON_INTERVAL);
+         add_fixed_field (fixed_tree, tvb, 10, FIELD_CAP_INFO);
 
+         next_idx = 12;        /* Size of fixed fields */
+         tagged_parameter_tree_len =
+             tvb_reported_length_remaining(tvb, next_idx);
+         tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx,
+                                                  tagged_parameter_tree_len);
 
-    case CONTROL_FRAME:
-      break;
+         while (tagged_parameter_tree_len > 0) {
+           if ((next_len=add_tagged_field (tagged_tree, tvb, next_idx))==0)
+             break;
+           next_idx +=next_len;
+           tagged_parameter_tree_len -= next_len;
+         }
+         break;
 
 
+       case MGT_ATIM:
+         break;
 
-    case DATA_FRAME:
-      addr_type = COOK_ADDR_SELECTOR (fcf);
 
-      /* In order to show src/dst address we must always do the following */
-      switch (addr_type)
-       {
-
-       case DATA_ADDR_T1:
-         src = tvb_get_ptr (tvb, 10, 6);
-         dst = tvb_get_ptr (tvb, 4, 6);
+       case MGT_DISASS:
+         fixed_tree = get_fixed_parameter_tree (mgt_tree, tvb, 0, 2);
+         add_fixed_field (fixed_tree, tvb, 0, FIELD_REASON_CODE);
          break;
 
 
-       case DATA_ADDR_T2:
-         src = tvb_get_ptr (tvb, 16, 6);
-         dst = tvb_get_ptr (tvb, 4, 6);
-         break;
+       case MGT_AUTHENTICATION:
+         fixed_tree = get_fixed_parameter_tree (mgt_tree, tvb, 0, 6);
+         add_fixed_field (fixed_tree, tvb, 0, FIELD_AUTH_ALG);
+         add_fixed_field (fixed_tree, tvb, 2, FIELD_AUTH_TRANS_SEQ);
+         add_fixed_field (fixed_tree, tvb, 4, FIELD_STATUS_CODE);
 
+         next_idx = 6; /* Size of fixed fields */
 
-       case DATA_ADDR_T3:
-         src = tvb_get_ptr (tvb, 10, 6);
-         dst = tvb_get_ptr (tvb, 16, 6);
+         tagged_parameter_tree_len =
+                 tvb_reported_length_remaining(tvb, next_idx);
+         if (tagged_parameter_tree_len != 0)
+           {
+             tagged_tree = get_tagged_parameter_tree (mgt_tree,
+                                                      tvb,
+                                                      next_idx,
+                                                      tagged_parameter_tree_len);
+
+             while (tagged_parameter_tree_len > 0) {
+               if ((next_len=add_tagged_field (tagged_tree, tvb, next_idx))==0)
+                 break;
+               next_idx +=next_len;
+               tagged_parameter_tree_len -= next_len;
+             }
+           }
          break;
 
 
-       case DATA_ADDR_T4:
-         src = tvb_get_ptr (tvb, 24, 6);
-         dst = tvb_get_ptr (tvb, 16, 6);
+       case MGT_DEAUTHENTICATION:
+         fixed_tree = get_fixed_parameter_tree (mgt_tree, tvb, 0, 2);
+         add_fixed_field (fixed_tree, tvb, 0, FIELD_REASON_CODE);
          break;
        }
+    }
+}
 
-      if (check_col (pinfo->fd, COL_DEF_SRC))
-       col_add_fstr (pinfo->fd, COL_DEF_SRC,
-                     "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
-                     src[0], src[1], src[2], src[3], src[4], src[5]);
+static void
+set_src_addr_cols(packet_info *pinfo, const guint8 *addr, char *type)
+{
+  if (check_col(pinfo->cinfo, COL_RES_DL_SRC))
+    col_add_fstr(pinfo->cinfo, COL_RES_DL_SRC, "%s (%s)",
+                   get_ether_name(addr), type);
+  if (check_col(pinfo->cinfo, COL_UNRES_DL_SRC))
+    col_add_fstr(pinfo->cinfo, COL_UNRES_DL_SRC, "%s (%s)",
+                    ether_to_str(addr), type);
+}
 
-      if (check_col (pinfo->fd, COL_DEF_DST))
-       col_add_fstr (pinfo->fd, COL_DEF_DST,
-                     "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
-                     dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]);
+static void
+set_dst_addr_cols(packet_info *pinfo, const guint8 *addr, char *type)
+{
+  if (check_col(pinfo->cinfo, COL_RES_DL_DST))
+    col_add_fstr(pinfo->cinfo, COL_RES_DL_DST, "%s (%s)",
+                    get_ether_name(addr), type);
+  if (check_col(pinfo->cinfo, COL_UNRES_DL_DST))
+    col_add_fstr(pinfo->cinfo, COL_UNRES_DL_DST, "%s (%s)",
+                    ether_to_str(addr), type);
+}
 
-      /* Now if we have a tree we start adding stuff */
-      if (tree)
-       {
+static void
+show_fragments(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+              fragment_data *fd_head)
+{
+  guint32 offset;
+  fragment_data *fd;
+  proto_tree *ft;
+  proto_item *fi;
+
+  fi = proto_tree_add_item(tree, hf_fragments, tvb, 0, -1, FALSE);
+  ft = proto_item_add_subtree(fi, ett_fragments);
+  offset = 0;
+  for (fd = fd_head->next; fd != NULL; fd = fd->next){
+    if (fd->flags & (FD_OVERLAP|FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
+      /*
+       * This fragment has some flags set; create a subtree for it and
+       * display the flags.
+       */
+      proto_tree *fet = NULL;
+      proto_item *fei = NULL;
+      int hf;
+
+      if (fd->flags & (FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
+       hf = hf_fragment_error;
+      } else {
+       hf = hf_fragment;
+      }
+      fei = proto_tree_add_none_format(ft, hf, tvb, offset, fd->len,
+                                      "Frame:%u payload:%u-%u",
+                                      fd->frame, offset, offset+fd->len-1);
+      fet = proto_item_add_subtree(fei, ett_fragment);
+      if (fd->flags&FD_OVERLAP)
+       proto_tree_add_boolean(fet, hf_fragment_overlap, tvb, 0, 0, TRUE);
+      if (fd->flags&FD_OVERLAPCONFLICT) {
+       proto_tree_add_boolean(fet, hf_fragment_overlap_conflict, tvb, 0, 0,
+                              TRUE);
+      }
+      if (fd->flags&FD_MULTIPLETAILS) {
+       proto_tree_add_boolean(fet, hf_fragment_multiple_tails, tvb, 0, 0,
+                              TRUE);
+      }
+      if (fd->flags&FD_TOOLONGFRAGMENT) {
+       proto_tree_add_boolean(fet, hf_fragment_too_long_fragment, tvb, 0, 0,
+                              TRUE);
+      }
+    } else {
+      /*
+       * Nothing of interest for this fragment.
+       */
+      proto_tree_add_none_format(ft, hf_fragment, tvb, offset, fd->len,
+                                "Frame:%u payload:%u-%u",
+                                fd->frame, offset, offset+fd->len-1);
+    }
+    offset += fd->len;
+  }
+  if (fd_head->flags & (FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
+    if (check_col(pinfo->cinfo, COL_INFO))
+      col_set_str(pinfo->cinfo, COL_INFO, "[Illegal fragments]");
+  }
+}
 
+/* ************************************************************************* */
+/*                          Dissect 802.11 frame                             */
+/* ************************************************************************* */
+static void
+dissect_ieee80211_common (tvbuff_t * tvb, packet_info * pinfo,
+                         proto_tree * tree, gboolean fixed_length_header,
+                         gboolean has_radio_information)
+{
+  guint16 fcf, flags, frame_type_subtype;
+  guint16 seq_control;
+  guint32 seq_number, frag_number;
+  gboolean more_frags;
+  const guint8 *src = NULL, *dst = NULL;
+  proto_item *ti = NULL;
+  proto_item *flag_item;
+  proto_item *fc_item;
+  proto_tree *hdr_tree = NULL;
+  proto_tree *flag_tree;
+  proto_tree *fc_tree;
+  guint16 hdr_len;
+  gboolean save_fragmented;
+  tvbuff_t *volatile next_tvb;
+  guint32 addr_type;
+  volatile gboolean is_802_2;
 
-         switch (addr_type)
-           {
+  if (check_col (pinfo->cinfo, COL_PROTOCOL))
+    col_set_str (pinfo->cinfo, COL_PROTOCOL, "IEEE 802.11");
+  if (check_col (pinfo->cinfo, COL_INFO))
+    col_clear (pinfo->cinfo, COL_INFO);
 
-           case DATA_ADDR_T1:
-             proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 4, 6,
-                                   tvb_get_ptr (tvb, 4, 6));
-             proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 10, 6,
-                                   tvb_get_ptr (tvb, 10, 6));
-             proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 16, 6,
-                                   tvb_get_ptr (tvb, 16, 6));
-             break;
+  fcf = tvb_get_letohs (tvb, 0);
+  if (fixed_length_header)
+    hdr_len = DATA_LONG_HDR_LEN;
+  else
+    hdr_len = find_header_length (fcf);
+  frame_type_subtype = COMPOSE_FRAME_TYPE(fcf);
 
+  if (check_col (pinfo->cinfo, COL_INFO))
+      col_set_str (pinfo->cinfo, COL_INFO,
+          val_to_str(frame_type_subtype, frame_type_subtype_vals,
+              "Unrecognized (Reserved frame)"));
 
-           case DATA_ADDR_T2:
-             proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 4, 6,
-                                   tvb_get_ptr (tvb, 4, 6));
-             proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 10, 6,
-                                   tvb_get_ptr (tvb, 10, 6));
-             proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 16, 6,
-                                   tvb_get_ptr (tvb, 16, 6));
-             break;
+  flags = COOK_FLAGS (fcf);
+  more_frags = HAVE_FRAGMENTS (flags);
 
+  /* Add the radio information, if present, and the FC to the current tree */
+  if (tree)
+    {
+      ti = proto_tree_add_protocol_format (tree, proto_wlan, tvb, 0, hdr_len,
+                                          "IEEE 802.11");
+      hdr_tree = proto_item_add_subtree (ti, ett_80211);
 
-           case DATA_ADDR_T3:
-             proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 4, 6,
-                                   tvb_get_ptr (tvb, 4, 6));
-             proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 10, 6,
-                                   tvb_get_ptr (tvb, 10, 6));
-             proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 16, 6,
-                                   tvb_get_ptr (tvb, 16, 6));
-             break;
+      if (has_radio_information) {
+       proto_tree_add_uint_format(hdr_tree, hf_data_rate,
+                                  tvb, 0, 0,
+                                  pinfo->pseudo_header->ieee_802_11.data_rate,
+                                  "Data Rate: %g mb/s",
+                                  .5*pinfo->pseudo_header->ieee_802_11.data_rate);
+
+       proto_tree_add_uint(hdr_tree, hf_channel,
+                           tvb, 0, 0,
+                           pinfo->pseudo_header->ieee_802_11.channel);
+
+       proto_tree_add_uint_format(hdr_tree, hf_signal_strength,
+                                  tvb, 0, 0,
+                                  pinfo->pseudo_header->ieee_802_11.signal_level,
+                                  "Signal Strength: %u%%",
+                                  pinfo->pseudo_header->ieee_802_11.signal_level);
+      }
+
+      proto_tree_add_uint (hdr_tree, hf_fc_frame_type_subtype,
+                          tvb, 0, 1,
+                          frame_type_subtype);
 
+      fc_item = proto_tree_add_uint_format (hdr_tree, hf_fc_field, tvb, 0, 2,
+                                           fcf,
+                                           "Frame Control: 0x%04X",
+                                           fcf);
 
-           case DATA_ADDR_T4:
-             proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6,
-                                   tvb_get_ptr (tvb, 4, 6));
-             proto_tree_add_ether (hdr_tree, hf_addr_ta, tvb, 10, 6,
-                                   tvb_get_ptr (tvb, 10, 6));
-             proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 16, 6,
-                                   tvb_get_ptr (tvb, 16, 6));
-             proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 24, 6,
-                                   tvb_get_ptr (tvb, 24, 6));
-             break;
+      fc_tree = proto_item_add_subtree (fc_item, ett_fc_tree);
 
-           }
 
-       }
-      break;
-    }
+      proto_tree_add_uint (fc_tree, hf_fc_proto_version, tvb, 0, 1,
+                          COOK_PROT_VERSION (fcf));
 
+      proto_tree_add_uint (fc_tree, hf_fc_frame_type, tvb, 0, 1,
+                          COOK_FRAME_TYPE (fcf));
 
-  switch (COMPOSE_FRAME_TYPE (fcf))
-    {
+      proto_tree_add_uint (fc_tree, hf_fc_frame_subtype,
+                          tvb, 0, 1,
+                          COOK_FRAME_SUBTYPE (fcf));
 
-    case MGT_ASSOC_REQ:
-      COL_SHOW_INFO (pinfo->fd, "Association Request");
-      if (tree)
-       {
-         fixed_tree = get_fixed_parameter_tree (tree, tvb, MGT_FRAME_LEN, 4);
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_HDR_LEN,
-                          FIELD_CAP_INFO);
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_HDR_LEN + 2,
-                          FIELD_LISTEN_IVAL);
+      flag_item =
+       proto_tree_add_uint_format (fc_tree, hf_fc_flags, tvb, 1, 1,
+                                   flags, "Flags: 0x%X", flags);
 
-         next_idx = MGT_FRAME_HDR_LEN + 4;     /* Size of fixed fields */
-         tagged_tree = get_tagged_parameter_tree (tree, tvb, next_idx,
-                                                  pinfo->captured_len - 4 -
-                                                  next_idx);
+      flag_tree = proto_item_add_subtree (flag_item, ett_proto_flags);
 
+      proto_tree_add_uint (flag_tree, hf_fc_data_ds, tvb, 1, 1,
+                          COOK_DS_STATUS (flags));
 
-         while (pinfo->captured_len > (next_idx + 4))
-           next_idx += add_tagged_field (tagged_tree, tvb, next_idx);
-       }
-      break;
+      proto_tree_add_boolean (flag_tree, hf_fc_more_frag, tvb, 1, 1,
+                             flags);
 
+      proto_tree_add_boolean (flag_tree, hf_fc_retry, tvb, 1, 1, flags);
 
+      proto_tree_add_boolean (flag_tree, hf_fc_pwr_mgt, tvb, 1, 1, flags);
 
-    case MGT_ASSOC_RESP:
-      COL_SHOW_INFO (pinfo->fd, "Association Response");
+      proto_tree_add_boolean (flag_tree, hf_fc_more_data, tvb, 1, 1,
+                             flags);
 
-      if (tree)
-       {
-         fixed_tree = get_fixed_parameter_tree (tree, tvb, MGT_FRAME_LEN, 6);
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN, FIELD_CAP_INFO);
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 2,
-                          FIELD_STATUS_CODE);
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 4,
-                          FIELD_ASSOC_ID);
+      proto_tree_add_boolean (flag_tree, hf_fc_wep, tvb, 1, 1, flags);
 
-         next_idx = MGT_FRAME_LEN + 6; /* Size of fixed fields */
+      proto_tree_add_boolean (flag_tree, hf_fc_order, tvb, 1, 1, flags);
 
-         tagged_tree = get_tagged_parameter_tree (tree, tvb, next_idx,
-                                                  pinfo->captured_len - 4 -
-                                                  next_idx);
+      if (frame_type_subtype == CTRL_PS_POLL) 
+       proto_tree_add_uint(hdr_tree, hf_assoc_id,tvb,2,2,
+                           COOK_ASSOC_ID(tvb_get_letohs(tvb,2)));
+     
+      else
+         proto_tree_add_uint (hdr_tree, hf_did_duration, tvb, 2, 2,
+                              tvb_get_letohs (tvb, 2));
+    }
 
-         while (pinfo->captured_len > (next_idx + 4))
-           next_idx += add_tagged_field (tagged_tree, tvb, next_idx);
+  /*
+   * Decode the part of the frame header that isn't the same for all
+   * frame types.
+   */
+  seq_control = 0;
+  frag_number = 0;
+  seq_number = 0;
 
-       }
-      break;
+  switch (frame_type_subtype)
+    {
 
+    case MGT_ASSOC_REQ:
+    case MGT_ASSOC_RESP:
     case MGT_REASSOC_REQ:
-      COL_SHOW_INFO (pinfo->fd, "Reassociation Request");
-      if (tree)
-       {
-         fixed_tree = get_fixed_parameter_tree (tree, tvb, MGT_FRAME_LEN, 10);
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN, FIELD_CAP_INFO);
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 2,
-                          FIELD_LISTEN_IVAL);
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 4,
-                          FIELD_CURRENT_AP_ADDR);
-
-         next_idx = MGT_FRAME_LEN + 10;        /* Size of fixed fields */
-         tagged_tree = get_tagged_parameter_tree (tree, tvb, next_idx,
-                                                  pinfo->captured_len - 4 -
-                                                  next_idx);
-
-         while ((pinfo->captured_len) > (next_idx + 4))
-           next_idx += add_tagged_field (tagged_tree, tvb, next_idx);
-       }
-      break;
-
     case MGT_REASSOC_RESP:
-      COL_SHOW_INFO (pinfo->fd, "Reassociation Response");
-      if (tree)
-       {
-         fixed_tree = get_fixed_parameter_tree (tree, tvb, MGT_FRAME_LEN, 10);
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN, FIELD_CAP_INFO);
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 2,
-                          FIELD_STATUS_CODE);
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 4,
-                          FIELD_ASSOC_ID);
-
-         next_idx = MGT_FRAME_LEN + 6; /* Size of fixed fields */
-         tagged_tree = get_tagged_parameter_tree (tree, tvb, next_idx,
-                                                  pinfo->captured_len - 4 -
-                                                  next_idx);
-
-         while (pinfo->captured_len > (next_idx + 4))
-           next_idx += add_tagged_field (tagged_tree, tvb, next_idx);
-
-
-       }
-      break;
-
     case MGT_PROBE_REQ:
-      COL_SHOW_INFO (pinfo->fd, "Probe Request");
-      if (tree)
-       {
-         next_idx = MGT_FRAME_LEN;
-         tagged_tree = get_tagged_parameter_tree (tree, tvb, MGT_FRAME_LEN,
-                                                  pinfo->captured_len - 4 -
-                                                  next_idx);
-
-         while (pinfo->captured_len > (next_idx + 4))
-           next_idx += add_tagged_field (tagged_tree, tvb, next_idx);
-       }
-      break;
-
-
-
     case MGT_PROBE_RESP:
-      COL_SHOW_INFO (pinfo->fd, "Probe Response");
-      if (tree)
-       {
-         fixed_tree = get_fixed_parameter_tree (tree, tvb, MGT_FRAME_LEN, 12);
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN, FIELD_TIMESTAMP);
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 8,
-                          FIELD_BEACON_INTERVAL);
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 10,
-                          FIELD_CAP_INFO);
-
-         next_idx = MGT_FRAME_LEN + 12;        /* Size of fixed fields */
-         tagged_tree = get_tagged_parameter_tree (tree, tvb, next_idx,
-                                                  pinfo->captured_len - 4 -
-                                                  next_idx);
-
-         while ((pinfo->captured_len) > (next_idx + 4))
-           next_idx += add_tagged_field (tagged_tree, tvb, next_idx);
-       }
-      break;
-
-
-    case MGT_BEACON:           /* Dissect protocol payload fields  */
-      COL_SHOW_INFO (pinfo->fd, "Beacon frame");
-
-      if (tree)
-       {
-         fixed_tree = get_fixed_parameter_tree (tree, tvb, MGT_FRAME_LEN, 12);
-
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN, FIELD_TIMESTAMP);
-
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 8,
-                          FIELD_BEACON_INTERVAL);
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 10,
-                          FIELD_CAP_INFO);
-
-         next_idx = MGT_FRAME_LEN + 12;        /* Size of fixed fields */
-         tagged_tree = get_tagged_parameter_tree (tree, tvb, next_idx,
-                                                  pinfo->captured_len - 4 -
-                                                  next_idx);
-
-         while (pinfo->captured_len > (next_idx + 4))
-           next_idx += add_tagged_field (tagged_tree, tvb, next_idx);
-
-       }
-      break;
-
+    case MGT_BEACON:
+    case MGT_ATIM:
+    case MGT_DISASS:
+    case MGT_AUTHENTICATION:
+    case MGT_DEAUTHENTICATION:
+      /*
+       * All management frame types have the same header.
+       */
+      src = tvb_get_ptr (tvb, 10, 6);
+      dst = tvb_get_ptr (tvb, 4, 6);
 
+      SET_ADDRESS(&pinfo->dl_src, AT_ETHER, 6, src);
+      SET_ADDRESS(&pinfo->src, AT_ETHER, 6, src);
+      SET_ADDRESS(&pinfo->dl_dst, AT_ETHER, 6, dst);
+      SET_ADDRESS(&pinfo->dst, AT_ETHER, 6, dst);
 
-    case MGT_ATIM:
-      COL_SHOW_INFO (pinfo->fd, "ATIM");
-      if (tree)
-       {
-       }
-      break;
+      seq_control = tvb_get_letohs(tvb, 22);
+      frag_number = COOK_FRAGMENT_NUMBER(seq_control);
+      seq_number = COOK_SEQUENCE_NUMBER(seq_control);
 
-    case MGT_DISASS:
-      COL_SHOW_INFO (pinfo->fd, "Dissassociate");
       if (tree)
        {
-         fixed_tree =
-           get_fixed_parameter_tree (tree, tvb, MGT_FRAME_LEN, cap_len);
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN, FIELD_REASON_CODE);
-       }
-      break;
+         proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 4, 6, dst);
 
-    case MGT_AUTHENTICATION:
-      COL_SHOW_INFO (pinfo->fd, "Authentication");
-      if (tree)
-       {
-         fixed_tree = get_fixed_parameter_tree (tree, tvb, MGT_FRAME_LEN, 6);
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN, FIELD_AUTH_ALG);
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 2,
-                          FIELD_AUTH_TRANS_SEQ);
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 4,
-                          FIELD_STATUS_CODE);
+         proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 10, 6, src);
 
-         next_idx = MGT_FRAME_LEN + 6; /* Size of fixed fields */
+         /* add items for wlan.addr filter */
+         proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 4, 6, dst);
+         proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 10, 6, src);
 
-         if ((pinfo->captured_len - next_idx - 4) != 0)
-           {
-             tagged_tree = get_tagged_parameter_tree (tree,
-                                                      tvb,
-                                                      next_idx,
-                                                      pinfo->captured_len -
-                                                      next_idx - 4);
+         proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 16, 6,
+                               tvb_get_ptr (tvb, 16, 6));
 
-             while ((pinfo->captured_len) > (next_idx - 4))
-               next_idx += add_tagged_field (tagged_tree, tvb, next_idx);
-           }
-       }
-      break;
+         proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2,
+                              frag_number);
 
-    case MGT_DEAUTHENTICATION:
-      COL_SHOW_INFO (pinfo->fd, "Deauthentication");
-      if (tree)
-       {
-         fixed_tree = get_fixed_parameter_tree (hdr_tree, tvb, MGT_FRAME_LEN, 2);
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN, FIELD_REASON_CODE);
+         proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
+                              seq_number);
        }
       break;
 
 
-
     case CTRL_PS_POLL:
-      COL_SHOW_INFO (pinfo->fd, "Power-Save poll");
-
       src = tvb_get_ptr (tvb, 10, 6);
       dst = tvb_get_ptr (tvb, 4, 6);
 
-
-      if (check_col (pinfo->fd, COL_DEF_SRC))
-       col_add_fstr (pinfo->fd, COL_DEF_SRC,
-                     "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X (BSSID)",
-                     src[0], src[1], src[2], src[3], src[4], src[5]);
-
-      if (check_col (pinfo->fd, COL_DEF_DST))
-       col_add_fstr (pinfo->fd, COL_DEF_DST,
-                     "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X (TA)",
-                     dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]);
+      set_src_addr_cols(pinfo, src, "BSSID");
+      set_dst_addr_cols(pinfo, dst, "BSSID");
 
       if (tree)
        {
-         proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 4, 6,
-                               tvb_get_ptr (tvb, 4, 6));
-
-         proto_tree_add_ether (hdr_tree, hf_addr_ta, tvb, 10, 6,
-                               tvb_get_ptr (tvb, 10, 6));
+         proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 4, 6, dst);
 
+         proto_tree_add_ether (hdr_tree, hf_addr_ta, tvb, 10, 6, src);
        }
       break;
 
 
-
     case CTRL_RTS:
-      COL_SHOW_INFO (pinfo->fd, "Request-to-send");
       src = tvb_get_ptr (tvb, 10, 6);
       dst = tvb_get_ptr (tvb, 4, 6);
 
-
-      if (check_col (pinfo->fd, COL_DEF_SRC))
-       col_add_fstr (pinfo->fd, COL_DEF_SRC,
-                     "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X (TA)",
-                     src[0], src[1], src[2], src[3], src[4], src[5]);
-
-      if (check_col (pinfo->fd, COL_DEF_DST))
-       col_add_fstr (pinfo->fd, COL_DEF_DST,
-                     "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X (RA)",
-                     dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]);
+      set_src_addr_cols(pinfo, src, "TA");
+      set_dst_addr_cols(pinfo, dst, "RA");
 
       if (tree)
        {
-         proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6,
-                               tvb_get_ptr (tvb, 4, 6));
-
-         proto_tree_add_ether (hdr_tree, hf_addr_ta, tvb, 10, 6,
-                               tvb_get_ptr (tvb, 10, 6));
+         proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6, dst);
 
+         proto_tree_add_ether (hdr_tree, hf_addr_ta, tvb, 10, 6, src);
        }
       break;
 
 
-
     case CTRL_CTS:
-      COL_SHOW_INFO (pinfo->fd, "Clear-to-send");
-
       dst = tvb_get_ptr (tvb, 4, 6);
 
-      if (check_col (pinfo->fd, COL_DEF_DST))
-       col_add_fstr (pinfo->fd, COL_DEF_DST,
-                     "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X (RA)",
-                     dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]);
+      set_dst_addr_cols(pinfo, dst, "RA");
 
       if (tree)
-       {
-         proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6,
-                               tvb_get_ptr (tvb, 4, 6));
-
-       }
+         proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6, dst);
       break;
 
 
-
     case CTRL_ACKNOWLEDGEMENT:
-      COL_SHOW_INFO (pinfo->fd, "Acknowledgement");
-
       dst = tvb_get_ptr (tvb, 4, 6);
 
-      if (check_col (pinfo->fd, COL_DEF_DST))
-       col_add_fstr (pinfo->fd, COL_DEF_DST,
-                     "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X (RA)",
-                     dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]);
+      set_dst_addr_cols(pinfo, dst, "RA");
 
       if (tree)
-       proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6,
-                             tvb_get_ptr (tvb, 4, 6));
+       proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6, dst);
       break;
 
 
-
     case CTRL_CFP_END:
-      COL_SHOW_INFO (pinfo->fd, "CF-End (Control-frame)");
-
       src = tvb_get_ptr (tvb, 10, 6);
       dst = tvb_get_ptr (tvb, 4, 6);
 
-
-      if (check_col (pinfo->fd, COL_DEF_SRC))
-       col_add_fstr (pinfo->fd, COL_DEF_SRC, "%X:%X:%X:%X:%X:%X (BSSID)",
-                     src[0], src[1], src[2], src[3], src[4], src[5]);
-
-      if (check_col (pinfo->fd, COL_DEF_DST))
-       col_add_fstr (pinfo->fd, COL_DEF_DST, "%X:%X:%X:%X:%X:%X (RA)",
-                     dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]);
+      set_src_addr_cols(pinfo, src, "BSSID");
+      set_dst_addr_cols(pinfo, dst, "RA");
 
       if (tree)
        {
-         proto_tree_add_uint (hdr_tree, hf_did_duration, tvb, 2, 2,
-                              tvb_get_ntohs (tvb, 2));
-
-         proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6,
-                               tvb_get_ptr (tvb, 4, 6));
-
-         proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 10, 6,
-                               tvb_get_ptr (tvb, 10, 6));
-
+         proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6, dst);
+         proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 10, 6, src);
        }
       break;
 
 
-
     case CTRL_CFP_ENDACK:
-      COL_SHOW_INFO (pinfo->fd, "CF-End + CF-Ack (Control-frame)");
-
       src = tvb_get_ptr (tvb, 10, 6);
       dst = tvb_get_ptr (tvb, 4, 6);
 
-      if (check_col (pinfo->fd, COL_DEF_SRC))
-       col_add_fstr (pinfo->fd, COL_DEF_SRC, "%X:%X:%X:%X:%X:%X (BSSID)",
-                     src[0], src[1], src[2], src[3], src[4], src[5]);
-
-      if (check_col (pinfo->fd, COL_DEF_DST))
-       col_add_fstr (pinfo->fd, COL_DEF_DST, "%X:%X:%X:%X:%X:%X (RA)",
-                     dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]);
+      set_src_addr_cols(pinfo, src, "BSSID");
+      set_dst_addr_cols(pinfo, dst, "RA");
 
       if (tree)
        {
-         proto_tree_add_uint (hdr_tree, hf_did_duration, tvb, 2, 2,
-                              tvb_get_ntohs (tvb, 2));
-
-         proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6,
-                               tvb_get_ptr (tvb, 4, 6));
-
-         proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 10, 6,
-                               tvb_get_ptr (tvb, 10, 6));
+         proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6, dst);
 
+         proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 10, 6, src);
        }
       break;
 
 
-
     case DATA:
-      COL_SHOW_INFO (pinfo->fd, "Data");
-      if (tree)
+    case DATA_NULL_FUNCTION:
+    case DATA_CF_ACK:
+    case DATA_CF_ACK_NOD:
+    case DATA_CF_POLL:
+    case DATA_CF_POLL_NOD:
+    case DATA_CF_ACK_POLL:
+    case DATA_CF_ACK_POLL_NOD:
+      addr_type = COOK_ADDR_SELECTOR (fcf);
+
+      /* In order to show src/dst address we must always do the following */
+      switch (addr_type)
        {
-         hdr_len = find_header_length (tvb_get_ptr (tvb, 0, cap_len), 0);
 
-         next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
-         dissect_llc (next_tvb, pinfo, tree);
+       case DATA_ADDR_T1:
+         src = tvb_get_ptr (tvb, 10, 6);
+         dst = tvb_get_ptr (tvb, 4, 6);
+         break;
 
-       }
-      break;
 
+       case DATA_ADDR_T2:
+         src = tvb_get_ptr (tvb, 16, 6);
+         dst = tvb_get_ptr (tvb, 4, 6);
+         break;
 
 
-    case DATA_CF_ACK:
-      COL_SHOW_INFO (pinfo->fd, "Data + CF-Acknowledgement");
-      if (tree)
-       {
-         hdr_len = find_header_length (tvb_get_ptr (tvb, 0, cap_len), 0);
+       case DATA_ADDR_T3:
+         src = tvb_get_ptr (tvb, 10, 6);
+         dst = tvb_get_ptr (tvb, 16, 6);
+         break;
 
-         next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
-         dissect_llc (next_tvb, pinfo, tree);
+
+       case DATA_ADDR_T4:
+         src = tvb_get_ptr (tvb, 24, 6);
+         dst = tvb_get_ptr (tvb, 16, 6);
+         break;
        }
-      break;
 
+      SET_ADDRESS(&pinfo->dl_src, AT_ETHER, 6, src);
+      SET_ADDRESS(&pinfo->src, AT_ETHER, 6, src);
+      SET_ADDRESS(&pinfo->dl_dst, AT_ETHER, 6, dst);
+      SET_ADDRESS(&pinfo->dst, AT_ETHER, 6, dst);
 
+      seq_control = tvb_get_letohs(tvb, 22);
+      frag_number = COOK_FRAGMENT_NUMBER(seq_control);
+      seq_number = COOK_SEQUENCE_NUMBER(seq_control);
 
-    case DATA_CF_POLL:
-      COL_SHOW_INFO (pinfo->fd, "Data + CF-Poll");
+      /* Now if we have a tree we start adding stuff */
       if (tree)
        {
-         hdr_len = find_header_length (tvb_get_ptr (tvb, 0, cap_len), 0);
-         next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
-         dissect_llc (next_tvb, pinfo, tree);
+
+
+         switch (addr_type)
+           {
+
+           case DATA_ADDR_T1:
+             proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 4, 6, dst);
+             proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 10, 6, src);
+             proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 16, 6,
+                                   tvb_get_ptr (tvb, 16, 6));
+             proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2,
+                                  frag_number);
+             proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
+                                  seq_number);
+
+             /* add items for wlan.addr filter */
+             proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 4, 6, dst);
+             proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 10, 6, src);
+             break;
+             
+             
+           case DATA_ADDR_T2:
+             proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 4, 6, dst);
+             proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 10, 6,
+                                   tvb_get_ptr (tvb, 10, 6));
+             proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 16, 6, src);
+             proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2,
+                                  frag_number);
+             proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
+                                  seq_number);
+
+             /* add items for wlan.addr filter */
+             proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 4, 6, dst);
+             proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 16, 6, src);
+             break;
+   
+
+           case DATA_ADDR_T3:
+             proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 4, 6,
+                                   tvb_get_ptr (tvb, 4, 6));
+             proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 10, 6, src);
+             proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 16, 6, dst);
+
+             proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2,
+                                  frag_number);
+             proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
+                                  seq_number);
+
+             /* add items for wlan.addr filter */
+             proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 10, 6, src);
+             proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 16, 6, dst);
+             break;
+             
+
+           case DATA_ADDR_T4:
+             proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6,
+                                   tvb_get_ptr (tvb, 4, 6));
+             proto_tree_add_ether (hdr_tree, hf_addr_ta, tvb, 10, 6,
+                                   tvb_get_ptr (tvb, 10, 6));
+             proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 16, 6, dst);
+             proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2,
+                                  frag_number);
+             proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
+                                  seq_number);
+             proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 24, 6, src);
+
+             /* add items for wlan.addr filter */
+             proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 16, 6, dst);
+             proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 24, 6, src);
+             break;
+           }
+
        }
       break;
+    }
 
+  /*
+   * Only management and data frames have a body, so we don't have
+   * anything more to do for other types of frames.
+   */
+  switch (COOK_FRAME_TYPE (fcf))
+    {
 
+    case MGT_FRAME:
+      break;
 
-    case DATA_CF_ACK_POLL:
-      COL_SHOW_INFO (pinfo->fd, "Data + CF-Acknowledgement/Poll");
-      if (tree)
+    case DATA_FRAME:
+      /*
+       * No-data frames don't have a body.
+       */
+      switch (frame_type_subtype)
        {
-         hdr_len = find_header_length (tvb_get_ptr (tvb, 0, cap_len), 0);
-         next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
-         dissect_llc (next_tvb, pinfo, tree);
+
+       case DATA_NULL_FUNCTION:
+       case DATA_CF_ACK_NOD:
+       case DATA_CF_POLL_NOD:
+       case DATA_CF_ACK_POLL_NOD:
+         return;
        }
-      break;
+       break;
 
+    default:
+      return;
+    }
 
+  /*
+   * For WEP-encrypted frames, dissect the WEP parameters and
+   * display the payload as data.
+   *
+   * XXX - allow the key to be specified, and, if it is, decrypt
+   * the payload and dissect it?
+   */
+  if (IS_WEP(COOK_FLAGS(fcf)))
+    {
+      int pkt_len = tvb_reported_length (tvb);
+      int cap_len = tvb_length (tvb);
 
-    case DATA_NULL_FUNCTION:
-      COL_SHOW_INFO (pinfo->fd, "Null function (No data)");
-      break;
+      if (tree)
+        {
+         get_wep_parameter_tree (tree, tvb, hdr_len, pkt_len);
+         pkt_len -= hdr_len + 4;
+         cap_len -= hdr_len + 4;
+
+         /*
+          * OK, pkt_len and cap_len have had the length of the 802.11
+          * header and WEP parameters subtracted.
+          *
+          * If there's anything left:
+          *
+          *    if cap_len is greater than or equal to pkt_len (i.e., we
+          *    captured the entire packet), subtract the length of the
+          *    WEP CRC from cap_len;
+          *
+          *    if cap_len is from 1 to 3 bytes less than pkt_len (i.e.,
+          *    we captured some but not all of the WEP CRC), subtract
+          *    the length of the part of the WEP CRC we captured from
+          *    crc_len;
+          *
+          *    otherwise, (i.e., we captured none of the WEP CRC),
+          *    leave cap_len alone;
+          *
+          * and subtract the length of the WEP CRC from pkt_len.
+          */
+         if (cap_len >= pkt_len)
+           cap_len -= 4;
+         else if ((pkt_len - cap_len) >= 1 && (pkt_len - cap_len) <= 3)
+           cap_len -= 4 - (pkt_len - cap_len);
+         pkt_len -= 4;
+         if (cap_len > 0 && pkt_len > 0)
+           call_dissector(data_handle,tvb_new_subset(tvb, hdr_len + 4, -1,tvb_reported_length_remaining(tvb,hdr_len + 4)),pinfo, tree);
+       }
+       return;
+    }
 
+  /*
+   * Now dissect the body of a non-WEP-encrypted frame.
+   */
+
+  /*
+   * Do defragmentation if "wlan_defragment" is true.
+   *
+   * We have to do some special handling to catch frames that
+   * have the "More Fragments" indicator not set but that
+   * don't show up as reassembled and don't have any other
+   * fragments present.  Some networking interfaces appear
+   * to do reassembly even when you're capturing raw packets
+   * *and* show the reassembled packet without the "More
+   * Fragments" indicator set *but* with a non-zero fragment
+   * number.
+   *
+   * (This could get some false positives if we really *did* only
+   * capture the last fragment of a fragmented packet, but that's
+   * life.)
+   */
+  save_fragmented = pinfo->fragmented;
+  if (wlan_defragment && (more_frags || frag_number != 0)) {
+    fragment_data *fd_head;
+
+    /*
+     * If we've already seen this frame, look it up in the
+     * table of reassembled packets, otherwise add it to
+     * whatever reassembly is in progress, if any, and see
+     * if it's done.
+     */
+    fd_head = fragment_add_seq_check(tvb, hdr_len, pinfo, seq_number,
+                                    wlan_fragment_table,
+                                    wlan_reassembled_table,
+                                    frag_number,
+                                    tvb_length_remaining(tvb, hdr_len),
+                                    more_frags);
+    if (fd_head != NULL) {
+      /*
+       * Either this is reassembled or it wasn't fragmented
+       * (see comment above about some networking interfaces).
+       * In either case, it's now in the table of reassembled
+       * packets.
+       *
+       * If the "fragment_data" structure doesn't have a list of
+       * fragments, we assume it's a placeholder to mark those
+       * not-really-fragmented packets, and just treat this as
+       * a non-fragmented frame.
+       */
+      if (fd_head->next != NULL) {
+        next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
+        tvb_set_child_real_data_tvbuff(tvb, next_tvb);
+        add_new_data_source(pinfo->fd, next_tvb, "Reassembled 802.11");
+
+       /* Show all fragments. */
+       show_fragments(next_tvb, pinfo, hdr_tree, fd_head);
+      } else {
+       /*
+        * Not fragmented, really.
+        * Show it as a regular frame.
+        */
+       next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
+      }
+
+      /* It's not fragmented. */
+      pinfo->fragmented = FALSE;
+    } else {
+      /* We don't have the complete reassembled payload. */
+      next_tvb = NULL;
+    }
+  } else {
+    /*
+     * If this is the first fragment, dissect its contents, otherwise
+     * just show it as a fragment.
+     */
+    if (frag_number != 0) {
+      /* Not the first fragment - don't dissect it. */
+      next_tvb = NULL;
+    } else {
+      /* First fragment, or not fragmented.  Dissect what we have here. */
+
+      /* Get a tvbuff for the payload. */
+      next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
+
+      /*
+       * If this is the first fragment, but not the only fragment,
+       * tell the next protocol that.
+       */
+      if (more_frags)
+        pinfo->fragmented = TRUE;
+      else
+        pinfo->fragmented = FALSE;
+    }
+  }
+
+  if (next_tvb == NULL) {
+    /* Just show this as a fragment. */
+    if (check_col(pinfo->cinfo, COL_INFO))
+      col_set_str(pinfo->cinfo, COL_INFO, "Fragmented IEEE 802.11 frame");
+    next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
+    call_dissector(data_handle, next_tvb, pinfo, tree);
+    pinfo->fragmented = save_fragmented;
+    return;
+  }
 
-    case DATA_CF_ACK_NOD:
-      COL_SHOW_INFO (pinfo->fd, "Data + Acknowledgement(No data)");
-      break;
+  switch (COOK_FRAME_TYPE (fcf))
+    {
 
+    case MGT_FRAME:
+      dissect_ieee80211_mgt (fcf, next_tvb, pinfo, tree);
+      break;
 
 
-    case DATA_CF_ACK_POLL_NOD:
-      COL_SHOW_INFO (pinfo->fd, "Data + CF-Acknowledgement/Poll (No data)");
+    case DATA_FRAME:
+      /* I guess some bridges take Netware Ethernet_802_3 frames,
+         which are 802.3 frames (with a length field rather than
+         a type field, but with no 802.2 header in the payload),
+         and just stick the payload into an 802.11 frame.  I've seen
+         captures that show frames of that sort.
+
+         This means we have to do the same check for Netware 802.3 -
+         or, if you will, "Netware 802.11" - that we do in the
+         Ethernet dissector, i.e. checking for 0xffff as the first
+         four bytes of the payload and, if we find it, treating it
+         as an IPX frame. */
+      is_802_2 = TRUE;
+      TRY {
+        if (tvb_get_ntohs(next_tvb, 0) == 0xffff)
+          is_802_2 = FALSE;
+      }
+      CATCH2(BoundsError, ReportedBoundsError) {
+           ; /* do nothing */
+
+      }
+      ENDTRY;
+
+      if (is_802_2)
+        call_dissector(llc_handle, next_tvb, pinfo, tree);
+      else
+        call_dissector(ipx_handle, next_tvb, pinfo, tree);
       break;
+    }
+  pinfo->fragmented = save_fragmented;
+}
 
+/*
+ * Dissect 802.11 with a variable-length link-layer header.
+ */
+static void
+dissect_ieee80211 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
+{
+  dissect_ieee80211_common (tvb, pinfo, tree, FALSE, FALSE);
+}
 
+/*
+ * Dissect 802.11 with a variable-length link-layer header and a pseudo-
+ * header containing radio information.
+ */
+static void
+dissect_ieee80211_radio (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
+{
+  dissect_ieee80211_common (tvb, pinfo, tree, FALSE, TRUE);
+}
 
-    default:
-      COL_SHOW_INFO (pinfo->fd, "Unrecognized (Reserved frame)");
-      break;
-    }
+/*
+ * Dissect 802.11 with a fixed-length link-layer header (padded to the
+ * maximum length).
+ */
+static void
+dissect_ieee80211_fixed (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
+{
+  dissect_ieee80211_common (tvb, pinfo, tree, TRUE, FALSE);
 }
 
+static void
+wlan_defragment_init(void)
+{
+  fragment_table_init(&wlan_fragment_table);
+  reassembled_table_init(&wlan_reassembled_table);
+}
 
 void
 proto_register_wlan (void)
 {
+  static const value_string frame_type[] = {
+    {MGT_FRAME,     "Management frame"},
+    {CONTROL_FRAME, "Control frame"},
+    {DATA_FRAME,    "Data frame"},
+    {0,             NULL}
+  };
 
   static const value_string tofrom_ds[] = {
-    {0, "Network operating in AD-HOC mode ( To DS: 0  From DS: 0)"},
-    {1, "Frame is exiting DS (To DS: 0  From DS: 1)"},
-    {2, "Frame is entering DS (To DS: 0  From DS: 1)"},
-    {3, "Frame part of WDS (To DS: 1  From DS: 1)"},
+    {0,                       "Not leaving DS or network is operating in AD-HOC mode (To DS: 0  From DS: 0)"},
+    {FLAG_TO_DS,              "Frame is entering DS (To DS: 1  From DS: 0)"},
+    {FLAG_FROM_DS,            "Frame is exiting DS (To DS: 0  From DS: 1)"},
+    {FLAG_TO_DS|FLAG_FROM_DS, "Frame part of WDS (To DS: 1  From DS: 1)"},
     {0, NULL}
   };
 
@@ -1426,8 +1821,8 @@ proto_register_wlan (void)
   };
 
   static const true_false_string more_frags = {
-    "MSDU/MMPDU is fragmented",
-    "No fragments"
+    "More fragments follow",
+    "This is the last fragment"
   };
 
   static const true_false_string retry_flags = {
@@ -1451,8 +1846,8 @@ proto_register_wlan (void)
   };
 
   static const true_false_string order_flags = {
-    "",
-    ""
+    "Strictly ordered",
+    "Not strictly ordered"
   };
 
   static const true_false_string cf_ess_flags = {
@@ -1466,6 +1861,21 @@ proto_register_wlan (void)
     "AP/STA cannot support WEP"
   };
 
+  static const true_false_string cf_preamble_flags = {
+    "Short preamble allowed",
+    "Short preamble not allowed"
+  };
+
+  static const true_false_string cf_pbcc_flags = {
+    "PBCC modulation allowed",
+    "PBCC modulation not allowed"
+  };
+
+  static const true_false_string cf_agility_flags = {
+    "Channel agility in use",
+    "Channel agility not in use"
+  };
+
 
   static const true_false_string cf_ibss_flags = {
     "Transmitter belongs to an IBSS",
@@ -1539,207 +1949,320 @@ proto_register_wlan (void)
     {0x00, NULL}
   };
 
+  static hf_register_info hf[] = {
+    {&hf_data_rate,
+     {"Data Rate", "wlan.data_rate", FT_UINT8, BASE_DEC, NULL, 0,
+      "Data rate (.5 Mb/s units)", HFILL }},
 
+    {&hf_channel,
+     {"Channel", "wlan.channel", FT_UINT8, BASE_DEC, NULL, 0,
+      "Radio channel", HFILL }},
+
+    {&hf_signal_strength,
+     {"Signal Strength", "wlan.signal_strength", FT_UINT8, BASE_DEC, NULL, 0,
+      "Signal strength (percentage)", HFILL }},
 
-  static hf_register_info hf[] = {
     {&hf_fc_field,
      {"Frame Control Field", "wlan.fc", FT_UINT16, BASE_HEX, NULL, 0,
-      "MAC Frame control"}},
+      "MAC Frame control", HFILL }},
 
     {&hf_fc_proto_version,
      {"Version", "wlan.fc.version", FT_UINT8, BASE_DEC, NULL, 0,
-      "MAC Protocol version"}},        /* 0 */
+      "MAC Protocol version", HFILL }},        /* 0 */
 
     {&hf_fc_frame_type,
-     {"Type", "wlan.fc.type", FT_UINT8, BASE_DEC, NULL, 0,
-      "Frame type"}},
+     {"Type", "wlan.fc.type", FT_UINT8, BASE_DEC, VALS(frame_type), 0,
+      "Frame type", HFILL }},
 
     {&hf_fc_frame_subtype,
      {"Subtype", "wlan.fc.subtype", FT_UINT8, BASE_DEC, NULL, 0,
-      "Frame subtype"}},       /* 2 */
+      "Frame subtype", HFILL }},       /* 2 */
+
+    {&hf_fc_frame_type_subtype,
+     {"Type/Subtype", "wlan.fc.type_subtype", FT_UINT16, BASE_DEC, VALS(frame_type_subtype_vals), 0,
+      "Type and subtype combined", HFILL }},
 
     {&hf_fc_flags,
      {"Protocol Flags", "wlan.flags", FT_UINT8, BASE_HEX, NULL, 0,
-      "Protocol flags"}},
+      "Protocol flags", HFILL }},
 
     {&hf_fc_data_ds,
-     {"DS status", "wlan.fc.ds", FT_UINT8, BASE_HEX, TFS (&tofrom_ds), 0,
-      "Data-frame DS-traversal status"}},      /* 3 */
+     {"DS status", "wlan.fc.ds", FT_UINT8, BASE_HEX, VALS (&tofrom_ds), 0,
+      "Data-frame DS-traversal status", HFILL }},      /* 3 */
 
     {&hf_fc_to_ds,
-     {"To DS", "wlan.fc.tods", FT_BOOLEAN, 8, TFS (&tods_flag), 0x1,
-      "To DS flag"}},          /* 4 */
+     {"To DS", "wlan.fc.tods", FT_BOOLEAN, 8, TFS (&tods_flag), FLAG_TO_DS,
+      "To DS flag", HFILL }},          /* 4 */
 
     {&hf_fc_from_ds,
-     {"From DS", "wlan.fc.fromds", FT_BOOLEAN, 8, TFS (&fromds_flag), 0x2,
-      "From DS flag"}},                /* 5 */
+     {"From DS", "wlan.fc.fromds", FT_BOOLEAN, 8, TFS (&fromds_flag), FLAG_FROM_DS,
+      "From DS flag", HFILL }},                /* 5 */
 
     {&hf_fc_more_frag,
-     {"Fragments", "wlan.fc.frag", FT_BOOLEAN, 8, TFS (&more_frags), 0x4,
-      "More Fragments flag"}}, /* 6 */
+     {"More Fragments", "wlan.fc.frag", FT_BOOLEAN, 8, TFS (&more_frags), FLAG_MORE_FRAGMENTS,
+      "More Fragments flag", HFILL }}, /* 6 */
 
     {&hf_fc_retry,
-     {"Retry", "wlan.fc.retry", FT_BOOLEAN, 8, TFS (&retry_flags), 0x8,
-      "Retransmission flag"}},
+     {"Retry", "wlan.fc.retry", FT_BOOLEAN, 8, TFS (&retry_flags), FLAG_RETRY,
+      "Retransmission flag", HFILL }},
 
     {&hf_fc_pwr_mgt,
-     {"PWR MGT", "wlan.fc.pwrmgt", FT_BOOLEAN, 8, TFS (&pm_flags), 0x10,
-      "Power management status"}},
+     {"PWR MGT", "wlan.fc.pwrmgt", FT_BOOLEAN, 8, TFS (&pm_flags), FLAG_POWER_MGT,
+      "Power management status", HFILL }},
 
     {&hf_fc_more_data,
-     {"More Data", "wlan.fc.moredata", FT_BOOLEAN, 8, TFS (&md_flags), 0x20,
-      "More data flag"}},
+     {"More Data", "wlan.fc.moredata", FT_BOOLEAN, 8, TFS (&md_flags), FLAG_MORE_DATA,
+      "More data flag", HFILL }},
 
     {&hf_fc_wep,
-     {"WEP flag", "wlan.fc.wep", FT_BOOLEAN, 8, TFS (&wep_flags), 0x40,
-      "WEP flag"}},
+     {"WEP flag", "wlan.fc.wep", FT_BOOLEAN, 8, TFS (&wep_flags), FLAG_WEP,
+      "WEP flag", HFILL }},
 
     {&hf_fc_order,
-     {"Order flag", "wlan.fc.order", FT_BOOLEAN, 8, TFS (&order_flags), 0x80,
-      "Strictly ordered flag"}},
+     {"Order flag", "wlan.fc.order", FT_BOOLEAN, 8, TFS (&order_flags), FLAG_ORDER,
+      "Strictly ordered flag", HFILL }},
+
+    {&hf_assoc_id,
+     {"Association ID","wlan.aid",FT_UINT16, BASE_DEC,NULL,0,
+      "Association-ID field", HFILL }},
 
     {&hf_did_duration,
      {"Duration", "wlan.duration", FT_UINT16, BASE_DEC, NULL, 0,
-      "Duration field"}},
+      "Duration field", HFILL }},
 
     {&hf_addr_da,
      {"Destination address", "wlan.da", FT_ETHER, BASE_NONE, NULL, 0,
-      "Destination Hardware address"}},
+      "Destination Hardware Address", HFILL }},
 
     {&hf_addr_sa,
      {"Source address", "wlan.sa", FT_ETHER, BASE_NONE, NULL, 0,
-      "Source Hardware address"}},
+      "Source Hardware Address", HFILL }},
+
+    { &hf_addr,
+      {"Source or Destination address", "wlan.addr", FT_ETHER, BASE_NONE, NULL, 0,
+       "Source or Destination Hardware Address", HFILL }},
 
     {&hf_addr_ra,
      {"Receiver address", "wlan.ra", FT_ETHER, BASE_NONE, NULL, 0,
-      "Receiving Station Hardware Address"}},
+      "Receiving Station Hardware Address", HFILL }},
 
     {&hf_addr_ta,
      {"Transmitter address", "wlan.ta", FT_ETHER, BASE_NONE, NULL, 0,
-      "Transmitting Station Hardware Address"}},
+      "Transmitting Station Hardware Address", HFILL }},
 
     {&hf_addr_bssid,
      {"BSS Id", "wlan.bssid", FT_ETHER, BASE_NONE, NULL, 0,
-      "Basic Service Set ID"}},
+      "Basic Service Set ID", HFILL }},
 
     {&hf_frag_number,
-     {"Fragment number", "wlan.frag", FT_UINT16, BASE_HEX, NULL, 0,
-      "Fragment number"}},
+     {"Fragment number", "wlan.frag", FT_UINT16, BASE_DEC, NULL, 0,
+      "Fragment number", HFILL }},
 
     {&hf_seq_number,
-     {"Sequence number", "wlan.seq", FT_UINT16, BASE_HEX, NULL, 0,
-      "Fragment number"}},
+     {"Sequence number", "wlan.seq", FT_UINT16, BASE_DEC, NULL, 0,
+      "Sequence number", HFILL }},
 
     {&hf_fcs,
      {"Frame Check Sequence (not verified)", "wlan.fcs", FT_UINT32, BASE_HEX,
-      NULL, 0, ""}},
+      NULL, 0, "", HFILL }},
+
+    {&hf_fragment_overlap,
+      {"Fragment overlap", "wlan.fragment.overlap", FT_BOOLEAN, BASE_NONE,
+       NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
+
+    {&hf_fragment_overlap_conflict,
+      {"Conflicting data in fragment overlap", "wlan.fragment.overlap.conflict",
+       FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+       "Overlapping fragments contained conflicting data", HFILL }},
+
+    {&hf_fragment_multiple_tails,
+      {"Multiple tail fragments found", "wlan.fragment.multipletails",
+       FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+       "Several tails were found when defragmenting the packet", HFILL }},
+
+    {&hf_fragment_too_long_fragment,
+      {"Fragment too long", "wlan.fragment.toolongfragment",
+       FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+       "Fragment contained data past end of packet", HFILL }},
+
+    {&hf_fragment_error,
+      {"Defragmentation error", "wlan.fragment.error",
+       FT_NONE, BASE_NONE, NULL, 0x0,
+       "Defragmentation error due to illegal fragments", HFILL }},
+
+    {&hf_fragment,
+      {"802.11 Fragment", "wlan.fragment", FT_NONE, BASE_NONE, NULL, 0x0,
+       "802.11 Fragment", HFILL }},
+
+    {&hf_fragments,
+      {"802.11 Fragments", "wlan.fragments", FT_NONE, BASE_NONE, NULL, 0x0,
+       "WTP Fragments", HFILL }},
+
+    {&hf_wep_iv,
+     {"Initialization Vector", "wlan.wep.iv", FT_UINT24, BASE_HEX, NULL, 0,
+      "Initialization Vector", HFILL }},
+
+    {&hf_wep_key,
+     {"Key", "wlan.wep.key", FT_UINT8, BASE_DEC, NULL, 0,
+      "Key", HFILL }},
+
+    {&hf_wep_crc,
+     {"WEP CRC (not verified)", "wlan.wep.crc", FT_UINT32, BASE_HEX, NULL, 0,
+      "WEP CRC", HFILL }},
+  };
 
+  static hf_register_info ff[] = {
     {&ff_timestamp,
-     {"Timestamp", "wlan.fixed.timestamp", FT_STRING, BASE_NONE,
-      NULL, 0, ""}},
+     {"Timestamp", "wlan_mgt.fixed.timestamp", FT_STRING, BASE_NONE,
+      NULL, 0, "", HFILL }},
 
     {&ff_auth_alg,
-     {"Authentication Algorithm", "wlan.fixed.auth.alg",
-      FT_UINT16, BASE_DEC, VALS (&auth_alg), 0, ""}},
+     {"Authentication Algorithm", "wlan_mgt.fixed.auth.alg",
+      FT_UINT16, BASE_DEC, VALS (&auth_alg), 0, "", HFILL }},
 
     {&ff_beacon_interval,
-     {"Beacon Interval", "wlan.fixed.beacon", FT_UINT16, BASE_DEC, NULL, 0,
-      ""}},
+     {"Beacon Interval", "wlan_mgt.fixed.beacon", FT_DOUBLE, BASE_DEC, NULL, 0,
+      "", HFILL }},
 
     {&hf_fixed_parameters,
-     {"Fixed parameters", "wlan.fixed.all", FT_UINT16, BASE_DEC, NULL, 0,
-      ""}},
+     {"Fixed parameters", "wlan_mgt.fixed.all", FT_UINT16, BASE_DEC, NULL, 0,
+      "", HFILL }},
 
     {&hf_tagged_parameters,
-     {"Tagged parameters", "wlan.tagged.all", FT_UINT16, BASE_DEC, NULL, 0,
-      ""}},
+     {"Tagged parameters", "wlan_mgt.tagged.all", FT_UINT16, BASE_DEC, NULL, 0,
+      "", HFILL }},
 
     {&ff_capture,
-     {"Capabilities", "wlan.fixed.capabilities", FT_UINT16, BASE_HEX, NULL, 0,
-      "Capability information"}},
+     {"Capabilities", "wlan_mgt.fixed.capabilities", FT_UINT16, BASE_HEX, NULL, 0,
+      "Capability information", HFILL }},
 
     {&ff_cf_sta_poll,
-     {"CFP participation capabilities", "wlan.fixed.capabilities.cfpoll.sta",
+     {"CFP participation capabilities", "wlan_mgt.fixed.capabilities.cfpoll.sta",
       FT_UINT16, BASE_HEX, VALS (&sta_cf_pollable), 0,
-      "CF-Poll capabilities for a STA"}},
+      "CF-Poll capabilities for a STA", HFILL }},
 
     {&ff_cf_ap_poll,
-     {"CFP participation capabilities", "wlan.fixed.capabilities.cfpoll.ap",
+     {"CFP participation capabilities", "wlan_mgt.fixed.capabilities.cfpoll.ap",
       FT_UINT16, BASE_HEX, VALS (&ap_cf_pollable), 0,
-      "CF-Poll capabilities for an AP"}},
+      "CF-Poll capabilities for an AP", HFILL }},
 
     {&ff_cf_ess,
-     {"ESS capabilities", "wlan.fixed.capabilities.ess",
-      FT_BOOLEAN, 1, TFS (&cf_ess_flags), 0x0001, "ESS capabilities"}},
+     {"ESS capabilities", "wlan_mgt.fixed.capabilities.ess",
+      FT_BOOLEAN, 8, TFS (&cf_ess_flags), 0x0001, "ESS capabilities", HFILL }},
 
 
     {&ff_cf_ibss,
-     {"IBSS status", "wlan.fixed.capabilities.ibss",
-      FT_BOOLEAN, 1, TFS (&cf_ibss_flags), 0x0002, "IBSS participation"}},
+     {"IBSS status", "wlan_mgt.fixed.capabilities.ibss",
+      FT_BOOLEAN, 8, TFS (&cf_ibss_flags), 0x0002, "IBSS participation", HFILL }},
 
     {&ff_cf_privacy,
-     {"Privacy", "wlan.fixed.capabilities.privacy",
-      FT_BOOLEAN, 1, TFS (&cf_privacy_flags), 0x0010, "WEP support"}},
+     {"Privacy", "wlan_mgt.fixed.capabilities.privacy",
+      FT_BOOLEAN, 8, TFS (&cf_privacy_flags), 0x0010, "WEP support", HFILL }},
+
+    {&ff_cf_preamble,
+     {"Short Preamble", "wlan_mgt.fixed.capabilities.preamble",
+      FT_BOOLEAN, 8, TFS (&cf_preamble_flags), 0x0020, "Short Preamble", HFILL }},
 
+    {&ff_cf_pbcc,
+     {"PBCC", "wlan_mgt.fixed.capabilities.pbcc",
+      FT_BOOLEAN, 8, TFS (&cf_pbcc_flags), 0x0040, "PBCC Modulation", HFILL }},
+
+    {&ff_cf_agility,
+     {"Channel Agility", "wlan_mgt.fixed.capabilities.agility",
+      FT_BOOLEAN, 8, TFS (&cf_agility_flags), 0x0080, "Channel Agility", HFILL }},
 
     {&ff_auth_seq,
-     {"Authentication SEQ", "wlan.fixed.auth_seq",
-      FT_UINT16, BASE_HEX, NULL, 0, "Authentication sequence number"}},
+     {"Authentication SEQ", "wlan_mgt.fixed.auth_seq",
+      FT_UINT16, BASE_HEX, NULL, 0, "Authentication sequence number", HFILL }},
 
     {&ff_assoc_id,
-     {"Association ID", "wlan.fixed.aid",
-      FT_UINT16, BASE_HEX, NULL, 0, "Association ID"}},
+     {"Association ID", "wlan_mgt.fixed.aid",
+      FT_UINT16, BASE_HEX, NULL, 0, "Association ID", HFILL }},
 
     {&ff_listen_ival,
-     {"Listen Interval", "wlan.fixed.listen_ival",
-      FT_UINT16, BASE_HEX, NULL, 0, "Listen Interval"}},
+     {"Listen Interval", "wlan_mgt.fixed.listen_ival",
+      FT_UINT16, BASE_HEX, NULL, 0, "Listen Interval", HFILL }},
 
     {&ff_current_ap,
-     {"Current AP", "wlan.fixed.current_ap",
-      FT_ETHER, BASE_NONE, NULL, 0, "MAC address of current AP"}},
+     {"Current AP", "wlan_mgt.fixed.current_ap",
+      FT_ETHER, BASE_NONE, NULL, 0, "MAC address of current AP", HFILL }},
 
     {&ff_reason,
-     {"Reason code", "wlan.fixed.reason_code",
+     {"Reason code", "wlan_mgt.fixed.reason_code",
       FT_UINT16, BASE_HEX, VALS (&reason_codes), 0,
-      "Reason for unsolicited notification"}},
+      "Reason for unsolicited notification", HFILL }},
 
     {&ff_status_code,
-     {"Status code", "wlan.fixed.status_code",
+     {"Status code", "wlan_mgt.fixed.status_code",
       FT_UINT16, BASE_HEX, VALS (&status_codes), 0,
-      "Status of requested event"}},
+      "Status of requested event", HFILL }},
 
     {&tag_number,
-     {"Tag", "wlan.tag.number",
+     {"Tag", "wlan_mgt.tag.number",
       FT_UINT16, BASE_DEC, NULL, 0,
-      "Element ID"}},
+      "Element ID", HFILL }},
 
     {&tag_length,
-     {"Tag length", "wlan.tag.length",
-      FT_UINT16, BASE_DEC, NULL, 0, "Length of tag"}},
+     {"Tag length", "wlan_mgt.tag.length",
+      FT_UINT16, BASE_DEC, NULL, 0, "Length of tag", HFILL }},
 
     {&tag_interpretation,
-     {"Tag interpretation", "wlan.tag.interpretation",
-      FT_STRING, BASE_NONE, NULL, 0, "Interpretation of tag"}}
-
+     {"Tag interpretation", "wlan_mgt.tag.interpretation",
+      FT_STRING, BASE_NONE, NULL, 0, "Interpretation of tag", HFILL }}
 
   };
 
-
-  static gint *tree_array[] = { &ett_80211,
+  static gint *tree_array[] = {
+    &ett_80211,
     &ett_fc_tree,
     &ett_proto_flags,
+    &ett_fragments,
+    &ett_fragment,
+    &ett_80211_mgt,
     &ett_fixed_parameters,
     &ett_tagged_parameters,
+    &ett_wep_parameters,
     &ett_cap_tree,
   };
+  module_t *wlan_module;
 
-  proto_wlan = proto_register_protocol ("IEEE 802.11 wireless LAN", "wlan");
+  proto_wlan = proto_register_protocol ("IEEE 802.11 wireless LAN",
+                                       "IEEE 802.11", "wlan");
   proto_register_field_array (proto_wlan, hf, array_length (hf));
+  proto_wlan_mgt = proto_register_protocol ("IEEE 802.11 wireless LAN management frame",
+                                       "802.11 MGT", "wlan_mgt");
+  proto_register_field_array (proto_wlan_mgt, ff, array_length (ff));
   proto_register_subtree_array (tree_array, array_length (tree_array));
+
+  register_dissector("wlan", dissect_ieee80211, proto_wlan);
+  register_dissector("wlan_fixed", dissect_ieee80211_fixed, proto_wlan);
+  register_init_routine(wlan_defragment_init);
+
+  /* Register configuration options */
+  wlan_module = prefs_register_protocol(proto_wlan, NULL);
+  prefs_register_bool_preference(wlan_module, "defragment",
+       "Reassemble fragmented 802.11 datagrams",
+       "Whether fragmented 802.11 datagrams should be reassembled",
+       &wlan_defragment);
 }
 
 void
 proto_reg_handoff_wlan(void)
 {
-       dissector_add("wtap_encap", WTAP_ENCAP_IEEE_802_11, dissect_ieee80211);
+  dissector_handle_t ieee80211_handle;
+  dissector_handle_t ieee80211_radio_handle;
+
+  /*
+   * Get handles for the LLC and IPX dissectors.
+   */
+  llc_handle = find_dissector("llc");
+  ipx_handle = find_dissector("ipx");
+  data_handle = find_dissector("data");
+
+  ieee80211_handle = find_dissector("wlan");
+  dissector_add("wtap_encap", WTAP_ENCAP_IEEE_802_11, ieee80211_handle);
+  ieee80211_radio_handle = create_dissector_handle(dissect_ieee80211_radio,
+                                                  proto_wlan);
+  dissector_add("wtap_encap", WTAP_ENCAP_IEEE_802_11_WITH_RADIO,
+               ieee80211_radio_handle);
 }