Remove "text2pcap-scanner.obj" and "tools\lemon\lemon.obj" when a "nmake
[obnox/wireshark/wip.git] / packet-ieee80211.c
index 91424f2c49bce9fd40a9507760292ff28678d011..64b6d3b379674abec3e0decaa44e97970b99fe8b 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.20 2001/06/08 06:01:06 guy Exp $
+ * $Id: packet-ieee80211.c,v 1.40 2001/09/25 02:21:15 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -64,6 +64,8 @@
 #include "bitswap.h"
 #include "proto.h"
 #include "packet.h"
+#include "resolv.h"
+#include "packet-ipx.h"
 #include "packet-llc.h"
 #include "packet-ieee80211.h"
 #include "etypes.h"
 /* ************************************************************************* */
 /*                          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)) && ((x & 0x100)))
-#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_IV(x)        (x & 0xFFFFFF)
-#define COOK_WEP_KEY(x)       ((x & 0xC0000000) >> 30)
+#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 COL_SHOW_INFO(fd,info) if (check_col(fd,COL_INFO)) \
-col_add_str(fd,COL_INFO,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 & 0x1))
-#define IS_FROM_DS(x)          ((x & 0x2))
-#define HAVE_FRAGMENTS(x)      ((x & 0x4))
-#define IS_RETRY(x)            ((x & 0x8))
-#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 MGT_RESERVED_RANGE(x) (((x>=0x06)&&(x<=0x07))||((x>=0x0D)&&(x<=0x0F)))
+                               col_set_str(fd,COL_INFO,info);
+
+#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))
@@ -119,7 +128,7 @@ col_set_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      */
@@ -148,17 +157,17 @@ col_set_str(fd,COL_INFO,info);
 #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)
 
 
 /* ************************************************************************* */
 /*          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)
 
 
 
@@ -188,6 +197,37 @@ col_set_str(fd,COL_INFO,info);
 #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;
 /* ************************************************************************* */
@@ -197,6 +237,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;
@@ -227,6 +268,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 */
 
 
 /* ************************************************************************* */
@@ -241,6 +283,8 @@ static int hf_seq_number = -1;
 static int hf_fcs = -1;
 
 
+
+static int proto_wlan_mgt = -1;
 /* ************************************************************************* */
 /*                      Fixed fields found in mgt frames                     */
 /* ************************************************************************* */
@@ -278,7 +322,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;
@@ -290,23 +333,47 @@ 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;
 
 static dissector_handle_t llc_handle;
+static dissector_handle_t ipx_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 */
+  }
 }
 
 
@@ -320,9 +387,6 @@ capture_ieee80211 (const u_char * pd, int offset, packet_counts * ld)
 
   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++;
@@ -333,23 +397,27 @@ capture_ieee80211 (const u_char * pd, int offset, packet_counts * ld)
     {
 
     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);
+      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 (pd[offset+hdr_length] == 0xff && pd[offset+hdr_length+1] == 0xff) {
+        capture_ipx (pd, offset + hdr_length, ld);
+      }
+      else {
+        capture_llc (pd, offset + hdr_length, ld);
+      }
       break;
 
     default:
@@ -399,22 +467,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,
@@ -429,7 +495,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;
@@ -452,10 +518,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]",
@@ -464,85 +528,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 Information: %04X",
-                                            pletohs (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,
-                             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;
     }
 }
@@ -554,16 +594,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)
 {
-  const guint8 *tag_info_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);
 
@@ -596,7 +635,7 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
     }
 
 
-  switch (tag_info_ptr[0])
+  switch (tag_no)
     {
 
 
@@ -628,13 +667,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++)
        {
-           n += snprintf (out_buff + n, SHORT_STR - n, "%2.1f%s ",
+           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;
+           }
+           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);
@@ -745,7 +791,239 @@ 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)
+{
+  if (check_col(pinfo->fd, COL_RES_DL_SRC))
+    col_add_fstr(pinfo->fd, COL_RES_DL_SRC, "%s (%s)",
+                   get_ether_name(addr), type);
+  if (check_col(pinfo->fd, COL_UNRES_DL_SRC))
+    col_add_fstr(pinfo->fd, COL_UNRES_DL_SRC, "%s (%s)",
+                    ether_to_str(addr), type);
+}
 
+static void
+set_dst_addr_cols(packet_info *pinfo, const guint8 *addr, char *type)
+{
+  if (check_col(pinfo->fd, COL_RES_DL_DST))
+    col_add_fstr(pinfo->fd, COL_RES_DL_DST, "%s (%s)",
+                    get_ether_name(addr), type);
+  if (check_col(pinfo->fd, COL_UNRES_DL_DST))
+    col_add_fstr(pinfo->fd, COL_UNRES_DL_DST, "%s (%s)",
+                    ether_to_str(addr), type);
+}
 
 /* ************************************************************************* */
 /*                          Dissect 802.11 frame                             */
@@ -753,39 +1031,43 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
 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;
