Put the IGMP type field value into the PIM tree, as is done for other
[obnox/wireshark/wip.git] / packet-ieee80211.c
index 1144f45b49447c16dee16d124542b599e31ea852..09727c5b8657964a1ee4f4ec8e5b901306357f25 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright 2000, Axis Communications AB 
  * Inquiries/bugreports should be sent to Johan.Jorgensen@axis.com
  *
- * $Id: packet-ieee80211.c,v 1.27 2001/06/20 22:26:07 guy Exp $
+ * $Id: packet-ieee80211.c,v 1.36 2001/06/22 08:12:11 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -73,7 +73,6 @@
 /*                          Miscellaneous Constants                          */
 /* ************************************************************************* */
 #define SHORT_STR 128
-#define MGT_FRAME_LEN 24
 
 /* ************************************************************************* */
 /*  Define some very useful macros that are used to analyze frame types etc. */
 #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_IV(x)        ((x) & 0xFFFFFF)
-#define COOK_WEP_KEY(x)       (((x) & 0xC0000000) >> 30)
+#define COOK_WEP_KEY(x)       (((x) & 0xC0) >> 6)
 #define COL_SHOW_INFO(fd,info) if (check_col(fd,COL_INFO)) \
                                col_add_str(fd,COL_INFO,info);
 #define COL_SHOW_INFO_CONST(fd,info) if (check_col(fd,COL_INFO)) \
                                col_set_str(fd,COL_INFO,info);
 
-#define IS_TO_DS(x)            ((x) & 0x01)
-#define IS_FROM_DS(x)          ((x) & 0x02)
-#define HAVE_FRAGMENTS(x)      ((x) & 0x04)
-#define IS_RETRY(x)            ((x) & 0x08)
-#define POWER_MGT_STATUS(x)    ((x) & 0x10)
-#define HAS_MORE_DATA(x)       ((x) & 0x20)
-#define IS_WEP(x)              ((x) & 0x40)
-#define IS_STRICTLY_ORDERED(x) ((x) & 0x80)
+#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_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      */
 #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         0x0000
-#define DATA_ADDR_T2         0x0100
-#define DATA_ADDR_T3         0x0200
-#define DATA_ADDR_T4         0x0300
+#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)
 
 
 /* ************************************************************************* */
 #define TAG_IBSS_PARAMETER 0x06
 #define TAG_CHALLENGE_TEXT 0x10
 
+/* ************************************************************************* */
+/*                         Frame types, and their names                      */
+/* ************************************************************************* */
+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;
 /* ************************************************************************* */
@@ -198,6 +236,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;
@@ -242,6 +281,8 @@ static int hf_seq_number = -1;
 static int hf_fcs = -1;
 
 
+
+static int proto_wlan_mgt = -1;
 /* ************************************************************************* */
 /*                      Fixed fields found in mgt frames                     */
 /* ************************************************************************* */
@@ -279,7 +320,6 @@ 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_parameters = -1;
 static int hf_wep_iv = -1;
 static int hf_wep_key = -1;
 static int hf_wep_crc = -1;
@@ -291,6 +331,8 @@ 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_80211_mgt = -1;
 static gint ett_fixed_parameters = -1;
 static gint ett_tagged_parameters = -1;
 static gint ett_wep_parameters = -1;
@@ -300,10 +342,35 @@ static dissector_handle_t llc_handle;
 /* ************************************************************************* */
 /*            Return the length of the current header (in bytes)             */
 /* ************************************************************************* */
