Ethereal-dev: [Ethereal-dev] 802.11

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Javier Achirica <achirica@xxxxxxx>
Date: Thu, 31 May 2001 15:39:03 +0200 (MEST)
Hello,

I've been enhancing the Cisco Aironet wireless driver to support raw
802.11 packet capture. With a small patch to libpcap I'm able to use
ethereal to see that traffic, but I've found a few bugs in the dissector.

Enclosed is a patch that fixes most of them and adds missing info. Do I
have to talk with someone to get it integrated in the code?

Javier Achirica
--- packet-ieee80211.c.FCS	Mon Apr 23 18:57:55 2001
+++ packet-ieee80211.c	Wed May 30 23:49:02 2001
@@ -72,12 +72,14 @@
 #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 & 0x2)) && ((x & 0x1)))
+#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 COL_SHOW_INFO(fd,info) if (check_col(fd,COL_INFO)) \
 col_add_str(fd,COL_INFO,info);
 
@@ -135,10 +137,10 @@
 #define DATA_CF_POLL_NOD     0x26       /* Data - Data + CF poll (No data)         */
 #define DATA_CF_ACK_POLL_NOD 0x27	/* Data - CF ack + CF poll (no data)       */
 
-#define DATA_ADDR_T1         0x00
-#define DATA_ADDR_T2         0x01
-#define DATA_ADDR_T3         0x02
-#define DATA_ADDR_T4         0x03
+#define DATA_ADDR_T1         0x0000
+#define DATA_ADDR_T2         0x0100
+#define DATA_ADDR_T3         0x0200
+#define DATA_ADDR_T4         0x0300
 
 
 /* ************************************************************************* */
@@ -250,6 +252,9 @@
 static int ff_cf_ess = -1;
 static int ff_cf_ibss = -1;
 static int ff_cf_privacy = -1;
+static int ff_cf_preamble = -1;
+static int ff_cf_pbcc = -1;
+static int ff_cf_agility = -1;
 
 /* ************************************************************************* */
 /*                       Tagged value format fields                          */
@@ -262,6 +267,10 @@
 
 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;
 
 /* ************************************************************************* */
 /*                               Protocol trees                              */
@@ -272,6 +281,7 @@
 static gint ett_fc_tree = -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;
 
@@ -283,7 +293,7 @@
 {
   guint16 frame_control;
 
-  frame_control = pntohs (pd);
+  frame_control = COOK_FLAGS(pletohs (pd));
   return ((IS_FROM_DS(frame_control))
 	  && (IS_TO_DS(frame_control))) ? 30 : 24;
 }
@@ -302,6 +312,12 @@
 
   hdr_length = MGT_FRAME_HDR_LEN;	/* Set the header length of the frame */
 
+  if (IS_WEP(COOK_FLAGS(fcf)))
+    {
+      ld->other++;
+      return;
+    }
+
   switch (COMPOSE_FRAME_TYPE (fcf))
     {
 
@@ -369,6 +385,30 @@
 }
 
 
+/* ************************************************************************* */
+/*            Add the subtree used to store WEP parameters                   */
+/* ************************************************************************* */
+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_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_uint (wep_tree, hf_wep_key, tvb, start + 3, 1,
+		       COOK_WEP_KEY (tvb_get_letohl (tvb, start)));
+
+  if (tvb_bytes_exist(tvb, start + crc_offset, 4))
+    proto_tree_add_uint (wep_tree, hf_wep_crc, tvb, start + crc_offset, 4,
+			 tvb_get_ntohl (tvb, start + crc_offset));
+}
 
 /* ************************************************************************* */
 /*              Dissect and add fixed mgmt fields to protocol tree           */
@@ -388,14 +428,8 @@
       dataptr = tvb_get_ptr (tvb, offset, 8);
       memset (out_buff, 0, SHORT_STR);
       snprintf (out_buff, SHORT_STR, "0x%02X%02X%02X%02X%02X%02X%02X%02X",
-		BIT_SWAP (dataptr[7]),
-		BIT_SWAP (dataptr[6]),
-		BIT_SWAP (dataptr[5]),
-		BIT_SWAP (dataptr[4]),
-		BIT_SWAP (dataptr[3]),
-		BIT_SWAP (dataptr[2]),
-		BIT_SWAP (dataptr[1]),
-		BIT_SWAP (dataptr[0]));
+		dataptr[7], dataptr[6], dataptr[5], dataptr[4],
+		dataptr[3], dataptr[2], dataptr[1], dataptr[0]);
 
       proto_tree_add_string (tree, ff_timestamp, tvb, offset, 8, out_buff);
       break;
