Fix document creation under Windows, add ethereal-filter.html to the NSIS
[obnox/wireshark/wip.git] / packet-ieee80211.c
index f4537c0918356a02735a2ade028048d77c3ee547..ab3f8433323fb00ab81bb4f15c21d948774cc78e 100644 (file)
@@ -1,9 +1,9 @@
 /* packet-ieee80211.c
  * Routines for Wireless LAN (IEEE 802.11) dissection
- * Copyright 2000, Axis Communications AB 
+ * Copyright 2000, Axis Communications AB
  * Inquiries/bugreports should be sent to Johan.Jorgensen@axis.com
  *
- * $Id: packet-ieee80211.c,v 1.68 2002/06/19 17:57:23 guy Exp $
+ * $Id: packet-ieee80211.c,v 1.101 2003/09/24 23:35:39 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  *
  * Credits:
- * 
+ *
  * The following people helped me by pointing out bugs etc. Thank you!
  *
  * Marco Molteni
- * Lena-Marie Nilsson     
+ * Lena-Marie Nilsson
  * Magnus Hultman-Persson
  */
 
+/*
+ * 09/12/2003 - Added dissection of country information tag
+ *
+ * Ritchie<at>tipsybottle.com
+ */
+
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
 #include <stdio.h>
 #include <stdlib.h>
 
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h>
-#endif
-
 #ifdef NEED_SNPRINTF_H
-# ifdef HAVE_STDARG_H
-#  include <stdarg.h>
-# else
-#  include <varargs.h>
-# endif
 # include "snprintf.h"
 #endif
 
@@ -70,6 +63,7 @@
 #include "packet-llc.h"
 #include "packet-ieee80211.h"
 #include "etypes.h"
+#include "crc32.h"
 
 /* Defragment fragmented 802.11 datagrams */
 static gboolean wlan_defragment = TRUE;
@@ -94,12 +88,12 @@ static tvbuff_t *try_decrypt_wep(tvbuff_t *tvb, guint32 offset, guint32 len);
 #define SSWAP(a,b) {guint8 tmp = s[a]; s[a] = s[b]; s[b] = tmp;}
 
 /* #define USE_ENV */
-/* When this is set, an unlimited number of WEP keys can be set in the 
-   environment:  
+/* When this is set, an unlimited number of WEP keys can be set in the
+   environment:
 
    ETHEREAL_WEPKEYNUM=##
-   ETHEREAL_WEPKEY1=aa:bb:cc:dd:... 
-   ETHEREAL_WEPKEY2=aa:bab:cc:dd:ee:... 
+   ETHEREAL_WEPKEY1=aa:bb:cc:dd:...
+   ETHEREAL_WEPKEY2=aa:bab:cc:dd:ee:...
 
    ... you get the idea.
 
@@ -224,14 +218,23 @@ static char *wep_keystr[] = {NULL, NULL, NULL, NULL};
 /* ************************************************************************* */
 /*        Logical field codes (IEEE 802.11 encoding of tags)                 */
 /* ************************************************************************* */
-#define TAG_SSID           0x00
-#define TAG_SUPP_RATES     0x01
-#define TAG_FH_PARAMETER   0x02
-#define TAG_DS_PARAMETER   0x03
-#define TAG_CF_PARAMETER   0x04
-#define TAG_TIM            0x05
-#define TAG_IBSS_PARAMETER 0x06
-#define TAG_CHALLENGE_TEXT 0x10
+#define TAG_SSID                 0x00
+#define TAG_SUPP_RATES           0x01
+#define TAG_FH_PARAMETER         0x02
+#define TAG_DS_PARAMETER         0x03
+#define TAG_CF_PARAMETER         0x04
+#define TAG_TIM                  0x05
+#define TAG_IBSS_PARAMETER       0x06
+#define TAG_COUNTRY_INFO         0x07
+#define TAG_FH_HOPPING_PARAMETER 0x08
+#define TAG_FH_HOPPING_TABLE     0x09
+#define TAG_CHALLENGE_TEXT       0x10
+#define TAG_ERP_INFO             0x2A
+#define TAG_ERP_INFO_OLD         0x2F  /* IEEE Std 802.11g/D4.0 */
+#define TAG_EXT_SUPP_RATES       0x32
+#define TAG_VENDOR_SPECIFIC_IE  0xDD
+
+#define WPA_OUI        "\x00\x50\xF2"
 
 /* ************************************************************************* */
 /*                         Frame types, and their names                      */
@@ -336,6 +339,7 @@ static int hf_fragment_overlap_conflict = -1;
 static int hf_fragment_multiple_tails = -1;
 static int hf_fragment_too_long_fragment = -1;
 static int hf_fragment_error = -1;
+static int hf_reassembled_in = -1;
 
 
 static int proto_wlan_mgt = -1;
@@ -356,14 +360,16 @@ static int ff_status_code = -1;   /* Status code                               */
 /*            Flags found in the capability field (fixed field)              */
 /* ************************************************************************* */
 static int ff_capture = -1;
-static int ff_cf_sta_poll = -1; /* CF pollable status for a STA            */
-static int ff_cf_ap_poll = -1; /* CF pollable status for an AP            */
 static int ff_cf_ess = -1;
 static int ff_cf_ibss = -1;
+static int ff_cf_sta_poll = -1; /* CF pollable status for a STA            */
+static int ff_cf_ap_poll = -1; /* CF pollable status for an AP            */
 static int ff_cf_privacy = -1;
 static int ff_cf_preamble = -1;
 static int ff_cf_pbcc = -1;
 static int ff_cf_agility = -1;
+static int ff_short_slot_time = -1;
+static int ff_dsss_ofdm = -1;
 
 /* ************************************************************************* */
 /*                       Tagged value format fields                          */
@@ -395,7 +401,7 @@ static gint ett_fixed_parameters = -1;
 static gint ett_tagged_parameters = -1;
 static gint ett_wep_parameters = -1;
 