-int
+static int
 find_header_length (guint16 fcf)
 {
-  return (COOK_ADDR_SELECTOR(fcf) == DATA_ADDR_T4) ? 30 : 24;
+  switch (COOK_FRAME_TYPE (fcf)) {
+
+  case MGT_FRAME:
+    return MGT_FRAME_HDR_LEN;
+
+  case CONTROL_FRAME:
+    switch (COMPOSE_FRAME_TYPE (fcf)) {
+
+    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 */
+  }
 }
 
 
@@ -327,20 +394,8 @@ capture_ieee80211 (const u_char * pd, int offset, packet_counts * ld)
     {
 
     case DATA:                 /* We got a data frame */
-      hdr_length = find_header_length (fcf);
-      capture_llc (pd, offset + hdr_length, ld);
-      break;
-
     case DATA_CF_ACK:          /* Data with ACK */
-      hdr_length = find_header_length (fcf);
-      capture_llc (pd, offset + hdr_length, ld);
-      break;
-
     case DATA_CF_POLL:
-      hdr_length = find_header_length (fcf);
-      capture_llc (pd, offset + hdr_length, ld);
-      break;
-
     case DATA_CF_ACK_POLL:
       hdr_length = find_header_length (fcf);
       capture_llc (pd, offset + hdr_length, ld);
@@ -393,22 +448,20 @@ get_tagged_parameter_tree (proto_tree * tree, tvbuff_t *tvb, int start, int size
 /* ************************************************************************* */
 /*            Add the subtree used to store WEP parameters                   */
 /* ************************************************************************* */
-void
+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_string_format(tree, hf_wep_parameters, tvb,
-                                           0, 4, 0, "WEP parameters");
+  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_uint (wep_tree, hf_wep_iv, tvb, start, 3,
-                      COOK_WEP_IV (tvb_get_letohl (tvb, start)));
+  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_letohl (tvb, start)));
+                      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,
@@ -423,7 +476,7 @@ add_fixed_field (proto_tree * tree, tvbuff_t * tvb, int offset, int lfcode)
 {
   const guint8 *dataptr;
   char out_buff[SHORT_STR];
-  guint16 *temp16;
+  guint16 capability;
   proto_item *cap_item;
   static proto_tree *cap_tree;
   double temp_double;
@@ -446,10 +499,8 @@ add_fixed_field (proto_tree * tree, tvbuff_t * tvb, int offset, int lfcode)
       proto_tree_add_string (tree, ff_timestamp, tvb, offset, 8, out_buff);
       break;
 
-
     case FIELD_BEACON_INTERVAL:
-      dataptr = tvb_get_ptr (tvb, offset, 2);
-      temp_double = ((double) *((guint16 *) dataptr));
+      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]",
@@ -458,85 +509,61 @@ add_fixed_field (proto_tree * tree, tvbuff_t * tvb, int offset, int lfcode)
 
 
     case FIELD_CAP_INFO:
-      dataptr = tvb_get_ptr (tvb, offset, 2);
-      temp16 = (guint16 *) dataptr;
+      capability = tvb_get_letohs (tvb, offset);
 
       cap_item = proto_tree_add_uint_format (tree, ff_capture, 
                                             tvb, offset, 2,
-                                            pletohs (temp16),
+                                            capability,
                                             "Capability Information: 0x%04X",
-                                            pletohs (temp16));
+                                            capability);
       cap_tree = proto_item_add_subtree (cap_item, ett_cap_tree);
       proto_tree_add_boolean (cap_tree, ff_cf_ess, tvb, offset, 1,
-                             pletohs (temp16));
+                             capability);
       proto_tree_add_boolean (cap_tree, ff_cf_ibss, tvb, offset, 1,
-                             pletohs (temp16));
+                             capability);
       proto_tree_add_boolean (cap_tree, ff_cf_privacy, tvb, offset, 1,
-                             pletohs (temp16));
+                             capability);
       proto_tree_add_boolean (cap_tree, ff_cf_preamble, tvb, offset, 1,
-                             pletohs (temp16));
+                             capability);
       proto_tree_add_boolean (cap_tree, ff_cf_pbcc, tvb, offset, 1,
-                             pletohs (temp16));
+                             capability);
       proto_tree_add_boolean (cap_tree, ff_cf_agility, tvb, offset, 1,
-                             pletohs (temp16));
-      if (ESS_SET (pletohs (temp16)) != 0)     /* This is an AP */
+                             capability);
+      if (ESS_SET (capability) != 0)   /* This is an AP */
        proto_tree_add_uint (cap_tree, ff_cf_ap_poll, tvb, offset, 2,
-                            ((pletohs (temp16) & 0xC) >> 2));
+                            ((capability & 0xC) >> 2));
 
       else                     /* This is a STA */
        proto_tree_add_uint (cap_tree, ff_cf_sta_poll, tvb, offset, 2,
-                            ((pletohs (temp16) & 0xC) >> 2));
+                            ((capability & 0xC) >> 2));
       break;
 
-
     case FIELD_AUTH_ALG:
-      dataptr = tvb_get_ptr (tvb, offset, 2);
-      temp16 =(guint16 *) dataptr;
-      proto_tree_add_uint (tree, ff_auth_alg, tvb, offset, 2,
-                          pletohs (temp16));
+      proto_tree_add_uint (tree, ff_auth_alg, tvb, offset, 2, TRUE);
       break;
 
-
     case FIELD_AUTH_TRANS_SEQ:
-      dataptr = tvb_get_ptr (tvb, offset, 2);
-      temp16 = (guint16 *)dataptr;
-      proto_tree_add_uint (tree, ff_auth_seq, tvb, offset, 2,
-                          pletohs (temp16));
+      proto_tree_add_uint (tree, ff_auth_seq, tvb, offset, 2, TRUE);
       break;
 
-
     case FIELD_CURRENT_AP_ADDR:
-      dataptr = tvb_get_ptr (tvb, offset, 6);
-      proto_tree_add_ether (tree, ff_current_ap, tvb, offset, 6, dataptr);
+      proto_tree_add_item (tree, ff_current_ap, tvb, offset, 6, FALSE);
       break;
 