@@ -403,110 +437,93 @@
 
     case FIELD_BEACON_INTERVAL:
       dataptr = tvb_get_ptr (tvb, offset, 2);
-      out_buff[0] = BIT_SWAP (dataptr[1]);
-      out_buff[1] = BIT_SWAP (dataptr[0]);
-      temp16 = (guint16 *) out_buff;
+      temp16 = (guint16 *) dataptr;
       proto_tree_add_uint (tree, ff_beacon_interval, tvb, offset, 2,
-			   pntohs (temp16));
+			   pletohs (temp16));
       break;
 
 
     case FIELD_CAP_INFO:
       dataptr = tvb_get_ptr (tvb, offset, 2);
-      out_buff[0] = BIT_SWAP (dataptr[1]);
-      out_buff[0] = BIT_SWAP (dataptr[0]);
-      temp16 = (guint16 *) out_buff;
+      temp16 = (guint16 *) dataptr;
 
       cap_item = proto_tree_add_uint_format (tree, ff_capture, 
 					     tvb, offset, 2,
-					     pntohs (temp16),
+					     pletohs (temp16),
 					     "Capability Information: %04X",
-					     pntohs (temp16));
+					     pletohs (temp16));
       cap_tree = proto_item_add_subtree (cap_item, ett_cap_tree);
       proto_tree_add_boolean (cap_tree, ff_cf_ess, tvb, offset, 1,
-			      pntohs (temp16));
+			      pletohs (temp16));
       proto_tree_add_boolean (cap_tree, ff_cf_ibss, tvb, offset, 1,
-			      pntohs (temp16));
+			      pletohs (temp16));
       proto_tree_add_boolean (cap_tree, ff_cf_privacy, tvb, offset, 1,
-			      pntohs (temp16));
-      if (ESS_SET (pntohs (temp16)) != 0)	/* This is an AP */
+			      pletohs (temp16));
+      proto_tree_add_boolean (cap_tree, ff_cf_preamble, tvb, offset, 1,
+			      pletohs (temp16));
+      proto_tree_add_boolean (cap_tree, ff_cf_pbcc, tvb, offset, 1,
+			      pletohs (temp16));
+      proto_tree_add_boolean (cap_tree, ff_cf_agility, tvb, offset, 1,
+			      pletohs (temp16));
+      if (ESS_SET (pletohs (temp16)) != 0)	/* This is an AP */
 	proto_tree_add_uint (cap_tree, ff_cf_ap_poll, tvb, offset, 2,
-			     ((pntohs (temp16) & 0xC) >> 2));
+			     ((pletohs (temp16) & 0xC) >> 2));
 
       else			/* This is a STA */
 	proto_tree_add_uint (cap_tree, ff_cf_sta_poll, tvb, offset, 2,
-			     ((pntohs (temp16) & 0xC) >> 2));
+			     ((pletohs (temp16) & 0xC) >> 2));
       break;
 
 
     case FIELD_AUTH_ALG:
       dataptr = tvb_get_ptr (tvb, offset, 2);
-      out_buff[0] = BIT_SWAP (dataptr[1]);
-      out_buff[1] = BIT_SWAP (dataptr[0]);
-      temp16 = (guint16 *) out_buff;
+      temp16 = (guint16 *) dataptr;
       proto_tree_add_uint (tree, ff_auth_alg, tvb, offset, 2,
-			   pntohs (temp16));
+			   pletohs (temp16));
       break;
 
 
     case FIELD_AUTH_TRANS_SEQ:
       dataptr = tvb_get_ptr (tvb, offset, 2);
-      out_buff[0] = BIT_SWAP (dataptr[1]);
-      out_buff[1] = BIT_SWAP (dataptr[0]);
-      temp16 = (guint16 *) out_buff;
+      temp16 = (guint16 *) dataptr;
       proto_tree_add_uint (tree, ff_auth_seq, tvb, offset, 2,
-			   pntohs (temp16));
+			   pletohs (temp16));
       break;
 
 
     case FIELD_CURRENT_AP_ADDR:
       dataptr = tvb_get_ptr (tvb, offset, 6);