-fragment_items frag_items = {
+static const fragment_items frag_items = {
        &ett_fragment,
        &ett_fragments,
        &hf_fragments,
@@ -405,6 +411,7 @@ fragment_items frag_items = {
        &hf_fragment_multiple_tails,
        &hf_fragment_too_long_fragment,
        &hf_fragment_error,
+       &hf_reassembled_in,
        "fragments"
 };
 
@@ -451,7 +458,7 @@ find_header_length (guint16 fcf)
 /*          This is the capture function used to update packet counts        */
 /* ************************************************************************* */
 static void
-capture_ieee80211_common (const u_char * pd, int offset, int len,
+capture_ieee80211_common (const guchar * pd, int offset, int len,
                          packet_counts * ld, gboolean fixed_length_header)
 {
   guint16 fcf, hdr_length;
@@ -513,7 +520,7 @@ capture_ieee80211_common (const u_char * pd, int offset, int len,
  * Handle 802.11 with a variable-length link-layer header.
  */
 void
-capture_ieee80211 (const u_char * pd, int offset, int len, packet_counts * ld)
+capture_ieee80211 (const guchar * pd, int offset, int len, packet_counts * ld)
 {
   capture_ieee80211_common (pd, offset, len, ld, FALSE);
 }
@@ -523,7 +530,7 @@ capture_ieee80211 (const u_char * pd, int offset, int len, packet_counts * ld)
  * maximum length).
  */
 void
-capture_ieee80211_fixed (const u_char * pd, int offset, int len, packet_counts * ld)
+capture_ieee80211_fixed (const guchar * pd, int offset, int len, packet_counts * ld)
 {
   capture_ieee80211_common (pd, offset, len, ld, TRUE);
 }
@@ -608,31 +615,35 @@ add_fixed_field (proto_tree * tree, tvbuff_t * tvb, int offset, int lfcode)
     case FIELD_CAP_INFO:
       capability = tvb_get_letohs (tvb, offset);
 
-      cap_item = proto_tree_add_uint_format (tree, ff_capture, 
+      cap_item = proto_tree_add_uint_format (tree, ff_capture,
                                             tvb, offset, 2,
                                             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,
-                             capability);
-      proto_tree_add_boolean (cap_tree, ff_cf_ibss, tvb, offset, 1,
-                             capability);
-      proto_tree_add_boolean (cap_tree, ff_cf_privacy, tvb, offset, 1,
-                             capability);
-      proto_tree_add_boolean (cap_tree, ff_cf_preamble, tvb, offset, 1,
+      proto_tree_add_boolean (cap_tree, ff_cf_ess, tvb, offset, 2,
                              capability);
-      proto_tree_add_boolean (cap_tree, ff_cf_pbcc, tvb, offset, 1,
-                             capability);
-      proto_tree_add_boolean (cap_tree, ff_cf_agility, tvb, offset, 1,
+      proto_tree_add_boolean (cap_tree, ff_cf_ibss, tvb, offset, 2,
                              capability);
       if (ESS_SET (capability) != 0)   /* This is an AP */
        proto_tree_add_uint (cap_tree, ff_cf_ap_poll, tvb, offset, 2,
-                            ((capability & 0xC) >> 2));
+                            capability);
 
       else                     /* This is a STA */
        proto_tree_add_uint (cap_tree, ff_cf_sta_poll, tvb, offset, 2,
-                            ((capability & 0xC) >> 2));
+                            capability);
+      proto_tree_add_boolean (cap_tree, ff_cf_privacy, tvb, offset, 2,
+                             capability);
+      proto_tree_add_boolean (cap_tree, ff_cf_preamble, tvb, offset, 2,
+                             capability);
+      proto_tree_add_boolean (cap_tree, ff_cf_pbcc, tvb, offset, 2,
+                             capability);
+      proto_tree_add_boolean (cap_tree, ff_cf_agility, tvb, offset, 2,
+                             capability);
+      proto_tree_add_boolean (cap_tree, ff_short_slot_time, tvb, offset, 2,
+                             capability);
+      proto_tree_add_boolean (cap_tree, ff_dsss_ofdm, tvb, offset, 2,
+                             capability);
       break;
 
     case FIELD_AUTH_ALG:
@@ -665,10 +676,143 @@ add_fixed_field (proto_tree * tree, tvbuff_t * tvb, int offset, int lfcode)
     }
 }
 
+static char *wpa_cipher_str[] = 
+{
+  "NONE",
+  "WEP (40-bit)",
+  "TKIP",
+  "AES (OCB)",
+  "AES (CCM)",
+  "WEP (104-bit)",
+};
+
+static char *
+wpa_cipher_idx2str(guint idx)
+{
+  if (idx < sizeof(wpa_cipher_str)/sizeof(wpa_cipher_str[0]))
+    return wpa_cipher_str[idx];
+  return "UNKNOWN";
+}
+
+static char *wpa_keymgmt_str[] = 
+{
+  "NONE",
+  "WPA",
+  "PSK",
+};
+
+static char *
+wpa_keymgmt_idx2str(guint idx)
+{
+  if (idx < sizeof(wpa_keymgmt_str)/sizeof(wpa_keymgmt_str[0]))
+    return wpa_keymgmt_str[idx];
+  return "UNKNOWN";
+}
+
+static void 
+dissect_vendor_specific_ie(proto_tree * tree, tvbuff_t * tvb, int offset,
+               guint32 tag_len, const guint8 *tag_val)
+{
+      guint32 tag_val_off = 0;
+      char out_buff[SHORT_STR];
+      int i;
+       
+      if (tag_val_off + 6 <= tag_len && !memcmp(tag_val, WPA_OUI"\x01", 4)) {
+        snprintf(out_buff, SHORT_STR, "WPA IE, type %u, version %u",
+                  tag_val[tag_val_off + 3], pletohs(&tag_val[tag_val_off + 4]));
+        proto_tree_add_string(tree, tag_interpretation, tvb, offset, 6, out_buff);
+        offset += 6;
+        tag_val_off += 6;
+        if (tag_val_off + 4 <= tag_len) {
+          /* multicast cipher suite */
+          if (!memcmp(&tag_val[tag_val_off], WPA_OUI, 3)) {
+            snprintf(out_buff, SHORT_STR, "Multicast cipher suite: %s", 
+                      wpa_cipher_idx2str(tag_val[tag_val_off + 3]));
+            proto_tree_add_string(tree, tag_interpretation, tvb, offset, 4, out_buff);
+            offset += 4;
+            tag_val_off += 4;
+            /* unicast cipher suites */
+            if (tag_val_off + 2 <= tag_len) {
+              snprintf(out_buff, SHORT_STR, "# of unicast cipher suites: %u",
+                        pletohs(tag_val + tag_val_off));
+              proto_tree_add_string(tree, tag_interpretation, tvb, offset, 2, out_buff);
+              offset += 2;
+              tag_val_off += 2;
+              i = 1;
+              while (tag_val_off + 4 <= tag_len) {
+                if (!memcmp(&tag_val[tag_val_off], WPA_OUI, 3)) {
+                  snprintf(out_buff, SHORT_STR, "Unicast cipher suite %u: %s", 
+                            i, wpa_cipher_idx2str(tag_val[tag_val_off + 3]));
+                  proto_tree_add_string(tree, tag_interpretation, tvb, offset, 4, out_buff);
+                  offset += 4;
+                  tag_val_off += 4;
+                  i ++;
+                }
+                else
+                  break;
+              }
+             /* authenticated key management suites */
+              if (tag_val_off + 2 <= tag_len) {
+                snprintf(out_buff, SHORT_STR, "# of auth key management suites: %u",
+                          pletohs(tag_val + tag_val_off));
+                proto_tree_add_string(tree, tag_interpretation, tvb, offset, 2, out_buff);
+                offset += 2;
+                tag_val_off += 2;
+                i = 1;
+                while (tag_val_off + 4 <= tag_len) {
+                  if (!memcmp(&tag_val[tag_val_off], WPA_OUI, 3)) {
+                    snprintf(out_buff, SHORT_STR, "auth key management suite %u: %s", 
+                              i, wpa_keymgmt_idx2str(tag_val[tag_val_off + 3]));
+                    proto_tree_add_string(tree, tag_interpretation, tvb, offset, 4, out_buff);
+                    offset += 4;
+                    tag_val_off += 4;
+                    i ++;
+                  }
+                  else
+                    break;
+                }
+              }
+            }
+          }
+        }
+        if (tag_val_off < tag_len)
+          proto_tree_add_string(tree, tag_interpretation, tvb,
+                                 offset, tag_len - tag_val_off, "Not interpreted");
+      }
+      else
+        proto_tree_add_string(tree, tag_interpretation, 
+                       tvb, offset, tag_len, "Not interpreted");
+}
 
 /* ************************************************************************* */
 /*           Dissect and add tagged (optional) fields to proto tree          */
 /* ************************************************************************* */
+
+static const value_string tag_num_vals[] = {
+       { TAG_SSID,                 "SSID parameter set" },
+       { TAG_SUPP_RATES,           "Supported Rates" },
+       { TAG_FH_PARAMETER,         "FH Parameter set" },
+       { TAG_DS_PARAMETER,         "DS Parameter set" },
+       { TAG_CF_PARAMETER,         "CF Parameter set" },
+       { TAG_TIM,                  "(TIM) Traffic Indication Map" },
+       { TAG_IBSS_PARAMETER,       "IBSS Parameter set" },
+       { TAG_COUNTRY_INFO,         "Country Information" },
+       { TAG_FH_HOPPING_PARAMETER, "Hopping Pattern Parameters" },
+       { TAG_CHALLENGE_TEXT,       "Challenge text" },
+       { TAG_ERP_INFO,             "ERP Information" },
+       { TAG_ERP_INFO_OLD,         "ERP Information" },
+       { TAG_EXT_SUPP_RATES,       "Extended Supported Rates" },
+       { TAG_VENDOR_SPECIFIC_IE,   "Vendor Specific" },
+       { 0,                        NULL }
+};
+
+static const value_string environment_vals[] = {
+       { 0x20, "Any" },
+       { 0x4f, "Outdoor" },
+       { 0x49, "Indoor" },
+       { 0,    NULL }
+};
+
 static int
 add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
 {
@@ -680,50 +824,24 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
 
 
   tag_no = tvb_get_guint8(tvb, offset);
+  proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
+                             "Tag Number: %u (%s)",
+                             tag_no,
+                             val_to_str(tag_no, tag_num_vals,
+                                        (tag_no >= 17 && tag_no <= 31) ?
+                                        "Reserved for challenge text" :
+                                        "Reserved tag number"));
+
   tag_len = tvb_get_guint8(tvb, offset + 1);
+  proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
 
   tag_data_ptr = tvb_get_ptr (tvb, offset + 2, tag_len);
 
-
-  if ((tag_no >= 17) && (tag_no <= 31))
-    {                          /* Reserved for challenge text */
-      proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
-                                 "Tag Number: %u (Reserved for challenge text)",
-                                 tag_no);
-
-      proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
-      proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
-                            tag_len, "Not interpreted");
-      return (int) tag_len + 2;
-    }
-
-  /* Next See if tag is reserved - if true, skip it! */
-  if (((tag_no >= 7) && (tag_no <= 15))
-      || ((tag_no >= 32) && (tag_no <= 255)))
-    {
-      proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
-                                 "Tag Number: %u (Reserved tag number)",
-                                 tag_no);
-
-      proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
-
-      proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
-                            tag_len, "Not interpreted");
-      return (int) tag_len + 2;
-    }
-
-
   switch (tag_no)
     {
 
 
     case TAG_SSID:
-      proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
-                                 "Tag Number: %u (SSID parameter set)",
-                                 tag_no);
-
-      proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
-
       memset (out_buff, 0, SHORT_STR);
 
       memcpy (out_buff, tag_data_ptr, (size_t) tag_len);
