/* 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.40 2001/09/25 02:21:15 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 <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
#include <string.h>
#include <glib.h>
-#include "bitswap.h"
-#include "proto.h"
-#include "packet.h"
-#include "resolv.h"
+#include <epan/bitswap.h>
+#include <epan/proto.h>
+#include <epan/packet.h>
+#include <epan/resolv.h>
+#include "prefs.h"
+#include "reassemble.h"
#include "packet-ipx.h"
#include "packet-llc.h"
#include "packet-ieee80211.h"
#include "etypes.h"
+#include "crc32.h"
+
+/* Defragment fragmented 802.11 datagrams */
+static gboolean wlan_defragment = TRUE;
+
+/* Check for the presence of the 802.11 FCS */
+static gboolean wlan_check_fcs = FALSE;
+
+/* Ignore the WEP bit; assume packet is decrypted */
+static gboolean wlan_ignore_wep = FALSE;
+
+/* Tables for reassembly of fragments. */
+static GHashTable *wlan_fragment_table = NULL;
+static GHashTable *wlan_reassembled_table = NULL;
+
+/* Stuff for the WEP decoder */
+static guint num_wepkeys = 0;
+static guint8 **wep_keys = NULL;
+static int *wep_keylens = NULL;
+static void init_wepkeys(void);
+static int wep_decrypt(guint8 *buf, guint32 len, int key_override);
+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:
+
+ ETHEREAL_WEPKEYNUM=##
+ ETHEREAL_WEPKEY1=aa:bb:cc:dd:...
+ ETHEREAL_WEPKEY2=aa:bab:cc:dd:ee:...
+
+ ... you get the idea.
+
+ otherwise you're limited to specifying four keys in the preference system.
+ */
+
+#ifndef USE_ENV
+static char *wep_keystr[] = {NULL, NULL, NULL, NULL};
+#endif
/* ************************************************************************* */
/* Miscellaneous Constants */
#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);
-#define COL_SHOW_INFO_CONST(fd,info) if (check_col(fd,COL_INFO)) \
- col_set_str(fd,COL_INFO,info);
#define FLAG_TO_DS 0x01
#define FLAG_FROM_DS 0x02
#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_WEP(x) (!wlan_ignore_wep && ((x) & FLAG_WEP))
#define IS_STRICTLY_ORDERED(x) ((x) & FLAG_ORDER)
#define MGT_RESERVED_RANGE(x) (((x>=0x06)&&(x<=0x07))||((x>=0x0D)&&(x<=0x0F)))
/* ************************************************************************* */
/* 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 */
};
static int proto_wlan = -1;
+
+/* ************************************************************************* */
+/* Header field info values for radio information */
+/* ************************************************************************* */
+static int hf_data_rate = -1;
+static int hf_channel = -1;
+static int hf_signal_strength = -1;
+
/* ************************************************************************* */
/* Header field info values for FC-field */
/* ************************************************************************* */
/* ************************************************************************* */
static int hf_fcs = -1;
+/* ************************************************************************* */
+/* Header values for reassembly */
+/* ************************************************************************* */
+static int hf_fragments = -1;
+static int hf_fragment = -1;
+static int hf_fragment_overlap = -1;
+static int hf_fragment_overlap_conflict = -1;
+static int hf_fragment_multiple_tails = -1;
+static int hf_fragment_too_long_fragment = -1;
+static int hf_fragment_error = -1;
+static int hf_reassembled_in = -1;
static int proto_wlan_mgt = -1;
/* 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 */
static int hf_tagged_parameters = -1; /* Fixed payload item */
static int hf_wep_iv = -1;
static int hf_wep_key = -1;
-static int hf_wep_crc = -1;
+static int hf_wep_icv = -1;
/* ************************************************************************* */
/* Protocol trees */
static gint ett_proto_flags = -1;
static gint ett_cap_tree = -1;
static gint ett_fc_tree = -1;
+static gint ett_fragments = -1;
+static gint ett_fragment = -1;
static gint ett_80211_mgt = -1;
static gint ett_fixed_parameters = -1;
static gint ett_tagged_parameters = -1;
static gint ett_wep_parameters = -1;
+static const fragment_items frag_items = {
+ &ett_fragment,
+ &ett_fragments,
+ &hf_fragments,
+ &hf_fragment,
+ &hf_fragment_overlap,
+ &hf_fragment_overlap_conflict,
+ &hf_fragment_multiple_tails,
+ &hf_fragment_too_long_fragment,
+ &hf_fragment_error,
+ &hf_reassembled_in,
+ "fragments"
+};
+
static dissector_handle_t llc_handle;
static dissector_handle_t ipx_handle;
+static dissector_handle_t data_handle;
/* ************************************************************************* */
/* Return the length of the current header (in bytes) */
/* ************************************************************************* */
/* This is the capture function used to update packet counts */
/* ************************************************************************* */
-void
-capture_ieee80211 (const u_char * pd, int offset, packet_counts * ld)
+static void
+capture_ieee80211_common (const guchar * pd, int offset, int len,
+ packet_counts * ld, gboolean fixed_length_header)
{
guint16 fcf, hdr_length;
+ if (!BYTES_ARE_IN_FRAME(offset, len, 2)) {
+ ld->other++;
+ return;
+ }
+
fcf = pletohs (&pd[0]);
if (IS_WEP(COOK_FLAGS(fcf)))
case DATA_CF_ACK: /* Data with ACK */
case DATA_CF_POLL:
case DATA_CF_ACK_POLL:
- hdr_length = find_header_length (fcf);
+ if (fixed_length_header)
+ hdr_length = DATA_LONG_HDR_LEN;
+ else
+ hdr_length = find_header_length (fcf);
/* I guess some bridges take Netware Ethernet_802_3 frames,
which are 802.3 frames (with a length field rather than
a type field, but with no 802.2 header in the payload),
Ethernet dissector, i.e. checking for 0xffff as the first
four bytes of the payload and, if we find it, treating it
as an IPX frame. */
+ if (!BYTES_ARE_IN_FRAME(offset+hdr_length, len, 2)) {
+ ld->other++;
+ return;
+ }
if (pd[offset+hdr_length] == 0xff && pd[offset+hdr_length+1] == 0xff) {
- capture_ipx (pd, offset + hdr_length, ld);
+ capture_ipx (ld);
}
else {
- capture_llc (pd, offset + hdr_length, ld);
+ capture_llc (pd, offset + hdr_length, len, ld);
}
break;
}
}
+/*
+ * Handle 802.11 with a variable-length link-layer header.
+ */
+void
+capture_ieee80211 (const guchar * pd, int offset, int len, packet_counts * ld)
+{
+ capture_ieee80211_common (pd, offset, len, ld, FALSE);
+}
+
+/*
+ * Handle 802.11 with a fixed-length link-layer header (padded to the
+ * maximum length).
+ */
+void
+capture_ieee80211_fixed (const guchar * pd, int offset, int len, packet_counts * ld)
+{
+ capture_ieee80211_common (pd, offset, len, ld, TRUE);
+}
/* ************************************************************************* */
}
-/* ************************************************************************* */
-/* Add the subtree used to store WEP parameters */
-/* ************************************************************************* */
-static void
-get_wep_parameter_tree (proto_tree * tree, tvbuff_t *tvb, int start, int size)
-{
- proto_item *wep_fields;
- proto_tree *wep_tree;
- int crc_offset = size - 4;
-
- wep_fields = proto_tree_add_text(tree, tvb, start, 4, "WEP parameters");
-
- wep_tree = proto_item_add_subtree (wep_fields, ett_wep_parameters);
- proto_tree_add_item (wep_tree, hf_wep_iv, tvb, start, 3, TRUE);
-
- proto_tree_add_uint (wep_tree, hf_wep_key, tvb, start + 3, 1,
- COOK_WEP_KEY (tvb_get_guint8 (tvb, start + 3)));
-
- if (tvb_bytes_exist(tvb, start + crc_offset, 4))
- proto_tree_add_uint (wep_tree, hf_wep_crc, tvb, start + crc_offset, 4,
- tvb_get_ntohl (tvb, start + crc_offset));
-}
-
/* ************************************************************************* */
/* Dissect and add fixed mgmt fields to protocol tree */
/* ************************************************************************* */
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,
+ proto_tree_add_boolean (cap_tree, ff_cf_ess, tvb, offset, 2,
capability);
- proto_tree_add_boolean (cap_tree, ff_cf_preamble, tvb, offset, 1,
- capability);
- proto_tree_add_boolean (cap_tree, ff_cf_pbcc, tvb, offset, 1,
- capability);
- proto_tree_add_boolean (cap_tree, ff_cf_agility, tvb, offset, 1,
+ 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:
- proto_tree_add_uint (tree, ff_auth_alg, tvb, offset, 2, TRUE);
+ proto_tree_add_item (tree, ff_auth_alg, tvb, offset, 2, TRUE);
break;
case FIELD_AUTH_TRANS_SEQ:
- proto_tree_add_uint (tree, ff_auth_seq, tvb, offset, 2, TRUE);
+ proto_tree_add_item (tree, ff_auth_seq, tvb, offset, 2, TRUE);
break;
case FIELD_CURRENT_AP_ADDR:
}
}
+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)
{
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);
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);
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;
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;
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,
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]);
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,
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, "
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));
break;
+ case TAG_COUNTRY_INFO:
+ memset (out_buff, 0, SHORT_STR);
- case TAG_CHALLENGE_TEXT:
- proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no,
- "Tag Number: %u (Challenge text)", tag_no);
+ 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)"));
+
+ n = strlen (out_buff);
- proto_tree_add_uint (tree, tag_length, tvb, offset + 1, 1, tag_len);
+ 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;
+
+
+ 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, tag_len,
- out_buff);
+ proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2,
+ tag_len, out_buff);
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 */
/* ************************************************************************* */
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_DATA(proto_wlan_mgt, tvb, pinfo, tree);
+ CHECK_DISPLAY_AS_X(data_handle,proto_wlan_mgt, tvb, pinfo, tree);
if (tree)
{
- ti = proto_tree_add_item (tree, proto_wlan_mgt, tvb, 0, tvb_length(tvb), FALSE);
+ ti = proto_tree_add_item (tree, proto_wlan_mgt, tvb, 0, -1, FALSE);
mgt_tree = proto_item_add_subtree (ti, ett_80211_mgt);
switch (COMPOSE_FRAME_TYPE(fcf))
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 + 4);
- 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;
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 + 4);
- 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;
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 + 4);
- 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:
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 + 4);
- 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 + 4);
- 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;
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 + 4);
- 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;
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 + 4);
- 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;
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 + 4);
+ 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;
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)",
+ if (check_col(pinfo->cinfo, COL_RES_DL_SRC))
+ col_add_fstr(pinfo->cinfo, COL_RES_DL_SRC, "%s (%s)",
get_ether_name(addr), type);
- if (check_col(pinfo->fd, COL_UNRES_DL_SRC))
- col_add_fstr(pinfo->fd, COL_UNRES_DL_SRC, "%s (%s)",
+ if (check_col(pinfo->cinfo, COL_UNRES_DL_SRC))
+ col_add_fstr(pinfo->cinfo, COL_UNRES_DL_SRC, "%s (%s)",
ether_to_str(addr), type);
}
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)",
+ if (check_col(pinfo->cinfo, COL_RES_DL_DST))
+ col_add_fstr(pinfo->cinfo, COL_RES_DL_DST, "%s (%s)",
get_ether_name(addr), type);
- if (check_col(pinfo->fd, COL_UNRES_DL_DST))
- col_add_fstr(pinfo->fd, COL_UNRES_DL_DST, "%s (%s)",
+ if (check_col(pinfo->cinfo, COL_UNRES_DL_DST))
+ col_add_fstr(pinfo->cinfo, COL_UNRES_DL_DST, "%s (%s)",
ether_to_str(addr), type);
}
/* Dissect 802.11 frame */
/* ************************************************************************* */
static void
-dissect_ieee80211 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
+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 wlan_broken_fc)
{
guint16 fcf, flags, frame_type_subtype;
+ guint16 seq_control;
+ guint32 seq_number, frag_number;
+ gboolean more_frags;
const guint8 *src = NULL, *dst = NULL;
proto_item *ti = NULL;
proto_item *flag_item;
proto_tree *flag_tree;
proto_tree *fc_tree;
guint16 hdr_len;
- tvbuff_t *next_tvb;
+ gint len, reported_len;
+ gboolean save_fragmented;
+ tvbuff_t *volatile next_tvb = NULL;
guint32 addr_type;
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);
+ if (check_col (pinfo->cinfo, COL_PROTOCOL))
+ col_set_str (pinfo->cinfo, COL_PROTOCOL, "IEEE 802.11");
+ if (check_col (pinfo->cinfo, COL_INFO))
+ col_clear (pinfo->cinfo, COL_INFO);
fcf = tvb_get_letohs (tvb, 0);
- hdr_len = find_header_length (fcf);
+ 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
+ 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)"));
+ if (check_col (pinfo->cinfo, COL_INFO))
+ col_set_str (pinfo->cinfo, COL_INFO,
+ val_to_str(frame_type_subtype, frame_type_subtype_vals,
+ "Unrecognized (Reserved frame)"));
- /* Add the FC to the current tree */
+ flags = COOK_FLAGS (fcf);
+ more_frags = HAVE_FRAGMENTS (flags);
+
+ /* Add the radio information, if present, and the FC to the current tree */
if (tree)
{
ti = proto_tree_add_protocol_format (tree, proto_wlan, tvb, 0, hdr_len,
"IEEE 802.11");
hdr_tree = proto_item_add_subtree (ti, ett_80211);
+ if (has_radio_information) {
+ proto_tree_add_uint_format(hdr_tree, hf_data_rate,
+ tvb, 0, 0,
+ pinfo->pseudo_header->ieee_802_11.data_rate,
+ "Data Rate: %g mb/s",
+ .5*pinfo->pseudo_header->ieee_802_11.data_rate);
+
+ proto_tree_add_uint(hdr_tree, hf_channel,
+ tvb, 0, 0,
+ pinfo->pseudo_header->ieee_802_11.channel);
+
+ proto_tree_add_uint_format(hdr_tree, hf_signal_strength,
+ tvb, 0, 0,
+ pinfo->pseudo_header->ieee_802_11.signal_level,
+ "Signal Strength: %u%%",
+ pinfo->pseudo_header->ieee_802_11.signal_level);
+ }
+
proto_tree_add_uint (hdr_tree, hf_fc_frame_type_subtype,
- tvb, 0, 1,
+ 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));
- flags = COOK_FLAGS (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));
* Decode the part of the frame header that isn't the same for all
* frame types.
*/
- switch (frame_type_subtype)
+ seq_control = 0;
+ frag_number = 0;
+ seq_number = 0;
+
+ switch (COOK_FRAME_TYPE (fcf))
{
- 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:
+ case MGT_FRAME:
/*
* All management frame types have the same header.
*/
SET_ADDRESS(&pinfo->dl_dst, AT_ETHER, 6, dst);
SET_ADDRESS(&pinfo->dst, AT_ETHER, 6, dst);
+ seq_control = tvb_get_letohs(tvb, 22);
+ frag_number = COOK_FRAGMENT_NUMBER(seq_control);
+ seq_number = COOK_SEQUENCE_NUMBER(seq_control);
+
if (tree)
{
proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 4, 6, dst);
tvb_get_ptr (tvb, 16, 6));
proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2,
- COOK_FRAGMENT_NUMBER (tvb_get_letohs
- (tvb, 22)));
+ frag_number);
proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
- COOK_SEQUENCE_NUMBER (tvb_get_letohs
- (tvb, 22)));
+ seq_number);
}
break;
+ case CONTROL_FRAME:
+ switch (frame_type_subtype)
+ {
- case CTRL_PS_POLL:
- src = tvb_get_ptr (tvb, 10, 6);
- dst = tvb_get_ptr (tvb, 4, 6);
+ 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");
+ 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);
+ if (tree)
+ {
+ proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 4, 6, dst);
- proto_tree_add_ether (hdr_tree, hf_addr_ta, tvb, 10, 6, src);
- }
- break;
+ 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 CTRL_RTS:
+ src = tvb_get_ptr (tvb, 10, 6);
+ dst = tvb_get_ptr (tvb, 4, 6);
- set_src_addr_cols(pinfo, src, "TA");
- set_dst_addr_cols(pinfo, dst, "RA");
+ set_src_addr_cols(pinfo, src, "TA");
+ set_dst_addr_cols(pinfo, dst, "RA");
- if (tree)
- {
- proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6, dst);
+ if (tree)
+ {
+ proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6, dst);
- proto_tree_add_ether (hdr_tree, hf_addr_ta, tvb, 10, 6, src);
- }
- break;
+ proto_tree_add_ether (hdr_tree, hf_addr_ta, tvb, 10, 6, src);
+ }
+ break;
- case CTRL_CTS:
- dst = tvb_get_ptr (tvb, 4, 6);
+ case CTRL_CTS:
+ dst = tvb_get_ptr (tvb, 4, 6);
- set_dst_addr_cols(pinfo, dst, "RA");
+ set_dst_addr_cols(pinfo, dst, "RA");
- if (tree)
- proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6, dst);
- break;
+ if (tree)
+ proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6, dst);
+ break;
- case CTRL_ACKNOWLEDGEMENT:
- dst = tvb_get_ptr (tvb, 4, 6);
+ case CTRL_ACKNOWLEDGEMENT:
+ dst = tvb_get_ptr (tvb, 4, 6);
- set_dst_addr_cols(pinfo, dst, "RA");
+ set_dst_addr_cols(pinfo, dst, "RA");
- if (tree)
- proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6, dst);
- break;
+ 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);
+ 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");
+ 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;
+ if (tree)
+ {
+ proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6, dst);
+ proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 10, 6, src);
+ }
+ break;
- case CTRL_CFP_ENDACK:
- src = tvb_get_ptr (tvb, 10, 6);
- dst = tvb_get_ptr (tvb, 4, 6);
+ case CTRL_CFP_ENDACK:
+ src = tvb_get_ptr (tvb, 10, 6);
+ dst = tvb_get_ptr (tvb, 4, 6);
- set_src_addr_cols(pinfo, src, "BSSID");
- set_dst_addr_cols(pinfo, dst, "RA");
+ 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);
+ 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);
+ proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 10, 6, src);
+ }
+ break;
}
break;
-
- case DATA:
- case DATA_CF_ACK:
- case DATA_CF_POLL:
- case DATA_CF_ACK_POLL:
+ case DATA_FRAME:
addr_type = COOK_ADDR_SELECTOR (fcf);
/* In order to show src/dst address we must always do the following */
SET_ADDRESS(&pinfo->dl_dst, AT_ETHER, 6, dst);
SET_ADDRESS(&pinfo->dst, AT_ETHER, 6, dst);
+ seq_control = tvb_get_letohs(tvb, 22);
+ frag_number = COOK_FRAGMENT_NUMBER(seq_control);
+ seq_number = COOK_SEQUENCE_NUMBER(seq_control);
+
/* Now if we have a tree we start adding stuff */
if (tree)
{
proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 16, 6,
tvb_get_ptr (tvb, 16, 6));
proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2,
- COOK_FRAGMENT_NUMBER (tvb_get_letohs
- (tvb, 22)));
+ frag_number);
proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
- COOK_SEQUENCE_NUMBER (tvb_get_letohs
- (tvb, 22)));
+ seq_number);
/* add items for wlan.addr filter */
proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 4, 6, dst);
proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 10, 6, src);
break;
-
-
+
+
case DATA_ADDR_T2:
proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 4, 6, dst);
proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 10, 6,
tvb_get_ptr (tvb, 10, 6));
proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 16, 6, src);
proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2,
- COOK_FRAGMENT_NUMBER (tvb_get_letohs
- (tvb, 22)));
+ frag_number);
proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
- COOK_SEQUENCE_NUMBER (tvb_get_letohs
- (tvb, 22)));
+ seq_number);
/* add items for wlan.addr filter */
proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 4, 6, dst);
proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 16, 6, src);
break;
-
+
case DATA_ADDR_T3:
proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 4, 6,
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)));
+ frag_number);
proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
- COOK_SEQUENCE_NUMBER (tvb_get_letohs
- (tvb, 22)));
+ seq_number);
/* add items for wlan.addr filter */
proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 10, 6, src);
proto_tree_add_ether_hidden(hdr_tree, hf_addr, tvb, 16, 6, dst);
break;
-
+
case DATA_ADDR_T4:
proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6,
tvb_get_ptr (tvb, 10, 6));
proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 16, 6, dst);
proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2,
- COOK_FRAGMENT_NUMBER (tvb_get_letohs
- (tvb, 22)));
+ frag_number);
proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2,
- COOK_SEQUENCE_NUMBER (tvb_get_letohs
- (tvb, 22)));
+ seq_number);
proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 24, 6, src);
/* add items for wlan.addr filter */
break;
}
+ len = tvb_length_remaining(tvb, hdr_len);
+ reported_len = tvb_reported_length_remaining(tvb, hdr_len);
+
+ if (!has_no_fcs && (wlan_check_fcs))
+ {
+ /*
+ * Well, this packet should, in theory, have an FCS.
+ * Do we have the entire packet, and does it have enough data for
+ * the FCS?
+ */
+ if (reported_len < 4)
+ {
+ /*
+ * The packet is claimed not to even have enough data for a 4-byte
+ * FCS.
+ * Pretend it doesn't have an FCS.
+ */
+ ;
+ }
+ else if (len < reported_len)
+ {
+ /*
+ * The packet is claimed to have enough data for a 4-byte FCS, but
+ * we didn't capture all of the packet.
+ * Slice off the 4-byte FCS from the reported length, and trim the
+ * captured length so it's no more than the reported length; that
+ * will slice off what of the FCS, if any, is in the captured
+ * length.
+ */
+ reported_len -= 4;
+ if (len > reported_len)
+ len = reported_len;
+ }
+ else
+ {
+ /*
+ * We have the entire packet, and it includes a 4-byte FCS.
+ * Slice it off, and put it into the tree.
+ */
+ len -= 4;
+ reported_len -= 4;
+ if (tree)
+ {
+ 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);
+ }
+ }
+ }
+
/*
* Only management and data frames have a body, so we don't have
* anything more to do for other types of frames.
{
case MGT_FRAME:
- case DATA_FRAME:
break;
+ case DATA_FRAME:
+ /*
+ * No-data frames don't have a body.
+ */
+ switch (frame_type_subtype)
+ {
+
+ case DATA_NULL_FUNCTION:
+ case DATA_CF_ACK_NOD:
+ case DATA_CF_POLL_NOD:
+ case DATA_CF_ACK_POLL_NOD:
+ return;
+ }
+ break;
+
default:
return;
}
- /*
- * For WEP-encrypted frames, dissect the WEP parameters and
- * display the payload as data.
- *
- * XXX - allow the key to be specified, and, if it is, decrypt
- * the payload and dissect it?
- */
- if (IS_WEP(COOK_FLAGS(fcf)))
- {
- int pkt_len = tvb_reported_length (tvb);
- int cap_len = tvb_length (tvb);
+ if (IS_WEP(COOK_FLAGS(fcf))) {
+ /*
+ * It's a WEP-encrypted frame; dissect the WEP parameters and decrypt
+ * the data, if we have a matching key. Otherwise display it as data.
+ */
+ 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;
+
+ wep_fields = proto_tree_add_text(hdr_tree, tvb, hdr_len, 4,
+ "WEP parameters");
+
+ wep_tree = proto_item_add_subtree (wep_fields, ett_wep_parameters);
+ 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;
+
+ /*
+ * Well, this packet should, in theory, have an ICV.
+ * Do we have the entire packet, and does it have enough data for
+ * the ICV?
+ */
+ if (reported_len < 4) {
+ /*
+ * The packet is claimed not to even have enough data for a
+ * 4-byte ICV.
+ * Pretend it doesn't have an ICV.
+ */
+ ;
+ } else if (len < reported_len) {
+ /*
+ * The packet is claimed to have enough data for a 4-byte ICV,
+ * but we didn't capture all of the packet.
+ * Slice off the 4-byte ICV from the reported length, and trim
+ * the captured length so it's no more than the reported length;
+ * that will slice off what of the ICV, if any, is in the
+ * captured length.
+ *
+ */
+ reported_len -= 4;
+ if (len > reported_len)
+ len = reported_len;
+ } else {
+ /*
+ * We have the entire packet, and it includes a 4-byte ICV.
+ * Slice it off, and put it into the tree.
+ *
+ * We only support decrypting if we have the the ICV.
+ *
+ * XXX - the ICV is encrypted; we're putting the encrypted
+ * value, not the decrypted value, into the tree.
+ */
+ len -= 4;
+ reported_len -= 4;
+ can_decrypt = TRUE;
+ }
+
+ if (!can_decrypt || (next_tvb = try_decrypt_wep(tvb, hdr_len, reported_len + 8)) == NULL) {
+ /*
+ * WEP decode impossible or failed, treat payload as raw data
+ * and don't attempt fragment reassembly or further dissection.
+ */
+ 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;
+ } else {
if (tree)
- {
- get_wep_parameter_tree (tree, tvb, hdr_len, pkt_len);
- pkt_len -= hdr_len + 4;
- cap_len -= hdr_len + 4;
+ 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));
- /*
- * 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);
- }
- return;
+ add_new_data_source(pinfo, next_tvb, "Decrypted WEP data");
}
+ /*
+ * WEP decryption successful!
+ *
+ * Use the tvbuff we got back from the decryption; the data starts at
+ * the beginning. The lengths are already correct for the decoded WEP
+ * payload.
+ */
+ hdr_len = 0;
+
+ } else {
+ /*
+ * Not a WEP-encrypted frame; just use the data from the tvbuff
+ * handed to us.
+ *
+ * The payload starts at "hdr_len" (i.e., just past the 802.11
+ * MAC header), the length of data in the tvbuff following the
+ * 802.11 header is "len", and the length of data in the packet
+ * following the 802.11 header is "reported_len".
+ */
+ next_tvb = tvb;
+ }
+
/*
- * Now dissect the body of a non-WEP-encrypted frame.
+ * Do defragmentation if "wlan_defragment" is true, and we have more
+ * fragments or this isn't the first fragment.
+ *
+ * We have to do some special handling to catch frames that
+ * have the "More Fragments" indicator not set but that
+ * don't show up as reassembled and don't have any other
+ * fragments present. Some networking interfaces appear
+ * to do reassembly even when you're capturing raw packets
+ * *and* show the reassembled packet without the "More
+ * Fragments" indicator set *but* with a non-zero fragment
+ * number.
+ *
+ * "fragment_add_seq_check()" handles that; we want to call it
+ * even if we have a short frame, so that it does those checks - if
+ * the frame is short, it doesn't do reassembly on it.
+ *
+ * (This could get some false positives if we really *did* only
+ * capture the last fragment of a fragmented packet, but that's
+ * life.)
*/
- next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1);
+ save_fragmented = pinfo->fragmented;
+ if (wlan_defragment && (more_frags || frag_number != 0)) {
+ fragment_data *fd_head;
+
+ /*
+ * If we've already seen this frame, look it up in the
+ * table of reassembled packets, otherwise add it to
+ * whatever reassembly is in progress, if any, and see
+ * if it's done.
+ */
+ fd_head = fragment_add_seq_check(next_tvb, hdr_len, pinfo, seq_number,
+ wlan_fragment_table,
+ wlan_reassembled_table,
+ frag_number,
+ reported_len,
+ more_frags);
+ 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
+ * just show it as a fragment.
+ */
+ if (frag_number != 0) {
+ /* Not the first fragment - don't dissect it. */
+ next_tvb = NULL;
+ } else {
+ /* First fragment, or not fragmented. Dissect what we have here. */
+
+ /* Get a tvbuff for the payload. */
+ next_tvb = tvb_new_subset (next_tvb, hdr_len, len, reported_len);
+
+ /*
+ * If this is the first fragment, but not the only fragment,
+ * tell the next protocol that.
+ */
+ if (more_frags)
+ pinfo->fragmented = TRUE;
+ else
+ pinfo->fragmented = FALSE;
+ }
+ }
+
+ if (next_tvb == NULL) {
+ /* Just show this as an incomplete fragment. */
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_set_str(pinfo->cinfo, COL_INFO, "Fragmented IEEE 802.11 frame");
+ next_tvb = tvb_new_subset (tvb, hdr_len, len, reported_len);
+ call_dissector(data_handle, next_tvb, pinfo, tree);
+ pinfo->fragmented = save_fragmented;
+ return;
+ }
+
switch (COOK_FRAME_TYPE (fcf))
{
call_dissector(ipx_handle, next_tvb, pinfo, tree);
break;
}
+ pinfo->fragmented = save_fragmented;
+}
+
+/*
+ * Dissect 802.11 with a variable-length link-layer header.
+ */
+static void
+dissect_ieee80211 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
+{
+ dissect_ieee80211_common (tvb, pinfo, tree, FALSE, FALSE, FALSE, FALSE);
+}
+
+/*
+ * Dissect 802.11 with a variable-length link-layer header and a pseudo-
+ * header containing radio information.
+ */
+static void
+dissect_ieee80211_radio (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
+{
+ /* These packets do NOT have a FCS present */
+ 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);
+}
+
+/*
+ * Dissect 802.11 with a fixed-length link-layer header (padded to the
+ * maximum length).
+ */
+static void
+dissect_ieee80211_fixed (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
+{
+ dissect_ieee80211_common (tvb, pinfo, tree, TRUE, FALSE, FALSE, FALSE);
+}
+
+static void
+wlan_defragment_init(void)
+{
+ fragment_table_init(&wlan_fragment_table);
+ reassembled_table_init(&wlan_reassembled_table);
}
void
-proto_register_wlan (void)
+proto_register_ieee80211 (void)
{
static const value_string frame_type[] = {
{MGT_FRAME, "Management frame"},
};
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 = {
- "MSDU/MMPDU is fragmented",
- "No fragments"
+ "More fragments follow",
+ "This is the last fragment"
};
static const true_false_string retry_flags = {
"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",
"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}
};
static hf_register_info hf[] = {
+ {&hf_data_rate,
+ {"Data Rate", "wlan.data_rate", FT_UINT8, BASE_DEC, NULL, 0,
+ "Data rate (.5 Mb/s units)", HFILL }},
+
+ {&hf_channel,
+ {"Channel", "wlan.channel", FT_UINT8, BASE_DEC, NULL, 0,
+ "Radio channel", HFILL }},
+
+ {&hf_signal_strength,
+ {"Signal Strength", "wlan.signal_strength", FT_UINT8, BASE_DEC, NULL, 0,
+ "Signal strength (percentage)", HFILL }},
+
{&hf_fc_field,
{"Frame Control Field", "wlan.fc", FT_UINT16, BASE_HEX, NULL, 0,
"MAC Frame control", HFILL }},
"From DS flag", HFILL }}, /* 5 */
{&hf_fc_more_frag,
- {"Fragments", "wlan.fc.frag", FT_BOOLEAN, 8, TFS (&more_frags), FLAG_MORE_FRAGMENTS,
+ {"More Fragments", "wlan.fc.frag", FT_BOOLEAN, 8, TFS (&more_frags), FLAG_MORE_FRAGMENTS,
"More Fragments flag", HFILL }}, /* 6 */
{&hf_fc_retry,
"Sequence number", HFILL }},
{&hf_fcs,
- {"Frame Check Sequence (not verified)", "wlan.fcs", FT_UINT32, BASE_HEX,
- NULL, 0, "", HFILL }},
+ {"Frame check sequence", "wlan.fcs", FT_UINT32, BASE_HEX,
+ NULL, 0, "FCS", HFILL }},
+
+ {&hf_fragment_overlap,
+ {"Fragment overlap", "wlan.fragment.overlap", FT_BOOLEAN, BASE_NONE,
+ NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
+
+ {&hf_fragment_overlap_conflict,
+ {"Conflicting data in fragment overlap", "wlan.fragment.overlap.conflict",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Overlapping fragments contained conflicting data", HFILL }},
+
+ {&hf_fragment_multiple_tails,
+ {"Multiple tail fragments found", "wlan.fragment.multipletails",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Several tails were found when defragmenting the packet", HFILL }},
+
+ {&hf_fragment_too_long_fragment,
+ {"Fragment too long", "wlan.fragment.toolongfragment",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Fragment contained data past end of packet", HFILL }},
+
+ {&hf_fragment_error,
+ {"Defragmentation error", "wlan.fragment.error",
+ FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ "Defragmentation error due to illegal fragments", HFILL }},
+
+ {&hf_fragment,
+ {"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,
{"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 }},
+ {&hf_wep_icv,
+ {"WEP ICV", "wlan.wep.icv", FT_UINT32, BASE_HEX, NULL, 0,
+ "WEP ICV", HFILL }},
};
static hf_register_info ff[] = {
{"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",
{&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",
&ett_80211,
&ett_fc_tree,
&ett_proto_flags,
+ &ett_fragments,
+ &ett_fragment,
&ett_80211_mgt,
&ett_fixed_parameters,
&ett_tagged_parameters,
&ett_wep_parameters,
&ett_cap_tree,
};
+ module_t *wlan_module;
+
+ static const enum_val_t wep_keys_options[] = {
+ {"0", 0},
+ {"1", 1},
+ {"2", 2},
+ {"3", 3},
+ {"4", 4},
+ {NULL, -1},
+ };
+
proto_wlan = proto_register_protocol ("IEEE 802.11 wireless LAN",
"IEEE 802.11", "wlan");
"802.11 MGT", "wlan_mgt");
proto_register_field_array (proto_wlan_mgt, ff, array_length (ff));
proto_register_subtree_array (tree_array, array_length (tree_array));
+
+ register_dissector("wlan", dissect_ieee80211, proto_wlan);
+ register_dissector("wlan_fixed", dissect_ieee80211_fixed, proto_wlan);
+ register_dissector("wlan_bsfc", dissect_ieee80211_bsfc, proto_wlan);
+ register_init_routine(wlan_defragment_init);
+
+ /* Register configuration options */
+ 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",
+ &wlan_defragment);
+
+ prefs_register_bool_preference(wlan_module, "check_fcs",
+ "Assume packets have FCS",
+ "Some 802.11 cards include the FCS at the end of a packet, others do not.",
+ &wlan_check_fcs);
+
+ prefs_register_bool_preference(wlan_module, "ignore_wep",
+ "Ignore the WEP bit",
+ "Some 802.11 cards leave the WEP bit set even though the packet is decrypted.",
+ &wlan_ignore_wep);
+
+#ifndef USE_ENV
+ 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) [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) [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) [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) [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;
+
/*
* Get handles for the LLC and IPX dissectors.
*/
llc_handle = find_dissector("llc");
ipx_handle = find_dissector("ipx");
+ data_handle = find_dissector("data");
+
+ ieee80211_handle = find_dissector("wlan");
+ dissector_add("wtap_encap", WTAP_ENCAP_IEEE_802_11, ieee80211_handle);
+ ieee80211_radio_handle = create_dissector_handle(dissect_ieee80211_radio,
+ proto_wlan);
+ dissector_add("wtap_encap", WTAP_ENCAP_IEEE_802_11_WITH_RADIO,
+ ieee80211_radio_handle);
+}
+
+static tvbuff_t *try_decrypt_wep(tvbuff_t *tvb, guint32 offset, guint32 len) {
+ guint8 *tmp = NULL;
+ int i;
+ tvbuff_t *decr_tvb = NULL;
+
+ if (num_wepkeys < 1)
+ return NULL;
+
+ 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 */
+#if 0
+ printf("trying %d\n", i);
+#endif
+ tvb_memcpy(tvb, tmp, offset, len);
+ if (wep_decrypt(tmp, len, i) == 0) {
+
+ /* decrypt successful, let's set up a new data tvb. */
+ decr_tvb = tvb_new_real_data(tmp, len-8, len-8);
+ tvb_set_free_cb(decr_tvb, g_free);
+ tvb_set_child_real_data_tvbuff(tvb, decr_tvb);
+
+ goto done;
+ }
+ }
+
+ done:
+ if ((!decr_tvb) && (tmp)) g_free(tmp);
+
+#if 0
+ printf("de-wep %p\n", decr_tvb);
+#endif
+
+ return decr_tvb;
+}
+
+
+/* de-weps the block. if successful, buf* will point to the data start. */
+static int wep_decrypt(guint8 *buf, guint32 len, int key_override) {
+ guint32 i, j, k, crc, keylen;
+ guint8 s[256], key[128], c_crc[4];
+ guint8 keyidx, *dpos, *cpos;
+
+ /* Needs to be at least 8 bytes of payload */
+ if (len < 8)
+ return -1;
+
+ /* initialize the first bytes of the key from the IV */
+ key[0] = buf[0];
+ key[1] = buf[1];
+ key[2] = buf[2];
+ keyidx = COOK_WEP_KEY(buf[3]);
+
+ if (key_override >= 0)
+ keyidx = key_override;
+
+ if (keyidx >= num_wepkeys)
+ return -1;
+
+ keylen = wep_keylens[keyidx];
+
+ if (keylen == 0)
+ return -1;
+ if (wep_keys[keyidx] == NULL)
+ return -1;
+
+ keylen+=3; /* add in ICV bytes */
+
+ /* copy the rest of the key over from the designated key */
+ memcpy(key+3, wep_keys[keyidx], wep_keylens[keyidx]);
+
+#if 0
+ printf("%d: %02x %02x %02x (%d %d) %02x:%02x:%02x:%02x:%02x\n", len, key[0], key[1], key[2], keyidx, keylen, key[3], key[4], key[5], key[6], key[7]);
+#endif
+
+ /* set up the RC4 state */
+ for (i = 0; i < 256; i++)
+ s[i] = i;
+ j = 0;
+ for (i = 0; i < 256; i++) {
+ j = (j + s[i] + key[i % keylen]) & 0xff;
+ SSWAP(i,j);
+ }
+
+ /* Apply the RC4 to the data, update the CRC32 */
+ cpos = buf+4;
+ dpos = buf;
+ crc = ~0;
+ i = j = 0;
+ for (k = 0; k < (len -8); k++) {
+ i = (i+1) & 0xff;
+ j = (j+s[i]) & 0xff;
+ SSWAP(i,j);
+#if 0
+ printf("%d -- %02x ", k, *dpos);
+#endif
+ *dpos = *cpos++ ^ s[(s[i] + s[j]) & 0xff];
+#if 0
+ printf("%02x\n", *dpos);
+#endif
+ crc = crc32_table[(crc ^ *dpos++) & 0xff] ^ (crc >> 8);
+ }
+ crc = ~crc;
+
+ /* now let's check the crc */
+ c_crc[0] = crc;
+ 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;
+ SSWAP(i,j);
+#if 0
+ printf("-- %02x %02x\n", *dpos, c_crc[k]);
+#endif
+ if ((*cpos++ ^ s[(s[i] + s[j]) & 0xff]) != c_crc[k])
+ return -1; /* ICV mismatch */
+ }
+
+ return 0;
+}
+
+static void init_wepkeys(void) {
+ char *tmp, *tmp2;
+ guint8 *tmp3;
+ guint i, j;
+
+#ifdef USE_ENV
+ guint8 buf[128];
+
+ tmp = getenv("ETHEREAL_WEPKEYNUM");
+ if (!tmp) {
+ num_wepkeys = 0;
+ return;
+ }
+ num_wepkeys = atoi(tmp);
+#else
+ if (num_wepkeys > 4)
+ num_wepkeys = 4;
+#endif
+
+ if (num_wepkeys < 1)
+ return;
+
+ if (wep_keys)
+ g_free(wep_keys);
+
+ 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;
+ wep_keylens[i] = 0;
+
+#ifdef USE_ENV
+ sprintf(buf, "ETHEREAL_WEPKEY%d", i+1);
+ tmp = getenv(buf);
+#else
+ tmp = wep_keystr[i];
+#endif
+
+ if (tmp) {
+ j = 0;
+#if 0
+#ifdef USE_ENV
+ printf("%s -- %s\n", buf, tmp);
+#else
+ printf("%d -- %s\n", i+1, tmp);
+#endif
+#endif
+
+ 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)) {
+ tmp3[j] = strtoul(tmp, &tmp2, 16) & 0xff;
+#if 0
+ printf("%d %d -- %02x\n", i, j, tmp3[j]);
+#endif
+ tmp = tmp2;
+ wep_keylens[i]++;
+
+ if ((tmp != NULL) && (*tmp == ':'))
+ tmp++;
+ j++;
+ }
+ }
+
+ }
- dissector_add("wtap_encap", WTAP_ENCAP_IEEE_802_11, dissect_ieee80211,
- proto_wlan);
+ return;
}