-
     case FIELD_LISTEN_IVAL:
-      dataptr = tvb_get_ptr (tvb, offset, 2);
-      temp16 = (guint16 *) dataptr;
-      proto_tree_add_uint (tree, ff_listen_ival, tvb, offset, 2,
-                          pletohs (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);
-      temp16 = (guint16 *) dataptr;
-      proto_tree_add_uint (tree, ff_reason, tvb, offset, 2, pletohs (temp16));
+      proto_tree_add_item (tree, ff_reason, tvb, offset, 2, TRUE);
       break;
 
-
     case FIELD_ASSOC_ID:
-      dataptr = tvb_get_ptr (tvb, offset, 2);
-      temp16 = (guint16 *) dataptr;
-      proto_tree_add_uint (tree, ff_assoc_id, tvb, offset, 2, pletohs (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);
-      temp16 = (guint16 *) dataptr;
-      proto_tree_add_uint (tree, ff_status_code, tvb, offset, 2,
-                          pletohs (temp16));
+      proto_tree_add_item (tree, ff_status_code, tvb, offset, 2, TRUE);
       break;
     }
 }
@@ -548,7 +575,6 @@ 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)
 {
-  const guint8 *tag_info_ptr;
   const guint8 *tag_data_ptr;
   guint32 tag_no, tag_len;
   unsigned int i;
@@ -556,9 +582,8 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
   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);
 
@@ -591,7 +616,7 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
     }
 
 
-  switch (tag_info_ptr[0])
+  switch (tag_no)
     {
 
 
@@ -740,6 +765,218 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
   return tag_len + 2;
 }
 
+/* ************************************************************************* */
+/*                     Dissect 802.11 management frame                       */
+/* ************************************************************************* */
+static void
+dissect_ieee80211_mgt (guint16 fcf, tvbuff_t * tvb, packet_info * pinfo,
+       proto_tree * tree)
+{
+  proto_item *ti = NULL;
+  proto_tree *mgt_tree;
+  proto_tree *fixed_tree;
+  proto_tree *tagged_tree;
+  guint32 next_idx;
+  guint32 next_len;
+  int tagged_parameter_tree_len;
+
+  CHECK_DISPLAY_AS_DATA(proto_wlan_mgt, tvb, pinfo, tree);
+
+  if (tree)
+    {
+      ti = proto_tree_add_item (tree, proto_wlan_mgt, tvb, 0, tvb_length(tvb), FALSE);
+      mgt_tree = proto_item_add_subtree (ti, ett_80211_mgt);
+
+      switch (COMPOSE_FRAME_TYPE(fcf))
+       {
+
+       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);
+
+         next_idx = 4; /* Size of fixed fields */
+         tagged_parameter_tree_len =
+             tvb_reported_length_remaining(tvb, next_idx + 4);
+         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 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);
+
+         next_idx = 6; /* Size of fixed fields */
+
+         tagged_parameter_tree_len =
+             tvb_reported_length_remaining(tvb, next_idx + 4);
+         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 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);
+
+         next_idx = 10;        /* Size of fixed fields */
+         tagged_parameter_tree_len =
+             tvb_reported_length_remaining(tvb, next_idx + 4);
+         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 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);
+
+         next_idx = 6; /* Size of fixed fields */
+         tagged_parameter_tree_len =
+             tvb_reported_length_remaining(tvb, next_idx + 4);
+         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 MGT_PROBE_REQ:
+         next_idx = 0;
+         tagged_parameter_tree_len =
+             tvb_reported_length_remaining(tvb, next_idx + 4);
+         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 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);
+
+         next_idx = 12;        /* Size of fixed fields */
+         tagged_parameter_tree_len =
+             tvb_reported_length_remaining(tvb, next_idx + 4);
+         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 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 + 4);
+         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 MGT_ATIM:
+         break;
+
+
+       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 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 */
+
+         tagged_parameter_tree_len =
+                 tvb_reported_length_remaining(tvb, next_idx + 4);
+         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 MGT_DEAUTHENTICATION:
+         fixed_tree = get_fixed_parameter_tree (mgt_tree, tvb, 0, 2);
+         add_fixed_field (fixed_tree, tvb, 0, FIELD_REASON_CODE);
+         break;
+       }
+    }
+}
+
 static void
 set_src_addr_cols(packet_info *pinfo, const guint8 *addr, char *type)
 {
@@ -768,31 +1005,30 @@ set_dst_addr_cols(packet_info *pinfo, const guint8 *addr, char *type)
 static void
 dissect_ieee80211 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
 {
-  guint16 fcf, flags;
+  guint16 fcf, flags, frame_type_subtype;
   const guint8 *src = NULL, *dst = NULL;
-  proto_item *ti;
+  proto_item *ti = NULL;
   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;
+  proto_tree *hdr_tree = NULL;
+  proto_tree *flag_tree;
+  proto_tree *fc_tree;
+  guint16 hdr_len;
   tvbuff_t *next_tvb;
-  guint32 next_idx;
   guint32 addr_type;
-  guint32 next_len;
-  int tagged_parameter_tree_len;
 
   if (check_col (pinfo->fd, COL_PROTOCOL))
     col_set_str (pinfo->fd, COL_PROTOCOL, "IEEE 802.11");
   if (check_col (pinfo->fd, COL_INFO))
     col_clear (pinfo->fd, COL_INFO);
 
-  cap_len = tvb_length(tvb);
   fcf = tvb_get_letohs (tvb, 0);
   hdr_len = find_header_length (fcf);
+  frame_type_subtype = COMPOSE_FRAME_TYPE(fcf);
+
+  COL_SHOW_INFO_CONST (pinfo->fd,
+      val_to_str(frame_type_subtype, frame_type_subtype_vals,
+          "Unrecognized (Reserved frame)"));
 
   /* Add the FC to the current tree */
   if (tree)
@@ -801,6 +1037,10 @@ dissect_ieee80211 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
                                           "IEEE 802.11");
       hdr_tree = proto_item_add_subtree (ti, ett_80211);
 
+      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",
@@ -844,7 +1084,7 @@ dissect_ieee80211 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
 
       proto_tree_add_boolean (flag_tree, hf_fc_order, tvb, 1, 1, flags);
 
-      if ((COMPOSE_FRAME_TYPE(fcf))==CTRL_PS_POLL) 
+      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)));
      