-      memset (out_buff, 0, SHORT_STR);
-      out_buff[0] = BIT_SWAP (dataptr[5]);
-      out_buff[1] = BIT_SWAP (dataptr[4]);
-      out_buff[2] = BIT_SWAP (dataptr[3]);
-      out_buff[3] = BIT_SWAP (dataptr[2]);
-      out_buff[4] = BIT_SWAP (dataptr[1]);
-      out_buff[5] = BIT_SWAP (dataptr[0]);
 
-      proto_tree_add_string (tree, ff_current_ap, tvb, offset, 6, out_buff);
+      proto_tree_add_string (tree, ff_current_ap, tvb, offset, 6, dataptr);
       break;
 
 
     case FIELD_LISTEN_IVAL:
       dataptr = tvb_get_ptr (tvb, offset, 2);
-      out_buff[0] = BIT_SWAP (dataptr[1]);
-      out_buff[1] = BIT_SWAP (dataptr[0]);
-      temp16 = (guint16 *) out_buff;
+      temp16 = (guint16 *) dataptr;
       proto_tree_add_uint (tree, ff_listen_ival, tvb, offset, 2,
-			   pntohs (temp16));
+			   pletohs (temp16));
       break;
 
 
     case FIELD_REASON_CODE:
       dataptr = tvb_get_ptr (tvb, offset, 2);
-      out_buff[0] = BIT_SWAP (dataptr[1]);
-      out_buff[1] = BIT_SWAP (dataptr[0]);
-      temp16 = (guint16 *) out_buff;
-      proto_tree_add_uint (tree, ff_reason, tvb, offset, 2, pntohs (temp16));
+      temp16 = (guint16 *) dataptr;
+      proto_tree_add_uint (tree, ff_reason, tvb, offset, 2, pletohs (temp16));
       break;
 
 
     case FIELD_ASSOC_ID:
       dataptr = tvb_get_ptr (tvb, offset, 2);
-      out_buff[0] = BIT_SWAP (dataptr[1]);
-      out_buff[1] = BIT_SWAP (dataptr[0]);
-      temp16 = (guint16 *) out_buff;
-      proto_tree_add_uint (tree, ff_assoc_id, tvb, offset, 2, pntohs (temp16));
+      temp16 = (guint16 *) dataptr;
+      proto_tree_add_uint (tree, ff_assoc_id, tvb, offset, 2, pletohs (temp16));
       break;
 
     case FIELD_STATUS_CODE:
       dataptr = tvb_get_ptr (tvb, offset, 2);
-      out_buff[0] = BIT_SWAP (dataptr[1]);
-      out_buff[1] = BIT_SWAP (dataptr[0]);
-      temp16 = (guint16 *) out_buff;
+      temp16 = (guint16 *) dataptr;
       proto_tree_add_uint (tree, ff_status_code, tvb, offset, 2,
-			   pntohs (temp16));
+			   pletohs (temp16));
       break;
     }
 }
@@ -541,7 +558,7 @@
       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
 			     tag_len, "Not interpreted");
-      return (int) tag_len;
+      return (int) tag_len + 2;
     }
 
   /* Next See if tag is reserved - if true, skip it! */
@@ -556,7 +573,7 @@
 
       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
 			     tag_len, "Not interpreted");
-      return (int) tag_len;
+      return (int) tag_len + 2;
     }
 
 
@@ -616,7 +633,7 @@
 
       snprintf (out_buff, SHORT_STR,
 		"Dwell time 0x%04X, Hop Set %2d, Hop Pattern %2d, "
-		"Hop Index %2d", pntohs (tag_data_ptr), tag_data_ptr[2],
+		"Hop Index %2d", pletohs (tag_data_ptr), tag_data_ptr[2],
 		tag_data_ptr[3], tag_data_ptr[4]);
 
       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
@@ -650,7 +667,7 @@
       snprintf (out_buff, SHORT_STR,
 		"CFP count %u, CFP period %u, CFP max duration %u, "
 		"CFP Remaining %u", tag_data_ptr[0], tag_data_ptr[1],
-		pntohs (tag_data_ptr + 2), pntohs (tag_data_ptr + 4));
+		pletohs (tag_data_ptr + 2), pletohs (tag_data_ptr + 4));
 
       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
 			     tag_len, out_buff);
@@ -682,7 +699,7 @@
       proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
       memset (out_buff, 0, SHORT_STR);
       snprintf (out_buff, SHORT_STR, "ATIM window 0x%X",
-		pntohs (tag_data_ptr));
+		pletohs (tag_data_ptr));
 
       proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
 			     tag_len, out_buff);