@@ -736,11 +854,7 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
 
 
     case TAG_SUPP_RATES:
-      proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
-                                 "Tag Number: %u (Supported Rates)", tag_no);
-
-      proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
-
+    case TAG_EXT_SUPP_RATES:
       memset (out_buff, 0, SHORT_STR);
       strcpy (out_buff, "Supported rates: ");
       n = strlen (out_buff);
@@ -750,9 +864,9 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
            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) {
+           if (ret == -1 || ret >= SHORT_STR - n) {
              /* Some versions of snprintf return -1 if they'd truncate
-                the output. */
+                the output. Others return <buf_size> or greater.  */
              break;
            }
            n += ret;
@@ -760,6 +874,7 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
       if (n < SHORT_STR)
        snprintf (out_buff + n, SHORT_STR - n, "[Mbit/sec]");
 
+      out_buff[SHORT_STR-1] = '\0';
       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
                             tag_len, out_buff);
       break;
@@ -767,11 +882,6 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
 
 
     case TAG_FH_PARAMETER:
-      proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
-                                 "Tag Number: %u (FH Parameter set)",
-                                 tag_no);
-
-      proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
       memset (out_buff, 0, SHORT_STR);
 
       snprintf (out_buff, SHORT_STR,
@@ -786,11 +896,6 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
 
 
     case TAG_DS_PARAMETER:
-      proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
-                                 "Tag Number: %u (DS Parameter set)",
-                                 tag_no);
-
-      proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
       memset (out_buff, 0, SHORT_STR);
 
       snprintf (out_buff, SHORT_STR, "Current Channel: %u", tag_data_ptr[0]);
@@ -800,11 +905,6 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
 
 
     case TAG_CF_PARAMETER:
-      proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
-                                 "Tag Number: %u (CF Parameter set)",
-                                 tag_no);
-
-      proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
       memset (out_buff, 0, SHORT_STR);
 
       snprintf (out_buff, SHORT_STR,
@@ -818,11 +918,6 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
 
 
     case TAG_TIM:
-      proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
-                                 "Tag Number: %u ((TIM) Traffic Indication Map)",
-                                 tag_no);
-
-      proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
       memset (out_buff, 0, SHORT_STR);
       snprintf (out_buff, SHORT_STR,
                "DTIM count %u, DTIM period %u, Bitmap control 0x%X, "
@@ -835,11 +930,6 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
 
 
     case TAG_IBSS_PARAMETER:
-      proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
-                                 "Tag Number: %u (IBSS Parameter set)",
-                                 tag_no);
-
-      proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
       memset (out_buff, 0, SHORT_STR);
       snprintf (out_buff, SHORT_STR, "ATIM window 0x%X",
                pletohs (tag_data_ptr));
@@ -849,12 +939,45 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
       break;
 
 
+    case TAG_COUNTRY_INFO:
+      memset (out_buff, 0, SHORT_STR);
+
+      snprintf (out_buff, SHORT_STR, "Country Code: %c%c, %s Environment",
+               tag_data_ptr[0], tag_data_ptr[1], 
+               val_to_str(tag_data_ptr[2], environment_vals,"Unknown (0x%02x)"));
 
-    case TAG_CHALLENGE_TEXT:
-      proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
-                                 "Tag Number: %u (Challenge text)", tag_no);
+      n = strlen (out_buff);
+
+      for (i = 3; (i + 3) <= tag_len && n < SHORT_STR; i += 3)
+      { 
+        ret = snprintf(out_buff + n, SHORT_STR - n,
+                       ", Start Channel: %u, Channels: %u, Max TX Power: %d dBm",
+                       tag_data_ptr[i], tag_data_ptr[i + 1],
+                       (gint)tag_data_ptr[i + 2]);
+
+        if (ret == -1 || ret >= SHORT_STR - n) {
+          /* Some versions of snprintf return -1 if they'd truncate
+             the output. Others return <buf_size> or greater.  */
+          break;
+        }
+        n += ret;
+      }
+
+      proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,tag_len, out_buff);
+      break;
 
-      proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
+
+    case TAG_FH_HOPPING_PARAMETER:
+      memset (out_buff, 0, SHORT_STR);
+      snprintf (out_buff, SHORT_STR, "Prime Radix: %u, Number of Channels: %u", 
+                       tag_data_ptr[0], tag_data_ptr[1]);
+      proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2, tag_len, out_buff);
+                            
+
+      break;
+
+
+    case TAG_CHALLENGE_TEXT:
       memset (out_buff, 0, SHORT_STR);
       snprintf (out_buff, SHORT_STR, "Challenge text: %.47s", tag_data_ptr);
       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
@@ -862,13 +985,56 @@ add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset)
 
       break;
 