@@ -853,11 +1093,27 @@ dissect_ieee80211 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
                               tvb_get_letohs (tvb, 2));
     }
 
-  /* Perform tasks which are common to a certain frame type */
-  switch (COOK_FRAME_TYPE (fcf))
+  /*
+   * Decode the part of the frame header that isn't the same for all
+   * frame types.
+   */
+  switch (frame_type_subtype)
     {
 
-    case MGT_FRAME:            /* All management frames share a common header */
+    case MGT_ASSOC_REQ:
+    case MGT_ASSOC_RESP:
+    case MGT_REASSOC_REQ:
+    case MGT_REASSOC_RESP:
+    case MGT_PROBE_REQ:
+    case MGT_PROBE_RESP:
+    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);
 
@@ -868,11 +1124,9 @@ dissect_ieee80211 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
 
       if (tree)
        {
-         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_da, tvb, 4, 6, dst);
 
-         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_sa, tvb, 10, 6, src);
 
          proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 16, 6,
                                tvb_get_ptr (tvb, 16, 6));
@@ -884,71 +1138,148 @@ dissect_ieee80211 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
          proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
                               COOK_SEQUENCE_NUMBER (tvb_get_letohs
                                                     (tvb, 22)));
-         cap_len = cap_len - MGT_FRAME_LEN - 4;
        }
       break;
 
 
+    case CTRL_PS_POLL:
+      src = tvb_get_ptr (tvb, 10, 6);
+      dst = tvb_get_ptr (tvb, 4, 6);
+
+      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, dst);
 
-    case CONTROL_FRAME:
+         proto_tree_add_ether (hdr_tree, hf_addr_ta, tvb, 10, 6, src);
+       }
       break;
 
 
+    case CTRL_RTS:
+      src = tvb_get_ptr (tvb, 10, 6);
+      dst = tvb_get_ptr (tvb, 4, 6);
 
-    case DATA_FRAME:
-      addr_type = COOK_ADDR_SELECTOR (fcf);
+      set_src_addr_cols(pinfo, src, "TA");
+      set_dst_addr_cols(pinfo, dst, "RA");
 
-      /* In order to show src/dst address we must always do the following */
-      switch (addr_type)
+      if (tree)
        {
+         proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6, dst);
 
-       case DATA_ADDR_T1:
-         src = tvb_get_ptr (tvb, 10, 6);
-         dst = tvb_get_ptr (tvb, 4, 6);
-         break;
+         proto_tree_add_ether (hdr_tree, hf_addr_ta, tvb, 10, 6, src);
+       }
+      break;
 
 
-       case DATA_ADDR_T2:
-         src = tvb_get_ptr (tvb, 16, 6);
-         dst = tvb_get_ptr (tvb, 4, 6);
-         break;
+    case CTRL_CTS:
+      dst = tvb_get_ptr (tvb, 4, 6);
 
+      set_dst_addr_cols(pinfo, dst, "RA");
 
-       case DATA_ADDR_T3:
-         src = tvb_get_ptr (tvb, 10, 6);
-         dst = tvb_get_ptr (tvb, 16, 6);
-         break;
+      if (tree)
+         proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6, dst);
+      break;
 
 
-       case DATA_ADDR_T4:
-         src = tvb_get_ptr (tvb, 24, 6);
-         dst = tvb_get_ptr (tvb, 16, 6);
-         break;
-       }
+    case CTRL_ACKNOWLEDGEMENT:
+      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);
+      set_dst_addr_cols(pinfo, dst, "RA");
 