+  volatile gboolean is_802_2;
 
   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)
     {
-      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");
+                                          "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",
@@ -829,7 +1111,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)));
      
@@ -838,30 +1120,44 @@ 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);
 
-
-      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]);
-
-      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]);
+      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);
 
       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);
+
+         /* 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);
 
          proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 16, 6,
                                tvb_get_ptr (tvb, 16, 6));
@@ -873,73 +1169,144 @@ 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);
-      hdr_len = find_header_length (tvb_get_ptr (tvb, 0, cap_len), 0);
+      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);
 
-      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]);
+      set_dst_addr_cols(pinfo, dst, "RA");
 
-      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]);
+      if (tree)
+       proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6, dst);
+      break;
+
+
+    case CTRL_CFP_END:
+      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");
 
-      /* 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);
+         proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 10, 6, src);
+       }
+      break;
 
 
-         switch (addr_type)
-           {
+    case CTRL_CFP_ENDACK:
+      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,
+      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
@@ -947,38 +1314,47 @@ 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)));
+
+             /* 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,
-                                   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)));
              proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
                                   COOK_SEQUENCE_NUMBER (tvb_get_letohs
                                                         (tvb, 22)));
+
+             /* 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,
-                                   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)));
              proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
                                   COOK_SEQUENCE_NUMBER (tvb_get_letohs
                                                         (tvb, 22)));
+
+             /* 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;
              
 
@@ -987,16 +1363,18 @@ 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);
+
+             /* 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;
            }
 
@@ -1004,549 +1382,128 @@ 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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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);
-
-
-      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]);
-
-      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);
-
-
-      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]);
-
-      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);
-
-      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]);
-
-      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);
-
-      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]);
-
-      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);
-
-
-      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]);
-
-      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);
-
-      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]);
+  /*
+   * 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");
-      hdr_len = find_header_length (tvb_get_ptr (tvb, 0, cap_len), 0);
-
-      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");
-      hdr_len = find_header_length (tvb_get_ptr (tvb, 0, cap_len), 0);
-
-      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;
-
-
+       return;
+    }
 
-    case DATA_CF_POLL:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Data + CF-Poll");
-      hdr_len = find_header_length (tvb_get_ptr (tvb, 0, cap_len), 0);
-      next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
+  /*
+   * 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))
+    {
 
-      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);
+    case MGT_FRAME:
+      dissect_ieee80211_mgt (fcf, next_tvb, pinfo, tree);
       break;
 
 
-
-    case DATA_CF_ACK_POLL:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Data + CF-Acknowledgement/Poll");
-      hdr_len = find_header_length (tvb_get_ptr (tvb, 0, cap_len), 0);
-      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);
-       }
+    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 (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;
-
-
-    case DATA_CF_ACK_POLL_NOD:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Data + CF-Acknowledgement/Poll (No data)");
-      break;
-
-
-    default:
-      COL_SHOW_INFO_CONST (pinfo->fd, "Unrecognized (Reserved frame)");
+        call_dissector(ipx_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}
   };
 
@@ -1586,8 +1543,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 = {
@@ -1689,227 +1646,230 @@ 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,
-      "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 */
+     {"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" }},
+      "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_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_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,
-      ""}},
-
-    {&hf_wep_parameters,
-     {"WEP parameters", "wlan.wep.all", FT_STRING, BASE_NONE, NULL, 0,
-      ""}},
-
-    {&hf_wep_iv,
-     {"Initialization Vector", "wlan.wep.iv", FT_UINT32, BASE_HEX, NULL, 0,
-      "Initialization Vector"}},
-
-    {&hf_wep_key,
-     {"Key", "wlan.wep.key", FT_UINT32, BASE_DEC, NULL, 0,
-      "Key"}},
-
-    {&hf_wep_crc,
-     {"WEP CRC (not verified)", "wlan.wep.crc", FT_UINT32, BASE_HEX, NULL, 0,
-      "WEP CRC"}},
+     {"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, 8, 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, 8, 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, 8, 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.fixed.capabilities.preamble",
-      FT_BOOLEAN, 8, TFS (&cf_preamble_flags), 0x0020, "Short 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",
-      FT_BOOLEAN, 8, TFS (&cf_pbcc_flags), 0x0040, "PBCC Modulation"}},
+     {"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",
-      FT_BOOLEAN, 8, TFS (&cf_agility_flags), 0x0080, "Channel 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_80211_mgt,
     &ett_fixed_parameters,
     &ett_tagged_parameters,
     &ett_wep_parameters,
@@ -1919,6 +1879,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));
 }
 
@@ -1926,9 +1889,10 @@ void
 proto_reg_handoff_wlan(void)
 {
   /*
-   * Get a handle for the LLC dissector.
+   * Get handles for the LLC and IPX dissectors.
    */
   llc_handle = find_dissector("llc");
+  ipx_handle = find_dissector("ipx");
 
   dissector_add("wtap_encap", WTAP_ENCAP_IEEE_802_11, dissect_ieee80211,
                proto_wlan);