+
+
+    case TAG_ERP_INFO:
+    case TAG_ERP_INFO_OLD:
+      memset (out_buff, 0, SHORT_STR);
+
+      snprintf (out_buff, SHORT_STR,
+               "ERP info: 0x%x (%sNon-ERP STAs, %suse protection, %s preambles)",
+               tag_data_ptr[0],
+               tag_data_ptr[0] & 0x01 ? "" : "no ",
+               tag_data_ptr[0] & 0x02 ? "" : "do not ",
+               tag_data_ptr[0] & 0x04 ? "short or long": "long");
+      proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
+                            tag_len, out_buff);
+
+      break;
+
+    case TAG_VENDOR_SPECIFIC_IE:
+      dissect_vendor_specific_ie(tree, tvb, offset + 2, tag_len,
+                                tag_data_ptr);
+      break;
+
+
     default:
-      return 0;
+      proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
+                            tag_len, "Not interpreted");
+      break;
     }
 
   return tag_len + 2;
 }
 
+void
+ieee_80211_add_tagged_parameters (tvbuff_t * tvb, int offset, proto_tree * tree,
+       int tagged_parameters_len)
+{
+  int next_len;
+
+  while (tagged_parameters_len > 0) {
+    if ((next_len=add_tagged_field (tree, tvb, offset))==0)
+      break;
+    if (next_len > tagged_parameters_len) {
+      /* XXX - flag this as an error? */
+      next_len = tagged_parameters_len;
+    }
+    offset += next_len;
+    tagged_parameters_len -= next_len;
+  }
+}
+
 /* ************************************************************************* */
 /*                     Dissect 802.11 management frame                       */
 /* ************************************************************************* */
@@ -880,8 +1046,7 @@ dissect_ieee80211_mgt (guint16 fcf, tvbuff_t * tvb, packet_info * pinfo,
   proto_tree *mgt_tree;
   proto_tree *fixed_tree;
   proto_tree *tagged_tree;
-  guint32 next_idx;
-  guint32 next_len;
+  int offset;
   int tagged_parameter_tree_len;
 
   CHECK_DISPLAY_AS_X(data_handle,proto_wlan_mgt, tvb, pinfo, tree);
@@ -899,18 +1064,14 @@ dissect_ieee80211_mgt (guint16 fcf, tvbuff_t * tvb, packet_info * pinfo,
          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 */
+         offset = 4;   /* Size of fixed fields */
          tagged_parameter_tree_len =
-             tvb_reported_length_remaining(tvb, next_idx);
-         tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx,
+             tvb_reported_length_remaining(tvb, offset);
+         tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, offset,
                                                   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;
-         }
+         ieee_80211_add_tagged_parameters (tvb, offset, tagged_tree,
+             tagged_parameter_tree_len);
          break;
 
 
@@ -920,19 +1081,15 @@ dissect_ieee80211_mgt (guint16 fcf, tvbuff_t * tvb, packet_info * pinfo,
          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 */
+         offset = 6;   /* Size of fixed fields */
 
          tagged_parameter_tree_len =
-             tvb_reported_length_remaining(tvb, next_idx);
-         tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx,
+             tvb_reported_length_remaining(tvb, offset);
+         tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, offset,
                                                   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;
-         }
+         ieee_80211_add_tagged_parameters (tvb, offset, tagged_tree,
+             tagged_parameter_tree_len);
          break;
 
 
@@ -942,18 +1099,14 @@ dissect_ieee80211_mgt (guint16 fcf, tvbuff_t * tvb, packet_info * pinfo,
          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 */
+         offset = 10;  /* Size of fixed fields */
          tagged_parameter_tree_len =
-             tvb_reported_length_remaining(tvb, next_idx);
-         tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx,
+             tvb_reported_length_remaining(tvb, offset);
+         tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, offset,
                                                   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;
-         }
+         ieee_80211_add_tagged_parameters (tvb, offset, tagged_tree,
+             tagged_parameter_tree_len);
          break;
 
        case MGT_REASSOC_RESP:
@@ -962,34 +1115,26 @@ dissect_ieee80211_mgt (guint16 fcf, tvbuff_t * tvb, packet_info * pinfo,
          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 */
+         offset = 6;   /* Size of fixed fields */
          tagged_parameter_tree_len =
-             tvb_reported_length_remaining(tvb, next_idx);
-         tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx,
+             tvb_reported_length_remaining(tvb, offset);
+         tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, offset,
                                                   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;
-         }
+         ieee_80211_add_tagged_parameters (tvb, offset, tagged_tree,
+             tagged_parameter_tree_len);
          break;
 
 
        case MGT_PROBE_REQ:
-         next_idx = 0;
+         offset = 0;
          tagged_parameter_tree_len =
-             tvb_reported_length_remaining(tvb, next_idx);
-         tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx,
+             tvb_reported_length_remaining(tvb, offset);
+         tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, offset,
                                                   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;
-         }
+         ieee_80211_add_tagged_parameters (tvb, offset, tagged_tree,
+             tagged_parameter_tree_len);
          break;
 
 
@@ -999,18 +1144,14 @@ dissect_ieee80211_mgt (guint16 fcf, tvbuff_t * tvb, packet_info * pinfo,
          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 */
+         offset = 12;  /* Size of fixed fields */
          tagged_parameter_tree_len =
-             tvb_reported_length_remaining(tvb, next_idx);
-         tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx,
+             tvb_reported_length_remaining(tvb, offset);
+         tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, offset,
                                                   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;
-         }
+         ieee_80211_add_tagged_parameters (tvb, offset, tagged_tree,
+             tagged_parameter_tree_len);
          break;
 
 
@@ -1021,18 +1162,14 @@ dissect_ieee80211_mgt (guint16 fcf, tvbuff_t * tvb, packet_info * pinfo,
          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 */
+         offset = 12;  /* Size of fixed fields */
          tagged_parameter_tree_len =
-             tvb_reported_length_remaining(tvb, next_idx);
-         tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx,
+             tvb_reported_length_remaining(tvb, offset);
+         tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, offset,
                                                   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;
-         }
+         ieee_80211_add_tagged_parameters (tvb, offset, tagged_tree,
+             tagged_parameter_tree_len);
          break;
 
 