-      /* Now if we have a tree we start adding stuff */
       if (tree)
-       {
+       proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6, dst);
+      break;
 
 
-         switch (addr_type)
-           {
+    case CTRL_CFP_END:
+      src = tvb_get_ptr (tvb, 10, 6);
+      dst = tvb_get_ptr (tvb, 4, 6);
 
-           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));
-             proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2,
-                                  COOK_FRAGMENT_NUMBER (tvb_get_letohs
-                                                        (tvb, 22)));
+      set_src_addr_cols(pinfo, src, "BSSID");
+      set_dst_addr_cols(pinfo, dst, "RA");
+
+      if (tree)
+       {
+         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:
+      src = tvb_get_ptr (tvb, 10, 6);
+      dst = tvb_get_ptr (tvb, 4, 6);
+
+      set_src_addr_cols(pinfo, src, "BSSID");
+      set_dst_addr_cols(pinfo, dst, "RA");
+
+      if (tree)
+       {
+         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:
+    case DATA_CF_ACK:
+    case DATA_CF_POLL:
+    case DATA_CF_ACK_POLL:
+      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);
+         break;
+
+
+       case DATA_ADDR_T2:
+         src = tvb_get_ptr (tvb, 16, 6);
+         dst = tvb_get_ptr (tvb, 4, 6);
+         break;
+
+
+       case DATA_ADDR_T3:
+         src = tvb_get_ptr (tvb, 10, 6);
+         dst = tvb_get_ptr (tvb, 16, 6);
+         break;
+
+
+       case DATA_ADDR_T4:
+         src = tvb_get_ptr (tvb, 24, 6);
+         dst = tvb_get_ptr (tvb, 16, 6);
+         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);
+
+      /* Now if we have a tree we start adding stuff */
+      if (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,
+                                  COOK_FRAGMENT_NUMBER (tvb_get_letohs
+                                                        (tvb, 22)));
              proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
                                   COOK_SEQUENCE_NUMBER (tvb_get_letohs
                                                         (tvb, 22)));
@@ -956,12 +1287,10 @@ dissect_ieee80211 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
              
              
            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_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,
-                                   tvb_get_ptr (tvb, 16, 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,
                                   COOK_FRAGMENT_NUMBER (tvb_get_letohs
                                                         (tvb, 22)));
@@ -974,10 +1303,8 @@ dissect_ieee80211 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
            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));
+             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,
                                   COOK_FRAGMENT_NUMBER (tvb_get_letohs
                                                         (tvb, 22)));
@@ -992,16 +1319,14 @@ dissect_ieee80211 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
                                    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_da, tvb, 16, 6, dst);
              proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2,
                                   COOK_FRAGMENT_NUMBER (tvb_get_letohs
                                                         (tvb, 22)));
              proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
                                   COOK_SEQUENCE_NUMBER (tvb_get_letohs
                                                         (tvb, 22)));
-             proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 24, 6,
-                                   tvb_get_ptr (tvb, 24, 6));
+             proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 24, 6, src);
              break;
            }
 
@@ -1009,512 +1334,103 @@ dissect_ieee80211 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
       break;
     }
 