@@ -791,11 +808,11 @@
 
       if ((COMPOSE_FRAME_TYPE(fcf))==CTRL_PS_POLL) 
 	proto_tree_add_uint(hdr_tree, hf_assoc_id,tvb,2,2,
-			    COOK_ASSOC_ID(tvb_get_ntohs(tvb,2)));
+			    COOK_ASSOC_ID(tvb_get_letohs(tvb,2)));
      
       else
 	  proto_tree_add_uint (hdr_tree, hf_did_duration, tvb, 2, 2,
-			       tvb_get_ntohs (tvb, 2));
+			       tvb_get_letohs (tvb, 2));
     }
 
   /* Perform tasks which are common to a certain frame type */
@@ -827,11 +844,11 @@
 				tvb_get_ptr (tvb, 16, 6));
 
 	  proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2,
-			       COOK_FRAGMENT_NUMBER (tvb_get_ntohs
+			       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_ntohs
+			       COOK_SEQUENCE_NUMBER (tvb_get_letohs
 						     (tvb, 22)));
 	  cap_len = cap_len - MGT_FRAME_LEN - 4;
 	}
@@ -902,10 +919,10 @@
 	      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_ntohs
+				   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_ntohs
+				   COOK_SEQUENCE_NUMBER (tvb_get_letohs
 							 (tvb, 22)));
 	      break;
 	      
@@ -918,10 +935,10 @@
 	      proto_tree_add_ether (hdr_tree, hf_addr_sa, 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_ntohs
+				   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_ntohs
+				   COOK_SEQUENCE_NUMBER (tvb_get_letohs
 							 (tvb, 22)));
 	      break;
    
@@ -934,10 +951,10 @@
 	      proto_tree_add_ether (hdr_tree, hf_addr_da, 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_ntohs
+				   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_ntohs
+				   COOK_SEQUENCE_NUMBER (tvb_get_letohs
 							 (tvb, 22)));
 	      break;
 	      
@@ -950,10 +967,10 @@
 	      proto_tree_add_ether (hdr_tree, hf_addr_da, 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_ntohs
+				   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_ntohs
+				   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));
@@ -1145,25 +1162,39 @@
       COL_SHOW_INFO (pinfo->fd, "Authentication");
       if (tree)
 	{
-	  fixed_tree = get_fixed_parameter_tree (tree, tvb, MGT_FRAME_LEN, 6);
-	  add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN, FIELD_AUTH_ALG);
-	  add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 2,
-			   FIELD_AUTH_TRANS_SEQ);
-	  add_fixed_field (fixed_tree, tvb, MGT_FRAME_LEN + 4,
-			   FIELD_STATUS_CODE);
-
-	  next_idx = MGT_FRAME_LEN + 6;	/* Size of fixed fields */
-
-	  if ((pinfo->captured_len - next_idx - 4) != 0)
+	  if (IS_WEP(COOK_FLAGS(fcf)))
 	    {
-	      tagged_tree = get_tagged_parameter_tree (tree,
-						       tvb,
-						       next_idx,
-						       pinfo->captured_len -
-						       next_idx - 4);
+	      int pkt_len = tvb_reported_length (tvb);
+	      int cap_len = tvb_length (tvb);
 
-	      while ((pinfo->captured_len) > (next_idx - 4))
-		next_idx += add_tagged_field (tagged_tree, tvb, next_idx);
+	      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
+	    {
+	      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 */
+
+	      if ((pinfo->captured_len - next_idx - 4) != 0)
+		{
+		  tagged_tree = get_tagged_parameter_tree (tree,
+							   tvb,
+							   next_idx,
+							   pinfo->captured_len -
+							   next_idx - 4);
+
+		  while ((pinfo->captured_len) > (next_idx - 4))
+		    next_idx += add_tagged_field (tagged_tree, tvb, next_idx);
+		}
 	    }
 	}
       break;