@@ -1052,23 +1189,19 @@ dissect_ieee80211_mgt (guint16 fcf, tvbuff_t * tvb, packet_info * pinfo,
          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 */
+         offset = 6;   /* Size of fixed fields */
 
          tagged_parameter_tree_len =
-                 tvb_reported_length_remaining(tvb, next_idx);
+                 tvb_reported_length_remaining(tvb, offset);
          if (tagged_parameter_tree_len != 0)
            {
              tagged_tree = get_tagged_parameter_tree (mgt_tree,
                                                       tvb,
-                                                      next_idx,
+                                                      offset,
                                                       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;
-             }
+             ieee_80211_add_tagged_parameters (tvb, offset, tagged_tree,
+               tagged_parameter_tree_len);
            }
          break;
 
@@ -1109,7 +1242,8 @@ set_dst_addr_cols(packet_info *pinfo, const guint8 *addr, char *type)
 static void
 dissect_ieee80211_common (tvbuff_t * tvb, packet_info * pinfo,
                          proto_tree * tree, gboolean fixed_length_header,
-                         gboolean has_radio_information, gboolean has_no_fcs)
+                         gboolean has_radio_information, gboolean has_no_fcs,
+                         gboolean wlan_broken_fc)
 {
   guint16 fcf, flags, frame_type_subtype;
   guint16 seq_control;
@@ -1135,6 +1269,10 @@ dissect_ieee80211_common (tvbuff_t * tvb, packet_info * pinfo,
     col_clear (pinfo->cinfo, COL_INFO);
 
   fcf = tvb_get_letohs (tvb, 0);
+  if (wlan_broken_fc) {
+    /* Swap bytes */
+    fcf = ((fcf & 0xff) << 8) | (((fcf & 0xff00) >> 8) & 0xff);
+  }
   if (fixed_length_header)
     hdr_len = DATA_LONG_HDR_LEN;
   else
@@ -1175,54 +1313,71 @@ dissect_ieee80211_common (tvbuff_t * tvb, packet_info * pinfo,
       }
 
       proto_tree_add_uint (hdr_tree, hf_fc_frame_type_subtype,
-                          tvb, 0, 1,
+                          tvb, 
+                          wlan_broken_fc?1:0, 1,
                           frame_type_subtype);
 
-      fc_item = proto_tree_add_uint_format (hdr_tree, hf_fc_field, tvb, 0, 2,
+      fc_item = proto_tree_add_uint_format (hdr_tree, hf_fc_field, tvb, 
+                                           0, 2,
                                            fcf,
-                                           "Frame Control: 0x%04X",
-                                           fcf);
+                                           "Frame Control: 0x%04X (%s)",
+                                           fcf, wlan_broken_fc?"Swapped":"Normal");
 
       fc_tree = proto_item_add_subtree (fc_item, ett_fc_tree);
 
 
-      proto_tree_add_uint (fc_tree, hf_fc_proto_version, tvb, 0, 1,
+      proto_tree_add_uint (fc_tree, hf_fc_proto_version, tvb, 
+                          wlan_broken_fc?1:0, 1,
                           COOK_PROT_VERSION (fcf));
 
-      proto_tree_add_uint (fc_tree, hf_fc_frame_type, tvb, 0, 1,
+      proto_tree_add_uint (fc_tree, hf_fc_frame_type, tvb, 
+                          wlan_broken_fc?1:0, 1,
                           COOK_FRAME_TYPE (fcf));
 
       proto_tree_add_uint (fc_tree, hf_fc_frame_subtype,
-                          tvb, 0, 1,
+                          tvb, 
+                          wlan_broken_fc?1:0, 1,
                           COOK_FRAME_SUBTYPE (fcf));
 
       flag_item =
-       proto_tree_add_uint_format (fc_tree, hf_fc_flags, tvb, 1, 1,
+       proto_tree_add_uint_format (fc_tree, hf_fc_flags, tvb, 
+                                   wlan_broken_fc?0:1, 1,
                                    flags, "Flags: 0x%X", flags);
 
       flag_tree = proto_item_add_subtree (flag_item, ett_proto_flags);
 
-      proto_tree_add_uint (flag_tree, hf_fc_data_ds, tvb, 1, 1,
+      proto_tree_add_uint (flag_tree, hf_fc_data_ds, tvb, 
+                          wlan_broken_fc?0:1, 1,
                           COOK_DS_STATUS (flags));
+      proto_tree_add_boolean_hidden (flag_tree, hf_fc_to_ds, tvb, 1, 1, 
+                                    flags);
+      proto_tree_add_boolean_hidden (flag_tree, hf_fc_from_ds, tvb, 1, 1, 
+                                    flags);
 
-      proto_tree_add_boolean (flag_tree, hf_fc_more_frag, tvb, 1, 1,
+      proto_tree_add_boolean (flag_tree, hf_fc_more_frag, tvb, 
+                             wlan_broken_fc?0:1, 1,
                              flags);
 
-      proto_tree_add_boolean (flag_tree, hf_fc_retry, tvb, 1, 1, flags);
+      proto_tree_add_boolean (flag_tree, hf_fc_retry, tvb, 
+                             wlan_broken_fc?0:1, 1, flags);
 
-      proto_tree_add_boolean (flag_tree, hf_fc_pwr_mgt, tvb, 1, 1, flags);
+      proto_tree_add_boolean (flag_tree, hf_fc_pwr_mgt, tvb, 
+                             wlan_broken_fc?0:1, 1, flags);
 
-      proto_tree_add_boolean (flag_tree, hf_fc_more_data, tvb, 1, 1,
+      proto_tree_add_boolean (flag_tree, hf_fc_more_data, tvb, 
+                             wlan_broken_fc?0:1, 1,
                              flags);
 
-      proto_tree_add_boolean (flag_tree, hf_fc_wep, tvb, 1, 1, flags);
+      proto_tree_add_boolean (flag_tree, hf_fc_wep, tvb,
+                             wlan_broken_fc?0:1, 1, flags);
 
-      proto_tree_add_boolean (flag_tree, hf_fc_order, tvb, 1, 1, flags);
+      proto_tree_add_boolean (flag_tree, hf_fc_order, tvb, 
+                             wlan_broken_fc?0:1, 1, flags);
 
-      if (frame_type_subtype == 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)));
-     
+
       else
          proto_tree_add_uint (hdr_tree, hf_did_duration, tvb, 2, 2,
                               tvb_get_letohs (tvb, 2));
@@ -1426,8 +1581,8 @@ dissect_ieee80211_common (tvbuff_t * tvb, packet_info * pinfo,
              proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 4, 6, dst);
              proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 10, 6, src);
              break;
-             
-             
+
+
            case DATA_ADDR_T2:
              proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 4, 6, dst);
              proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 10, 6,
@@ -1442,7 +1597,7 @@ dissect_ieee80211_common (tvbuff_t * tvb, packet_info * pinfo,
              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,
@@ -1459,7 +1614,7 @@ dissect_ieee80211_common (tvbuff_t * tvb, packet_info * pinfo,
              proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 10, 6, src);
              proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 16, 6, dst);
              break;
-             
+
 
            case DATA_ADDR_T4:
              proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6,
@@ -1525,7 +1680,19 @@ dissect_ieee80211_common (tvbuff_t * tvb, packet_info * pinfo,
          len -= 4;
          reported_len -= 4;
          if (tree)
-           proto_tree_add_item (hdr_tree, hf_fcs, tvb, hdr_len + len, 4, FALSE);
+           {
+             guint32 fcs = crc32_tvb_802(tvb, hdr_len + len);
+             guint32 sent_fcs = tvb_get_ntohl(tvb, hdr_len + len);
+             if (fcs == sent_fcs)
+               proto_tree_add_uint_format(hdr_tree, hf_fcs, tvb,
+                       hdr_len + len, 4, sent_fcs,
+                       "Frame check sequence: 0x%08x (correct)", sent_fcs);
+             else
+               proto_tree_add_uint_format(hdr_tree, hf_fcs, tvb,
+                       hdr_len + len, 4, sent_fcs,
+                       "Frame check sequence: 0x%08x (incorrect, should be 0x%08x)",
+                       sent_fcs, fcs);
+           }
        }
     }
 
@@ -1565,7 +1732,18 @@ dissect_ieee80211_common (tvbuff_t * tvb, packet_info * pinfo,
      */
     gboolean can_decrypt = FALSE;
     proto_tree *wep_tree = NULL;
+    guint32 iv;
+    guint8 key;
 
+    /*
+     * XXX - pass the IV and key to "try_decrypt_wep()", and have it pass
+     * them to "wep_decrypt()", rather than having "wep_decrypt()" extract
+     * them itself.
+     *
+     * Also, just pass the data *following* the WEP parameters as the
+     * buffer to decrypt.
+     */
+    iv = tvb_get_letoh24(tvb, hdr_len);
     if (tree) {
       proto_item *wep_fields;
 
@@ -1573,19 +1751,15 @@ dissect_ieee80211_common (tvbuff_t * tvb, packet_info * pinfo,
                                           "WEP parameters");
 
       wep_tree = proto_item_add_subtree (wep_fields, ett_wep_parameters);
-      proto_tree_add_item (wep_tree, hf_wep_iv, tvb, hdr_len, 3, TRUE);
-
-      proto_tree_add_uint (wep_tree, hf_wep_key, tvb, hdr_len + 3, 1,
-                          COOK_WEP_KEY (tvb_get_guint8 (tvb, hdr_len + 3)));
+      proto_tree_add_uint (wep_tree, hf_wep_iv, tvb, hdr_len, 3, iv);
     }
+    key = COOK_WEP_KEY (tvb_get_guint8 (tvb, hdr_len + 3));
+    if (tree)
+      proto_tree_add_uint (wep_tree, hf_wep_key, tvb, hdr_len + 3, 1, key);
 
     /* Subtract out the length of the IV. */
     len -= 4;
     reported_len -= 4;
-    if (len < 0 || reported_len < 0) {
-      /* We don't have anything beyond the IV. */
-      return;
-    }
 
     /*
      * Well, this packet should, in theory, have an ICV.
@@ -1624,9 +1798,6 @@ dissect_ieee80211_common (tvbuff_t * tvb, packet_info * pinfo,
        */
       len -= 4;
       reported_len -= 4;
-      if (tree)
-       proto_tree_add_item (wep_tree, hf_wep_icv, tvb, hdr_len + 4 + len, 4,
-                            FALSE);
       can_decrypt = TRUE;
     }
 
@@ -1637,9 +1808,24 @@ dissect_ieee80211_common (tvbuff_t * tvb, packet_info * pinfo,
        */
       next_tvb = tvb_new_subset(tvb, hdr_len + 4, len, reported_len);
 
+      if (tree && can_decrypt)
+       proto_tree_add_uint_format (wep_tree, hf_wep_icv, tvb, 
+                                   hdr_len + 4 + len, 4, 
+                                   tvb_get_ntohl(tvb, hdr_len + 4 + len),
+                                   "WEP ICV: 0x%08x (not verified)", 
+                                   tvb_get_ntohl(tvb, hdr_len + 4 + len));
+
       call_dissector(data_handle, next_tvb, pinfo, tree);
-      return; 
+      return;
     } else {
+
+      if (tree)
+       proto_tree_add_uint_format (wep_tree, hf_wep_icv, tvb, 
+                                   hdr_len + 4 + len, 4, 
+                                   tvb_get_ntohl(tvb, hdr_len + 4 + len),
+                                   "WEP ICV: 0x%08x (correct)", 
+                                   tvb_get_ntohl(tvb, hdr_len + 4 + len));
+
       add_new_data_source(pinfo, next_tvb, "Decrypted WEP data");
     }
 
@@ -1700,41 +1886,11 @@ dissect_ieee80211_common (tvbuff_t * tvb, packet_info * pinfo,
                                     wlan_fragment_table,
                                     wlan_reassembled_table,
                                     frag_number,
-                                    len,
+                                    reported_len,
                                     more_frags);
-    if (fd_head != NULL) {
-      /*
-       * Either this is reassembled or it wasn't fragmented
-       * (see comment above about some networking interfaces).
-       * In either case, it's now in the table of reassembled
-       * packets.
-       *
-       * If the "fragment_data" structure doesn't have a list of
-       * fragments, we assume it's a placeholder to mark those
-       * not-really-fragmented packets, and just treat this as
-       * a non-fragmented frame.
-       */
-      if (fd_head->next != NULL) {
-        next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
-        tvb_set_child_real_data_tvbuff(tvb, next_tvb);
-        add_new_data_source(pinfo, next_tvb, "Reassembled 802.11");
-
-        /* Show all fragments. */
-        show_fragment_seq_tree(fd_head, &frag_items, hdr_tree, pinfo, next_tvb);
-      } else {
-       /*
-        * Not fragmented, really.
-        * Show it as a regular frame.
-        */
-       next_tvb = tvb_new_subset (next_tvb, hdr_len, len, reported_len);
-      }
-
-      /* It's not fragmented. */
-      pinfo->fragmented = FALSE;
-    } else {
-      /* We don't have the complete reassembled payload. */
-      next_tvb = NULL;
-    }
+    next_tvb = process_reassembled_data(tvb, hdr_len, pinfo,
+                                       "Reassembled 802.11", fd_head,
+                                       &frag_items, NULL, hdr_tree);
   } else {
     /*
      * If this is the first fragment, dissect its contents, otherwise
@@ -1768,8 +1924,8 @@ dissect_ieee80211_common (tvbuff_t * tvb, packet_info * pinfo,
     call_dissector(data_handle, next_tvb, pinfo, tree);
     pinfo->fragmented = save_fragmented;
     return;
-  }  
-  
+  }
+
   switch (COOK_FRAME_TYPE (fcf))
     {
 
@@ -1816,7 +1972,7 @@ dissect_ieee80211_common (tvbuff_t * tvb, packet_info * pinfo,
 static void
 dissect_ieee80211 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
 {
-  dissect_ieee80211_common (tvb, pinfo, tree, FALSE, FALSE, FALSE);
+  dissect_ieee80211_common (tvb, pinfo, tree, FALSE, FALSE, FALSE, FALSE);
 }
 
 /*
@@ -1827,7 +1983,18 @@ static void
 dissect_ieee80211_radio (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
 {
   /* These packets do NOT have a FCS present */
-  dissect_ieee80211_common (tvb, pinfo, tree, FALSE, TRUE, TRUE);
+  dissect_ieee80211_common (tvb, pinfo, tree, FALSE, TRUE, TRUE, FALSE);
+}
+
+/*
+ * Dissect 802.11 with a variable-length link-layer header and a byte-swapped
+ * control field (some hardware sends out LWAPP-encapsulated 802.11
+ * packets with the control field byte swapped).
+ */
+static void
+dissect_ieee80211_bsfc (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
+{
+  dissect_ieee80211_common (tvb, pinfo, tree, FALSE, FALSE, FALSE, TRUE);
 }
 
 /*
@@ -1837,7 +2004,7 @@ dissect_ieee80211_radio (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
 static void
 dissect_ieee80211_fixed (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
 {
-  dissect_ieee80211_common (tvb, pinfo, tree, TRUE, FALSE, FALSE);
+  dissect_ieee80211_common (tvb, pinfo, tree, TRUE, FALSE, FALSE, FALSE);
 }
 
 static void
@@ -1848,7 +2015,7 @@ wlan_defragment_init(void)
 }
 
 void
-proto_register_wlan (void)
+proto_register_ieee80211 (void)
 {
   static const value_string frame_type[] = {
     {MGT_FRAME,     "Management frame"},
@@ -1866,13 +2033,13 @@ proto_register_wlan (void)
   };
 
   static const true_false_string tods_flag = {
-    "TO DS: Should be false",
-    "Not used"
+    "Frame is entering DS",
+    "Frame is not entering DS"
   };
 
   static const true_false_string fromds_flag = {
-    "FROM DS: Should be false",
-    "Not used"
+    "Frame is exiting DS",
+    "Frame is not exiting DS"
   };
 
   static const true_false_string more_frags = {
@@ -1931,6 +2098,16 @@ proto_register_wlan (void)
     "Channel agility not in use"
   };
 
+  static const true_false_string short_slot_time_flags = {
+    "Short slot time in use",
+    "Short slot time not in use"
+  };
+
+  static const true_false_string dsss_ofdm_flags = {
+    "DSSS-OFDM modulation allowed",
+    "DSSS-OFDM modulation not allowed"
+  };
+
 
   static const true_false_string cf_ibss_flags = {
     "Transmitter belongs to an IBSS",
@@ -2001,6 +2178,16 @@ proto_register_wlan (void)
      "associated stations"},
     {0x12, "Association denied due to requesting station not supporting all "
      "of the datarates in the BSSBasicServiceSet Parameter"},
+    {0x13, "Association denied due to requesting station not supporting "
+     "short preamble operation"},
+    {0x14, "Association denied due to requesting station not supporting "
+     "PBCC encoding"},
+    {0x15, "Association denied due to requesting station not supporting "
+     "channel agility"},
+    {0x19, "Association denied due to requesting station not supporting "
+     "short slot operation"},
+    {0x1A, "Association denied due to requesting station not supporting "
+     "DSSS-OFDM operation"},
     {0x00, NULL}
   };
 
@@ -2118,7 +2305,7 @@ proto_register_wlan (void)
       "Sequence number", HFILL }},
 
     {&hf_fcs,
-     {"Frame Check Sequence (not verified)", "wlan.fcs", FT_UINT32, BASE_HEX,
+     {"Frame check sequence", "wlan.fcs", FT_UINT32, BASE_HEX,
       NULL, 0, "FCS", HFILL }},
 
     {&hf_fragment_overlap,
@@ -2142,17 +2329,21 @@ proto_register_wlan (void)
 
     {&hf_fragment_error,
       {"Defragmentation error", "wlan.fragment.error",
-       FT_NONE, BASE_NONE, NULL, 0x0,
+       FT_FRAMENUM, BASE_NONE, NULL, 0x0,
        "Defragmentation error due to illegal fragments", HFILL }},
 
     {&hf_fragment,
-      {"802.11 Fragment", "wlan.fragment", FT_NONE, BASE_NONE, NULL, 0x0,
+      {"802.11 Fragment", "wlan.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
        "802.11 Fragment", HFILL }},
 
     {&hf_fragments,
       {"802.11 Fragments", "wlan.fragments", FT_NONE, BASE_NONE, NULL, 0x0,
        "802.11 Fragments", HFILL }},
 
+    {&hf_reassembled_in,
+      {"Reassembled 802.11 in frame", "wlan.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+       "This 802.11 packet is reassembled in this frame", HFILL }},
+
     {&hf_wep_iv,
      {"Initialization Vector", "wlan.wep.iv", FT_UINT24, BASE_HEX, NULL, 0,
       "Initialization Vector", HFILL }},
@@ -2162,7 +2353,7 @@ proto_register_wlan (void)
       "Key", HFILL }},
 
     {&hf_wep_icv,
-     {"WEP ICV (not verified)", "wlan.wep.icv", FT_UINT32, BASE_HEX, NULL, 0,
+     {"WEP ICV", "wlan.wep.icv", FT_UINT32, BASE_HEX, NULL, 0,
       "WEP ICV", HFILL }},
   };
 
@@ -2191,39 +2382,49 @@ proto_register_wlan (void)
      {"Capabilities", "wlan_mgt.fixed.capabilities", FT_UINT16, BASE_HEX, NULL, 0,
       "Capability information", HFILL }},
 
+    {&ff_cf_ess,
+     {"ESS capabilities", "wlan_mgt.fixed.capabilities.ess",
+      FT_BOOLEAN, 16, TFS (&cf_ess_flags), 0x0001, "ESS capabilities", HFILL }},
+
+    {&ff_cf_ibss,
+     {"IBSS status", "wlan_mgt.fixed.capabilities.ibss",
+      FT_BOOLEAN, 16, TFS (&cf_ibss_flags), 0x0002, "IBSS participation", HFILL }},
+
     {&ff_cf_sta_poll,
      {"CFP participation capabilities", "wlan_mgt.fixed.capabilities.cfpoll.sta",
-      FT_UINT16, BASE_HEX, VALS (&sta_cf_pollable), 0,
+      FT_UINT16, BASE_HEX, VALS (&sta_cf_pollable), 0x000C,
       "CF-Poll capabilities for a STA", HFILL }},
 
     {&ff_cf_ap_poll,
      {"CFP participation capabilities", "wlan_mgt.fixed.capabilities.cfpoll.ap",
-      FT_UINT16, BASE_HEX, VALS (&ap_cf_pollable), 0,
+      FT_UINT16, BASE_HEX, VALS (&ap_cf_pollable), 0x000C,
       "CF-Poll capabilities for an AP", HFILL }},
 
-    {&ff_cf_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_mgt.fixed.capabilities.ibss",
-      FT_BOOLEAN, 8, TFS (&cf_ibss_flags), 0x0002, "IBSS participation", HFILL }},
     {&ff_cf_privacy,
      {"Privacy", "wlan_mgt.fixed.capabilities.privacy",
-      FT_BOOLEAN, 8, TFS (&cf_privacy_flags), 0x0010, "WEP support", HFILL }},
+      FT_BOOLEAN, 16, TFS (&cf_privacy_flags), 0x0010, "WEP support", HFILL }},
 
     {&ff_cf_preamble,
      {"Short Preamble", "wlan_mgt.fixed.capabilities.preamble",
-      FT_BOOLEAN, 8, TFS (&cf_preamble_flags), 0x0020, "Short Preamble", HFILL }},
+      FT_BOOLEAN, 16, TFS (&cf_preamble_flags), 0x0020, "Short Preamble", HFILL }},
 
     {&ff_cf_pbcc,
      {"PBCC", "wlan_mgt.fixed.capabilities.pbcc",
-      FT_BOOLEAN, 8, TFS (&cf_pbcc_flags), 0x0040, "PBCC Modulation", HFILL }},
+      FT_BOOLEAN, 16, TFS (&cf_pbcc_flags), 0x0040, "PBCC Modulation", HFILL }},
 
     {&ff_cf_agility,
      {"Channel Agility", "wlan_mgt.fixed.capabilities.agility",
-      FT_BOOLEAN, 8, TFS (&cf_agility_flags), 0x0080, "Channel Agility", HFILL }},
+      FT_BOOLEAN, 16, TFS (&cf_agility_flags), 0x0080, "Channel Agility", HFILL }},
+
+    {&ff_short_slot_time,
+     {"Short Slot Time", "wlan_mgt.fixed.capabilities.short_slot_time",
+      FT_BOOLEAN, 16, TFS (&short_slot_time_flags), 0x0400, "Short Slot Time",
+      HFILL }},
+
+    {&ff_dsss_ofdm,
+     {"DSSS-OFDM", "wlan_mgt.fixed.capabilities.dsss_ofdm",
+      FT_BOOLEAN, 16, TFS (&dsss_ofdm_flags), 0x2000, "DSSS-OFDM Modulation",
+      HFILL }},
 
     {&ff_auth_seq,
      {"Authentication SEQ", "wlan_mgt.fixed.auth_seq",
@@ -2253,12 +2454,12 @@ proto_register_wlan (void)
 
     {&tag_number,
      {"Tag", "wlan_mgt.tag.number",
-      FT_UINT16, BASE_DEC, NULL, 0,
+      FT_UINT8, BASE_DEC, VALS(tag_num_vals), 0,
       "Element ID", HFILL }},
 
     {&tag_length,
      {"Tag length", "wlan_mgt.tag.length",
-      FT_UINT16, BASE_DEC, NULL, 0, "Length of tag", HFILL }},
+      FT_UINT8, BASE_DEC, NULL, 0, "Length of tag", HFILL }},
 
     {&tag_interpretation,
      {"Tag interpretation", "wlan_mgt.tag.interpretation",
@@ -2300,10 +2501,11 @@ proto_register_wlan (void)
 
   register_dissector("wlan", dissect_ieee80211, proto_wlan);
   register_dissector("wlan_fixed", dissect_ieee80211_fixed, proto_wlan);
+  register_dissector("wlan_bsfc", dissect_ieee80211_bsfc, proto_wlan);
   register_init_routine(wlan_defragment_init);
 
   /* Register configuration options */
-  wlan_module = prefs_register_protocol(proto_wlan, NULL);
+  wlan_module = prefs_register_protocol(proto_wlan, init_wepkeys);
   prefs_register_bool_preference(wlan_module, "defragment",
        "Reassemble fragmented 802.11 datagrams",
        "Whether fragmented 802.11 datagrams should be reassembled",
@@ -2320,32 +2522,32 @@ proto_register_wlan (void)
                                 &wlan_ignore_wep);
 
 #ifndef USE_ENV
-  prefs_register_enum_preference(wlan_module, "wep_keys", 
+  prefs_register_enum_preference(wlan_module, "wep_keys",
                                 "WEP key count",
                                 "How many WEP keys do we have to choose from? (0 to disable, up to 4)",
                                 &num_wepkeys, wep_keys_options, FALSE);
 
   prefs_register_string_preference(wlan_module, "wep_key1",
                                   "WEP key #1",
-                                  "First WEP key (A:B:C:D:E:F)",
+                                  "First WEP key (A:B:C:D:E) [40bit], (A:B:C:D:E:F:G:H:I:J:K:L:M) [104bit], or whatever key length you're using",
                                   &wep_keystr[0]);
   prefs_register_string_preference(wlan_module, "wep_key2",
                                   "WEP key #2",
-                                  "Second WEP key (A:B:C:D:E:F)",
+                                  "Second WEP key (A:B:C:D:E) [40bit], (A:B:C:D:E:F:G:H:I:J:K:L:M) [104bit], or whatever key length you're using",
                                   &wep_keystr[1]);
   prefs_register_string_preference(wlan_module, "wep_key3",
                                   "WEP key #3",
-                                  "Third WEP key (A:B:C:D:E:F)",
+                                  "Third WEP key (A:B:C:D:E) [40bit], (A:B:C:D:E:F:G:H:I:J:K:L:M) [104bit], or whatever key length you're using",
                                   &wep_keystr[2]);
   prefs_register_string_preference(wlan_module, "wep_key4",
                                   "WEP key #4",
-                                  "Fourth WEP key (A:B:C:D:E:F)",
+                                  "Fourth WEP key (A:B:C:D:E) [40bit] (A:B:C:D:E:F:G:H:I:J:K:L:M) [104bit], or whatever key length you're using",
                                   &wep_keystr[3]);
 #endif
 }
 
 void
-proto_reg_handoff_wlan(void)
+proto_reg_handoff_ieee80211(void)
 {
   dissector_handle_t ieee80211_handle;
   dissector_handle_t ieee80211_radio_handle;
@@ -2365,61 +2567,6 @@ proto_reg_handoff_wlan(void)
                ieee80211_radio_handle);
 }
 
-static const guint32 wep_crc32_table[256] = {
-        0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
-        0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
-        0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
-        0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
-        0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
-        0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
-        0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
-        0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
-        0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
-        0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
-        0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
-        0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
-        0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
-        0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
-        0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
-        0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
-        0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
-        0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
-        0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
-        0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
-        0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
-        0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
-        0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
-        0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
-        0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
-        0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
-        0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
-        0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
-        0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
-        0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
-        0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
-        0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
-        0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
-        0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
-        0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
-        0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
-        0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
-        0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
-        0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
-        0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
-        0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
-        0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
-        0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
-        0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
-        0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
-        0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
-        0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
-        0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
-        0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
-        0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
-        0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
-        0x2d02ef8dL
-};
-
 static tvbuff_t *try_decrypt_wep(tvbuff_t *tvb, guint32 offset, guint32 len) {
   guint8 *tmp = NULL;
   int i;
@@ -2427,12 +2574,10 @@ static tvbuff_t *try_decrypt_wep(tvbuff_t *tvb, guint32 offset, guint32 len) {
 
   if (num_wepkeys < 1)
     return NULL;
-  if (wep_keylens == NULL)
-    init_wepkeys();
 
   if ((tmp = g_malloc(len)) == NULL)
     return NULL;  /* krap! */
-  
+
   /* try once with the key index in the packet, then look through our list. */
   for (i = -1; i < (int) num_wepkeys; i++) {
     /* copy the encrypted data over to the tmp buffer */
@@ -2452,11 +2597,11 @@ static tvbuff_t *try_decrypt_wep(tvbuff_t *tvb, guint32 offset, guint32 len) {
   }
 
  done:
-  if ((!decr_tvb) && (tmp))    free(tmp);
+  if ((!decr_tvb) && (tmp))    g_free(tmp);
 
 #if 0
   printf("de-wep %p\n", decr_tvb);
-#endif 
+#endif
 
   return decr_tvb;
 }
@@ -2525,7 +2670,7 @@ static int wep_decrypt(guint8 *buf, guint32 len, int key_override) {
 #if 0
     printf("%02x\n", *dpos);
 #endif
-    crc = wep_crc32_table[(crc ^ *dpos++) & 0xff] ^ (crc >> 8);
+    crc = crc32_table[(crc ^ *dpos++) & 0xff] ^ (crc >> 8);
   }
   crc = ~crc;
 
@@ -2534,7 +2679,7 @@ static int wep_decrypt(guint8 *buf, guint32 len, int key_override) {
   c_crc[1] = crc >> 8;
   c_crc[2] = crc >> 16;
   c_crc[3] = crc >> 24;
-  
+
   for (k = 0; k < 4; k++) {
     i = (i + 1) & 0xff;
     j = (j+s[i]) & 0xff;
@@ -2549,12 +2694,10 @@ static int wep_decrypt(guint8 *buf, guint32 len, int key_override) {
   return 0;
 }
 
-/* XXX need to verify these malloc()s succeed */
-
 static void init_wepkeys(void) {
   char *tmp, *tmp2;
   guint8 *tmp3;
-  uint i, j;
+  guint i, j;
 
 #ifdef USE_ENV
   guint8 buf[128];
@@ -2573,11 +2716,14 @@ static void init_wepkeys(void) {
   if (num_wepkeys < 1)
     return;
 
-  if (wep_keylens != NULL)
-    return;
+  if (wep_keys)
+    g_free(wep_keys);
 
-  wep_keys = malloc(num_wepkeys * sizeof(guint8*));
-  wep_keylens = malloc(num_wepkeys * sizeof(int));
+  if (wep_keylens)
+    g_free(wep_keylens);
+
+  wep_keys = g_malloc(num_wepkeys * sizeof(guint8*));
+  wep_keylens = g_malloc(num_wepkeys * sizeof(int));
 
   for (i = 0 ; i < num_wepkeys; i++) {
     wep_keys[i] = NULL;
@@ -2600,7 +2746,9 @@ static void init_wepkeys(void) {
 #endif
 #endif
 
-      wep_keys[i] = malloc(32 * sizeof(guint8));
+      if (wep_keys[i])
+       g_free(wep_keys[i]);
+      wep_keys[i] = g_malloc(32 * sizeof(guint8));
       memset(wep_keys[i], 0, 32 * sizeof(guint8));
       tmp3 = wep_keys[i];
       while ((tmp != NULL) && (*tmp != 0)) {
@@ -2616,7 +2764,7 @@ static void init_wepkeys(void) {
        j++;
       }
     }
-    
+
   }
 
   return;