-
-  switch (COMPOSE_FRAME_TYPE (fcf))
+  /*
+   * 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_ASSOC_REQ:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Association Request");
-      if (tree)
-       {
-         fixed_tree = get_fixed_parameter_tree (hdr_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);
-
-         next_idx = MGT_FRAME_HDR_LEN + 4;     /* Size of fixed fields */
-         tagged_parameter_tree_len =
-             tvb_reported_length_remaining(tvb, next_idx + 4);
-         tagged_tree = get_tagged_parameter_tree (hdr_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 MGT_ASSOC_RESP:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Association Response");
-
-      if (tree)
-       {
-         fixed_tree = get_fixed_parameter_tree (hdr_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);
-
-         next_idx = MGT_FRAME_LEN + 6; /* Size of fixed fields */
-
-         tagged_parameter_tree_len =
-             tvb_reported_length_remaining(tvb, next_idx + 4);
-         tagged_tree = get_tagged_parameter_tree (hdr_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 MGT_REASSOC_REQ:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Reassociation Request");
-      if (tree)
-       {
-         fixed_tree = get_fixed_parameter_tree (hdr_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_parameter_tree_len =
-             tvb_reported_length_remaining(tvb, next_idx + 4);
-         tagged_tree = get_tagged_parameter_tree (hdr_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 MGT_REASSOC_RESP:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Reassociation Response");
-      if (tree)
-       {
-         fixed_tree = get_fixed_parameter_tree (hdr_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_parameter_tree_len =
-             tvb_reported_length_remaining(tvb, next_idx + 4);
-         tagged_tree = get_tagged_parameter_tree (hdr_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 MGT_PROBE_REQ:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Probe Request");
-      if (tree)
-       {
-         next_idx = MGT_FRAME_LEN;
-         tagged_parameter_tree_len =
-             tvb_reported_length_remaining(tvb, next_idx + 4);
-         tagged_tree = get_tagged_parameter_tree (hdr_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 MGT_PROBE_RESP:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Probe Response");
-      if (tree)
-       {
-         fixed_tree = get_fixed_parameter_tree (hdr_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_parameter_tree_len =
-             tvb_reported_length_remaining(tvb, next_idx + 4);
-         tagged_tree = get_tagged_parameter_tree (hdr_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 MGT_BEACON:           /* Dissect protocol payload fields  */
-      COL_SHOW_INFO_CONST (pinfo->fd, "Beacon frame");
-
-      if (tree)
-       {
-         fixed_tree = get_fixed_parameter_tree (hdr_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_parameter_tree_len =
-             tvb_reported_length_remaining(tvb, next_idx + 4);
-         tagged_tree = get_tagged_parameter_tree (hdr_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 MGT_ATIM:
-      COL_SHOW_INFO_CONST (pinfo->fd, "ATIM");
-      if (tree)
-       {
-       }
-      break;
-
-    case MGT_DISASS:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Dissassociate");
-      if (tree)
-       {
-         fixed_tree = get_fixed_parameter_tree (hdr_tree, tvb, MGT_FRAME_LEN, cap_len);
-         add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN, FIELD_REASON_CODE);
-       }
-      break;
-
-    case MGT_AUTHENTICATION:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Authentication");
-      if (IS_WEP(COOK_FLAGS(fcf)))
-       {
-         int pkt_len = tvb_reported_length (tvb);
-         int cap_len = tvb_length (tvb);
-
-         if (tree)
-           get_wep_parameter_tree (tree, tvb, MGT_FRAME_LEN, pkt_len);
-         pkt_len = MAX (pkt_len - 8 - MGT_FRAME_LEN, 0);
-         cap_len = MIN (pkt_len, MAX (cap_len - 8 - MGT_FRAME_LEN, 0));
-         next_tvb = tvb_new_subset (tvb, MGT_FRAME_LEN + 4, cap_len, pkt_len);
-         dissect_data (next_tvb, 0, pinfo, tree);
-       }
-      else
-       {
-         if (tree)
-           {
-             fixed_tree = get_fixed_parameter_tree (hdr_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);
-
-             next_idx = MGT_FRAME_LEN + 6;     /* Size of fixed fields */
-
-             tagged_parameter_tree_len =
-                 tvb_reported_length_remaining(tvb, next_idx + 4);
-             if (tagged_parameter_tree_len != 0)
-               {
-                 tagged_tree = get_tagged_parameter_tree (hdr_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 MGT_DEAUTHENTICATION:
-      COL_SHOW_INFO_CONST (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);
-       }
-      break;
-
-
-
-    case CTRL_PS_POLL:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Power-Save poll");
-
-      src = tvb_get_ptr (tvb, 10, 6);
-      dst = tvb_get_ptr (tvb, 4, 6);
-
-      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));
-
-       }
-      break;
-
-
-
-    case CTRL_RTS:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Request-to-send");
-      src = tvb_get_ptr (tvb, 10, 6);
-      dst = tvb_get_ptr (tvb, 4, 6);
-
-      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));
-
-       }
-      break;
-
-
-
-    case CTRL_CTS:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Clear-to-send");
-
-      dst = tvb_get_ptr (tvb, 4, 6);
-
-      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));
-
-       }
-      break;
-
-
-
-    case CTRL_ACKNOWLEDGEMENT:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Acknowledgement");
-
-      dst = tvb_get_ptr (tvb, 4, 6);
-
-      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));
-      break;
-
-
-
-    case CTRL_CFP_END:
-      COL_SHOW_INFO_CONST (pinfo->fd, "CF-End (Control-frame)");
-
-      src = tvb_get_ptr (tvb, 10, 6);
-      dst = tvb_get_ptr (tvb, 4, 6);
-
-      set_src_addr_cols(pinfo, src, "BSSID");
-      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_bssid, tvb, 10, 6,
-                               tvb_get_ptr (tvb, 10, 6));
-       }
+    case MGT_FRAME:
+    case DATA_FRAME:
       break;
 
+    default:
+      return;
+    }
 
-
-    case CTRL_CFP_ENDACK:
-      COL_SHOW_INFO_CONST (pinfo->fd, "CF-End + CF-Ack (Control-frame)");
-
-      src = tvb_get_ptr (tvb, 10, 6);
-      dst = tvb_get_ptr (tvb, 4, 6);
-
-      set_src_addr_cols(pinfo, src, "BSSID");
-      set_dst_addr_cols(pinfo, dst, "RA");
+  /*
+   * 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);
 
       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_bssid, tvb, 10, 6,
-                               tvb_get_ptr (tvb, 10, 6));
+        {
+         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)
+           dissect_data (tvb, hdr_len + 4, pinfo, tree);
        }
-      break;
-
-
-
-    case DATA:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Data");
-
-      next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
-
-      if (IS_WEP(COOK_FLAGS(fcf)))
-       {
-         int pkt_len = tvb_reported_length (next_tvb);
-         int cap_len = tvb_length (next_tvb);
-
-         if (tree)
-           get_wep_parameter_tree (tree, next_tvb, 0, pkt_len);
-         pkt_len = MAX (pkt_len - 8, 0);
-         cap_len = MIN (pkt_len, MAX (cap_len - 8, 0));
-         next_tvb = tvb_new_subset (tvb, hdr_len + 4, cap_len, pkt_len);
-         dissect_data (next_tvb, 0, pinfo, tree);
-       }
-      else
-       call_dissector (llc_handle, next_tvb, pinfo, tree);
-      break;
-
-
-
-    case DATA_CF_ACK:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Data + CF-Acknowledgement");
-
-      next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
-
-      if (IS_WEP(COOK_FLAGS(fcf)))
-       {
-         int pkt_len = tvb_reported_length (next_tvb);
-         int cap_len = tvb_length (next_tvb);
-
-         if (tree)
-           get_wep_parameter_tree (tree, next_tvb, 0, pkt_len);
-         pkt_len = MAX (pkt_len - 8, 0);
-         cap_len = MIN (pkt_len, MAX (cap_len - 8, 0));
-         next_tvb = tvb_new_subset (tvb, hdr_len + 4, cap_len, pkt_len);
-         dissect_data (next_tvb, 0, pinfo, tree);
-       }
-      else
-       call_dissector (llc_handle, next_tvb, pinfo, tree);
-      break;
-
-
-
-    case DATA_CF_POLL:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Data + CF-Poll");
-      next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
-
-      if (IS_WEP(COOK_FLAGS(fcf)))
-       {
-         int pkt_len = tvb_reported_length (next_tvb);
-         int cap_len = tvb_length (next_tvb);
-
-         if (tree)
-           get_wep_parameter_tree (tree, next_tvb, 0, pkt_len);
-         pkt_len = MAX (pkt_len - 8, 0);
-         cap_len = MIN (pkt_len, MAX (cap_len - 8, 0));
-         next_tvb = tvb_new_subset (tvb, hdr_len + 4, cap_len, pkt_len);
-         dissect_data (next_tvb, 0, pinfo, tree);
-       }
-      else
-       call_dissector (llc_handle, next_tvb, pinfo, tree);
-      break;
-
-
-
-    case DATA_CF_ACK_POLL:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Data + CF-Acknowledgement/Poll");
-      next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
-
-      if (IS_WEP(COOK_FLAGS(fcf)))
-       {
-         int pkt_len = tvb_reported_length (next_tvb);
-         int cap_len = tvb_length (next_tvb);
-
-         if (tree)
-           get_wep_parameter_tree (tree, next_tvb, 0, pkt_len);
-         pkt_len = MAX (pkt_len - 8, 0);
-         cap_len = MIN (pkt_len, MAX (cap_len - 8, 0));
-         next_tvb = tvb_new_subset (tvb, hdr_len + 4, cap_len, pkt_len);
-         dissect_data (next_tvb, 0, pinfo, tree);
-       }
-      else
-       call_dissector (llc_handle, next_tvb, pinfo, tree);
-      break;
-
-
-
-    case DATA_NULL_FUNCTION:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Null function (No data)");
-      break;
-
-
-    case DATA_CF_ACK_NOD:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Data + Acknowledgement (No data)");
-      break;
-
-
-    case DATA_CF_POLL_NOD:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Data + CF-Poll (No data)");
-      break;
+       return;
+    }
 
+  /*
+   * Now dissect the body of a non-WEP-encrypted frame.
+   */
+  next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
+  switch (COOK_FRAME_TYPE (fcf))
+    {
 
-    case DATA_CF_ACK_POLL_NOD:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Data + CF-Acknowledgement/Poll (No data)");
+    case MGT_FRAME:
+      dissect_ieee80211_mgt (fcf, next_tvb, pinfo, tree);
       break;
 
 
-    default:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Unrecognized (Reserved frame)");
+    case DATA_FRAME:
+      call_dissector (llc_handle, next_tvb, pinfo, tree);
       break;
     }
 }
 
-
 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, "Not leaving DS or network is 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: 1  From DS: 0)"},
-    {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}
   };
 
@@ -1657,8 +1573,6 @@ proto_register_wlan (void)
     {0x00, NULL}
   };
 
-
-
   static hf_register_info hf[] = {
     {&hf_fc_field,
      {"Frame Control Field", "wlan.fc", FT_UINT16, BASE_HEX, NULL, 0,
@@ -1669,13 +1583,17 @@ proto_register_wlan (void)
       "MAC Protocol version", HFILL }},        /* 0 */
 
     {&hf_fc_frame_type,
-     {"Type", "wlan.fc.type", FT_UINT8, BASE_DEC, NULL, 0,
+     {"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", 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", HFILL }},
@@ -1685,35 +1603,35 @@ proto_register_wlan (void)
       "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", "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", "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,
+     {"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,
+     {"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,
+     {"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", "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", "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,
+     {"Order flag", "wlan.fc.order", FT_BOOLEAN, 8, TFS (&order_flags), FLAG_ORDER,
       "Strictly ordered flag", HFILL }},
 
     {&hf_assoc_id,
@@ -1745,139 +1663,136 @@ proto_register_wlan (void)
       "Basic Service Set ID", HFILL }},
 
     {&hf_frag_number,
-     {"Fragment number", "wlan.frag", FT_UINT16, BASE_HEX, NULL, 0,
+     {"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", HFILL }},
+     {"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, "", 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,
+     {"Timestamp", "wlan_mgt.fixed.timestamp", FT_STRING, BASE_NONE,
       NULL, 0, "", HFILL }},
 
     {&ff_auth_alg,
-     {"Authentication Algorithm", "wlan.fixed.auth.alg",
+     {"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_DOUBLE, 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,
-      "", HFILL }},
-
-    {&hf_wep_parameters,
-     {"WEP parameters", "wlan.wep.all", FT_STRING, BASE_NONE, NULL, 0,
+     {"Tagged parameters", "wlan_mgt.tagged.all", FT_UINT16, BASE_DEC, NULL, 0,
       "", HFILL }},
 
-    {&hf_wep_iv,
-     {"Initialization Vector", "wlan.wep.iv", FT_UINT32, BASE_HEX, NULL, 0,
-      "Initialization Vector", HFILL }},
-
-    {&hf_wep_key,
-     {"Key", "wlan.wep.key", FT_UINT32, 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 }},
-
     {&ff_capture,
-     {"Capabilities", "wlan.fixed.capabilities", FT_UINT16, BASE_HEX, NULL, 0,
+     {"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", 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", HFILL }},
 
     {&ff_cf_ess,
-     {"ESS capabilities", "wlan.fixed.capabilities.ess",
+     {"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",
+     {"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",
+     {"Privacy", "wlan_mgt.fixed.capabilities.privacy",
       FT_BOOLEAN, 8, TFS (&cf_privacy_flags), 0x0010, "WEP support", HFILL }},
 
     {&ff_cf_preamble,
-     {"Short Preamble", "wlan.fixed.capabilities.preamble",
+     {"Short Preamble", "wlan_mgt.fixed.capabilities.preamble",
       FT_BOOLEAN, 8, TFS (&cf_preamble_flags), 0x0020, "Short Preamble", HFILL }},
 
     {&ff_cf_pbcc,
-     {"PBCC", "wlan.fixed.capabilities.pbcc",
+     {"PBCC", "wlan_mgt.fixed.capabilities.pbcc",
       FT_BOOLEAN, 8, TFS (&cf_pbcc_flags), 0x0040, "PBCC Modulation", HFILL }},
 
     {&ff_cf_agility,
-     {"Channel Agility", "wlan.fixed.capabilities.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",
+     {"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",
+     {"Association ID", "wlan_mgt.fixed.aid",
       FT_UINT16, BASE_HEX, NULL, 0, "Association ID", HFILL }},
 
     {&ff_listen_ival,
-     {"Listen Interval", "wlan.fixed.listen_ival",
+     {"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",
+     {"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", 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", HFILL }},
 
     {&tag_number,
-     {"Tag", "wlan.tag.number",
+     {"Tag", "wlan_mgt.tag.number",
       FT_UINT16, BASE_DEC, NULL, 0,
       "Element ID", HFILL }},
 
     {&tag_length,
-     {"Tag length", "wlan.tag.length",
+     {"Tag length", "wlan_mgt.tag.length",
       FT_UINT16, BASE_DEC, NULL, 0, "Length of tag", HFILL }},
 
     {&tag_interpretation,
-     {"Tag interpretation", "wlan.tag.interpretation",
+     {"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_80211_mgt,
     &ett_fixed_parameters,
     &ett_tagged_parameters,
     &ett_wep_parameters,
@@ -1887,6 +1802,9 @@ proto_register_wlan (void)
   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));
 }