@@ -1332,9 +1363,21 @@
       if (tree)
 	{
 	  hdr_len = find_header_length (tvb_get_ptr (tvb, 0, cap_len), 0);
-
 	  next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
-	  call_dissector (llc_handle, next_tvb, pinfo, tree);
+
+	  if (IS_WEP(COOK_FLAGS(fcf)))
+	    {
+	      int pkt_len = tvb_reported_length (next_tvb);
+	      int cap_len = tvb_length (next_tvb);
+
+	      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;
 
@@ -1345,9 +1388,21 @@
       if (tree)
 	{
 	  hdr_len = find_header_length (tvb_get_ptr (tvb, 0, cap_len), 0);
-
 	  next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
-	  call_dissector (llc_handle, next_tvb, pinfo, tree);
+
+	  if (IS_WEP(COOK_FLAGS(fcf)))
+	    {
+	      int pkt_len = tvb_reported_length (next_tvb);
+	      int cap_len = tvb_length (next_tvb);
+
+	      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;
 
@@ -1359,7 +1414,20 @@
 	{
 	  hdr_len = find_header_length (tvb_get_ptr (tvb, 0, cap_len), 0);
 	  next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
-	  call_dissector (llc_handle, next_tvb, pinfo, tree);
+
+	  if (IS_WEP(COOK_FLAGS(fcf)))
+	    {
+	      int pkt_len = tvb_reported_length (next_tvb);
+	      int cap_len = tvb_length (next_tvb);
+
+	      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;
 
@@ -1371,7 +1439,20 @@
 	{
 	  hdr_len = find_header_length (tvb_get_ptr (tvb, 0, cap_len), 0);
 	  next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
-	  call_dissector (llc_handle, next_tvb, pinfo, tree);
+
+	  if (IS_WEP(COOK_FLAGS(fcf)))
+	    {
+	      int pkt_len = tvb_reported_length (next_tvb);
+	      int cap_len = tvb_length (next_tvb);
+
+	      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;
 
@@ -1467,6 +1548,21 @@
     "AP/STA cannot support WEP"
   };
 
+  static const true_false_string cf_preamble_flags = {
+    "Short preamble allowed",
+    "Short preamble not allowed"
+  };
+
+  static const true_false_string cf_pbcc_flags = {
+    "PBCC modulation allowed",
+    "PBCC modulation not allowed"
+  };
+
+  static const true_false_string cf_agility_flags = {
+    "Channel agility in use",
+    "Channel agility not in use"
+  };
+
 
   static const true_false_string cf_ibss_flags = {
     "Transmitter belongs to an IBSS",
@@ -1659,6 +1755,22 @@
      {"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"}},
+
     {&ff_capture,
      {"Capabilities", "wlan.fixed.capabilities", FT_UINT16, BASE_HEX, NULL, 0,
       "Capability information"}},
@@ -1675,16 +1787,28 @@
 
     {&ff_cf_ess,
      {"ESS capabilities", "wlan.fixed.capabilities.ess",
-      FT_BOOLEAN, 1, TFS (&cf_ess_flags), 0x0001, "ESS capabilities"}},
+      FT_BOOLEAN, 8, TFS (&cf_ess_flags), 0x0001, "ESS capabilities"}},
 
 
     {&ff_cf_ibss,
      {"IBSS status", "wlan.fixed.capabilities.ibss",
-      FT_BOOLEAN, 1, TFS (&cf_ibss_flags), 0x0002, "IBSS participation"}},
+      FT_BOOLEAN, 8, TFS (&cf_ibss_flags), 0x0002, "IBSS participation"}},
 
     {&ff_cf_privacy,
      {"Privacy", "wlan.fixed.capabilities.privacy",
-      FT_BOOLEAN, 1, TFS (&cf_privacy_flags), 0x0010, "WEP support"}},
+      FT_BOOLEAN, 8, TFS (&cf_privacy_flags), 0x0010, "WEP support"}},
+
+    {&ff_cf_preamble,
+     {"Short Preamble", "wlan.fixed.capabilities.preamble",
+      FT_BOOLEAN, 8, TFS (&cf_preamble_flags), 0x0020, "Short Preamble"}},
+
+    {&ff_cf_pbcc,
+     {"PBCC", "wlan.fixed.capabilities.pbcc",
+      FT_BOOLEAN, 8, TFS (&cf_pbcc_flags), 0x0040, "PBCC Modulation"}},
+
+    {&ff_cf_agility,
+     {"Channel Agility", "wlan.fixed.capabilities.agility",
+      FT_BOOLEAN, 8, TFS (&cf_agility_flags), 0x0080, "Channel Agility"}},
 
 
     {&ff_auth_seq,
@@ -1735,6 +1859,7 @@
     &ett_proto_flags,
     &ett_fixed_parameters,
     &ett_tagged_parameters,
+    &ett_wep_parameters,
     &ett_cap_tree,
   };