/* packet-ieee80211.c * Routines for Wireless LAN (IEEE 802.11) dissection * Copyright 2000, Axis Communications AB * Inquiries/bugreports should be sent to Johan.Jorgensen@axis.com * * $Id: packet-ieee80211.c,v 1.36 2001/06/22 08:12:11 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * Copied from README.developer * * This program is free software; you can redistribute it and/or * 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 * Magnus Hultman-Persson * */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif #ifdef NEED_SNPRINTF_H # ifdef HAVE_STDARG_H # include # else # include # endif # include "snprintf.h" #endif #include #include #include "bitswap.h" #include "proto.h" #include "packet.h" #include "resolv.h" #include "packet-llc.h" #include "packet-ieee80211.h" #include "etypes.h" /* ************************************************************************* */ /* Miscellaneous Constants */ /* ************************************************************************* */ #define SHORT_STR 128 /* ************************************************************************* */ /* Define some very useful macros that are used to analyze frame types etc. */ /* ************************************************************************* */ #define COMPOSE_FRAME_TYPE(x) (((x & 0x0C)<< 2)+((x & 0xF0) >> 4)) /* Create key to (sub)type */ #define COOK_PROT_VERSION(x) ((x) & 0x3) #define COOK_FRAME_TYPE(x) (((x) & 0xC) >> 2) #define COOK_FRAME_SUBTYPE(x) (((x) & 0xF0) >> 4) #define COOK_ADDR_SELECTOR(x) ((x) & 0x300) #define COOK_ASSOC_ID(x) ((x) & 0x3FFF) #define COOK_FRAGMENT_NUMBER(x) ((x) & 0x000F) #define COOK_SEQUENCE_NUMBER(x) (((x) & 0xFFF0) >> 4) #define COOK_FLAGS(x) (((x) & 0xFF00) >> 8) #define COOK_DS_STATUS(x) ((x) & 0x3) #define COOK_WEP_KEY(x) (((x) & 0xC0) >> 6) #define COL_SHOW_INFO(fd,info) if (check_col(fd,COL_INFO)) \ col_add_str(fd,COL_INFO,info); #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 FLAG_MORE_FRAGMENTS 0x04 #define FLAG_RETRY 0x08 #define FLAG_POWER_MGT 0x10 #define FLAG_MORE_DATA 0x20 #define FLAG_WEP 0x40 #define FLAG_ORDER 0x80 #define IS_TO_DS(x) ((x) & FLAG_TO_DS) #define IS_FROM_DS(x) ((x) & FLAG_FROM_DS) #define HAVE_FRAGMENTS(x) ((x) & FLAG_MORE_FRAGMENTS) #define IS_RETRY(x) ((x) & FLAG_RETRY) #define POWER_MGT_STATUS(x) ((x) & FLAG_POWER_MGT) #define HAS_MORE_DATA(x) ((x) & FLAG_MORE_DATA) #define IS_WEP(x) ((x) & FLAG_WEP) #define IS_STRICTLY_ORDERED(x) ((x) & FLAG_ORDER) #define MGT_RESERVED_RANGE(x) (((x>=0x06)&&(x<=0x07))||((x>=0x0D)&&(x<=0x0F))) #define CTRL_RESERVED_RANGE(x) ((x>=0x10)&&(x<=0x19)) #define DATA_RESERVED_RANGE(x) ((x>=0x28)&&(x<=0x2f)) #define SPEC_RESERVED_RANGE(x) ((x>=0x30)&&(x<=0x3f)) /* ************************************************************************* */ /* Constants used to identify cooked frame types */ /* ************************************************************************* */ #define MGT_FRAME 0x00 /* Frame type is management */ #define CONTROL_FRAME 0x01 /* Frame type is control */ #define DATA_FRAME 0x02 /* Frame type is Data */ #define DATA_SHORT_HDR_LEN 24 #define DATA_LONG_HDR_LEN 30 #define MGT_FRAME_HDR_LEN 24 /* Length of Managment frame-headers */ #define MGT_ASSOC_REQ 0x00 /* Management - association request */ #define MGT_ASSOC_RESP 0x01 /* Management - association response */ #define MGT_REASSOC_REQ 0x02 /* Management - reassociation request */ #define MGT_REASSOC_RESP 0x03 /* Management - reassociation response */ #define MGT_PROBE_REQ 0x04 /* Management - Probe request */ #define MGT_PROBE_RESP 0x05 /* Management - Probe response */ #define MGT_BEACON 0x08 /* Management - Beacon frame */ #define MGT_ATIM 0x09 /* Management - ATIM */ #define MGT_DISASS 0x0A /* Management - Disassociation */ #define MGT_AUTHENTICATION 0x0B /* Management - Authentication */ #define MGT_DEAUTHENTICATION 0x0C /* Management - Deauthentication */ #define CTRL_PS_POLL 0x1A /* Control - power-save poll */ #define CTRL_RTS 0x1B /* Control - request to send */ #define CTRL_CTS 0x1C /* Control - clear to send */ #define CTRL_ACKNOWLEDGEMENT 0x1D /* Control - acknowledgement */ #define CTRL_CFP_END 0x1E /* Control - contention-free period end */ #define CTRL_CFP_ENDACK 0x1F /* Control - contention-free period end/ack */ #define DATA 0x20 /* Data - Data */ #define DATA_CF_ACK 0x21 /* Data - Data + CF acknowledge */ #define DATA_CF_POLL 0x22 /* Data - Data + CF poll */ #define DATA_CF_ACK_POLL 0x23 /* Data - Data + CF acknowledge + CF poll */ #define DATA_NULL_FUNCTION 0x24 /* Data - Null function (no data) */ #define DATA_CF_ACK_NOD 0x25 /* Data - CF ack (no data) */ #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 0 #define DATA_ADDR_T2 (FLAG_FROM_DS << 8) #define DATA_ADDR_T3 (FLAG_TO_DS << 8) #define DATA_ADDR_T4 ((FLAG_TO_DS|FLAG_FROM_DS) << 8) /* ************************************************************************* */ /* Macros used to extract information about fixed fields */ /* ************************************************************************* */ #define ESS_SET(x) ((x) & 0x0001) #define IBSS_SET(x) ((x) & 0x0002) /* ************************************************************************* */ /* Logical field codes (dissector's encoding of fixed fields) */ /* ************************************************************************* */ #define FIELD_TIMESTAMP 0x01 /* 64-bit timestamp */ #define FIELD_BEACON_INTERVAL 0x02 /* 16-bit beacon interval */ #define FIELD_CAP_INFO 0x03 /* Add capability information tree */ #define FIELD_AUTH_ALG 0x04 /* Authentication algorithm used */ #define FIELD_AUTH_TRANS_SEQ 0x05 /* Authentication sequence number */ #define FIELD_CURRENT_AP_ADDR 0x06 #define FIELD_LISTEN_IVAL 0x07 #define FIELD_REASON_CODE 0x08 #define FIELD_ASSOC_ID 0x09 #define FIELD_STATUS_CODE 0x0A /* ************************************************************************* */ /* 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 /* ************************************************************************* */ /* Frame types, and their names */ /* ************************************************************************* */ static const value_string frame_type_subtype_vals[] = { {MGT_ASSOC_REQ, "Association Request"}, {MGT_ASSOC_RESP, "Association Response"}, {MGT_REASSOC_REQ, "Reassociation Request"}, {MGT_REASSOC_RESP, "Reassociation Response"}, {MGT_PROBE_REQ, "Probe Request"}, {MGT_PROBE_RESP, "Probe Response"}, {MGT_BEACON, "Beacon frame"}, {MGT_ATIM, "ATIM"}, {MGT_DISASS, "Dissassociate"}, {MGT_AUTHENTICATION, "Authentication"}, {MGT_DEAUTHENTICATION, "Deauthentication"}, {CTRL_PS_POLL, "Power-Save poll"}, {CTRL_RTS, "Request-to-send"}, {CTRL_CTS, "Clear-to-send"}, {CTRL_ACKNOWLEDGEMENT, "Acknowledgement"}, {CTRL_CFP_END, "CF-End (Control-frame)"}, {CTRL_CFP_ENDACK, "CF-End + CF-Ack (Control-frame)"}, {DATA, "Data"}, {DATA_CF_ACK, "Data + CF-Acknowledgement"}, {DATA_CF_POLL, "Data + CF-Poll"}, {DATA_CF_ACK_POLL, "Data + CF-Acknowledgement/Poll"}, {DATA_NULL_FUNCTION, "Null function (No data)"}, {DATA_CF_ACK_NOD, "Data + Acknowledgement (No data)"}, {DATA_CF_POLL_NOD, "Data + CF-Poll (No data)"}, {DATA_CF_ACK_POLL_NOD, "Data + CF-Acknowledgement/Poll (No data)"}, {0, NULL} }; static int proto_wlan = -1; /* ************************************************************************* */ /* Header field info values for FC-field */ /* ************************************************************************* */ static int hf_fc_field = -1; static int hf_fc_proto_version = -1; static int hf_fc_frame_type = -1; static int hf_fc_frame_subtype = -1; static int hf_fc_frame_type_subtype = -1; static int hf_fc_flags = -1; static int hf_fc_to_ds = -1; static int hf_fc_from_ds = -1; static int hf_fc_data_ds = -1; static int hf_fc_more_frag = -1; static int hf_fc_retry = -1; static int hf_fc_pwr_mgt = -1; static int hf_fc_more_data = -1; static int hf_fc_wep = -1; static int hf_fc_order = -1; /* ************************************************************************* */ /* Header values for Duration/ID field */ /* ************************************************************************* */ static int hf_did_duration = -1; static int hf_assoc_id = -1; /* ************************************************************************* */ /* Header values for different address-fields (all 4 of them) */ /* ************************************************************************* */ static int hf_addr_da = -1; /* Destination address subfield */ static int hf_addr_sa = -1; /* Source address subfield */ static int hf_addr_ra = -1; /* Receiver address subfield */ static int hf_addr_ta = -1; /* Transmitter address subfield */ static int hf_addr_bssid = -1; /* address is bssid */ /* ************************************************************************* */ /* Header values for sequence number field */ /* ************************************************************************* */ static int hf_frag_number = -1; static int hf_seq_number = -1; /* ************************************************************************* */ /* Header values for Frame Check field */ /* ************************************************************************* */ static int hf_fcs = -1; static int proto_wlan_mgt = -1; /* ************************************************************************* */ /* Fixed fields found in mgt frames */ /* ************************************************************************* */ static int ff_auth_alg = -1; /* Authentication algorithm field */ static int ff_auth_seq = -1; /* Authentication transaction sequence */ static int ff_current_ap = -1; /* Current AP MAC address */ static int ff_listen_ival = -1; /* Listen interval fixed field */ static int ff_timestamp = -1; /* 64 bit timestamp */ static int ff_beacon_interval = -1; /* 16 bit Beacon interval */ static int ff_assoc_id = -1; /* 16 bit AID field */ static int ff_reason = -1; /* 16 bit reason code */ static int ff_status_code = -1; /* Status code */ /* ************************************************************************* */ /* Flags found in the capability field (fixed field) */ /* ************************************************************************* */ static int ff_capture = -1; static int ff_cf_sta_poll = -1; /* CF pollable status for a STA */ static int ff_cf_ap_poll = -1; /* CF pollable status for an AP */ static int ff_cf_ess = -1; static int ff_cf_ibss = -1; static int ff_cf_privacy = -1; static int ff_cf_preamble = -1; static int ff_cf_pbcc = -1; static int ff_cf_agility = -1; /* ************************************************************************* */ /* Tagged value format fields */ /* ************************************************************************* */ static int tag_number = -1; static int tag_length = -1; static int tag_interpretation = -1; static int hf_fixed_parameters = -1; /* Protocol payload for management frames */ static int hf_tagged_parameters = -1; /* Fixed payload item */ static int hf_wep_iv = -1; static int hf_wep_key = -1; static int hf_wep_crc = -1; /* ************************************************************************* */ /* Protocol trees */ /* ************************************************************************* */ static gint ett_80211 = -1; static gint ett_proto_flags = -1; static gint ett_cap_tree = -1; static gint ett_fc_tree = -1; static gint ett_80211_mgt = -1; static gint ett_fixed_parameters = -1; static gint ett_tagged_parameters = -1; static gint ett_wep_parameters = -1; static dissector_handle_t llc_handle; /* ************************************************************************* */ /* Return the length of the current header (in bytes) */ /* ************************************************************************* */ static int find_header_length (guint16 fcf) { switch (COOK_FRAME_TYPE (fcf)) { case MGT_FRAME: return MGT_FRAME_HDR_LEN; case CONTROL_FRAME: switch (COMPOSE_FRAME_TYPE (fcf)) { case CTRL_CTS: case CTRL_ACKNOWLEDGEMENT: return 10; case CTRL_RTS: case CTRL_PS_POLL: case CTRL_CFP_END: case CTRL_CFP_ENDACK: return 16; } return 4; /* XXX */ case DATA_FRAME: return (COOK_ADDR_SELECTOR(fcf) == DATA_ADDR_T4) ? DATA_LONG_HDR_LEN : DATA_SHORT_HDR_LEN; default: return 4; /* XXX */ } } /* ************************************************************************* */ /* This is the capture function used to update packet counts */ /* ************************************************************************* */ void capture_ieee80211 (const u_char * pd, int offset, packet_counts * ld) { guint16 fcf, hdr_length; fcf = pletohs (&pd[0]); if (IS_WEP(COOK_FLAGS(fcf))) { ld->other++; return; } switch (COMPOSE_FRAME_TYPE (fcf)) { case DATA: /* We got a data frame */ case DATA_CF_ACK: /* Data with ACK */ case DATA_CF_POLL: case DATA_CF_ACK_POLL: hdr_length = find_header_length (fcf); capture_llc (pd, offset + hdr_length, ld); break; default: ld->other++; break; } } /* ************************************************************************* */ /* Add the subtree used to store the fixed parameters */ /* ************************************************************************* */ static proto_tree * get_fixed_parameter_tree (proto_tree * tree, tvbuff_t *tvb, int start, int size) { proto_item *fixed_fields; fixed_fields = proto_tree_add_uint_format (tree, hf_fixed_parameters, tvb, start, size, size, "Fixed parameters (%d bytes)", size); return proto_item_add_subtree (fixed_fields, ett_fixed_parameters); } /* ************************************************************************* */ /* Add the subtree used to store tagged parameters */ /* ************************************************************************* */ static proto_tree * get_tagged_parameter_tree (proto_tree * tree, tvbuff_t *tvb, int start, int size) { proto_item *tagged_fields; tagged_fields = proto_tree_add_uint_format (tree, hf_tagged_parameters, tvb, start, size, size, "Tagged parameters (%d bytes)", size); return proto_item_add_subtree (tagged_fields, ett_tagged_parameters); } /* ************************************************************************* */ /* 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 */ /* ************************************************************************* */ static void add_fixed_field (proto_tree * tree, tvbuff_t * tvb, int offset, int lfcode) { const guint8 *dataptr; char out_buff[SHORT_STR]; guint16 capability; proto_item *cap_item; static proto_tree *cap_tree; double temp_double; switch (lfcode) { case FIELD_TIMESTAMP: 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", 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; case FIELD_BEACON_INTERVAL: temp_double = (double) tvb_get_letohs (tvb, offset); temp_double = temp_double * 1024 / 1000000; proto_tree_add_double_format (tree, ff_beacon_interval, tvb, offset, 2, temp_double,"Beacon Interval: %f [Seconds]", temp_double); break; case FIELD_CAP_INFO: capability = tvb_get_letohs (tvb, offset); cap_item = proto_tree_add_uint_format (tree, ff_capture, tvb, offset, 2, capability, "Capability Information: 0x%04X", capability); cap_tree = proto_item_add_subtree (cap_item, ett_cap_tree); proto_tree_add_boolean (cap_tree, ff_cf_ess, tvb, offset, 1, capability); proto_tree_add_boolean (cap_tree, ff_cf_ibss, tvb, offset, 1, capability); proto_tree_add_boolean (cap_tree, ff_cf_privacy, tvb, offset, 1, capability); proto_tree_add_boolean (cap_tree, ff_cf_preamble, tvb, offset, 1, 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, 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)); else /* This is a STA */ proto_tree_add_uint (cap_tree, ff_cf_sta_poll, tvb, offset, 2, ((capability & 0xC) >> 2)); break; case FIELD_AUTH_ALG: proto_tree_add_uint (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); break; case FIELD_CURRENT_AP_ADDR: proto_tree_add_item (tree, ff_current_ap, tvb, offset, 6, FALSE); break; case FIELD_LISTEN_IVAL: proto_tree_add_item (tree, ff_listen_ival, tvb, offset, 2, TRUE); break; case FIELD_REASON_CODE: proto_tree_add_item (tree, ff_reason, tvb, offset, 2, TRUE); break; case FIELD_ASSOC_ID: proto_tree_add_item (tree, ff_assoc_id, tvb, offset, 2, TRUE); break; case FIELD_STATUS_CODE: proto_tree_add_item (tree, ff_status_code, tvb, offset, 2, TRUE); break; } } /* ************************************************************************* */ /* Dissect and add tagged (optional) fields to proto tree */ /* ************************************************************************* */ static int add_tagged_field (proto_tree * tree, tvbuff_t * tvb, int offset) { const guint8 *tag_data_ptr; guint32 tag_no, tag_len; unsigned int i; int n; char out_buff[SHORT_STR]; tag_no = tvb_get_guint8(tvb, offset); tag_len = tvb_get_guint8(tvb, offset + 1); tag_data_ptr = tvb_get_ptr (tvb, offset + 2, tag_len); 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); out_buff[tag_len + 1] = 0; proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2, tag_len, out_buff); break; 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); memset (out_buff, 0, SHORT_STR); strcpy (out_buff, "Supported rates: "); n = strlen (out_buff); for (i = 0; i < tag_len; i++) { n += snprintf (out_buff + n, SHORT_STR - n, "%2.1f%s ", (tag_data_ptr[i] & 0x7F) * 0.5, (tag_data_ptr[i] & 0x80) ? "(B)" : ""); } snprintf (out_buff + n, SHORT_STR - n, "[Mbit/sec]"); 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, "Dwell time 0x%04X, Hop Set %2d, Hop Pattern %2d, " "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, tag_len, out_buff); break; 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]); proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2, tag_len, out_buff); break; 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, "CFP count %u, CFP period %u, CFP max duration %u, " "CFP Remaining %u", tag_data_ptr[0], tag_data_ptr[1], pletohs (tag_data_ptr + 2), pletohs (tag_data_ptr + 4)); proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2, tag_len, out_buff); break; 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, " "(Bitmap suppressed)", tag_data_ptr[0], tag_data_ptr[1], tag_data_ptr[2]); proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2, tag_len, out_buff); break; 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)); proto_tree_add_string (tree, tag_interpretation, tvb, offset + 2, tag_len, out_buff); break; case TAG_CHALLENGE_TEXT: proto_tree_add_uint_format (tree, tag_number, tvb, offset, 1, tag_no, "Tag Number: %u (Challenge text)", 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, "Challenge text: %.47s", tag_data_ptr); proto_tree_add_string (tree, tag_interpretation, tvb, offset, tag_len, out_buff); break; default: return 0; } return tag_len + 2; } /* ************************************************************************* */ /* Dissect 802.11 management frame */ /* ************************************************************************* */ static void dissect_ieee80211_mgt (guint16 fcf, tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) { proto_item *ti = NULL; proto_tree *mgt_tree; proto_tree *fixed_tree; proto_tree *tagged_tree; guint32 next_idx; guint32 next_len; int tagged_parameter_tree_len; CHECK_DISPLAY_AS_DATA(proto_wlan_mgt, tvb, pinfo, tree); if (tree) { ti = proto_tree_add_item (tree, proto_wlan_mgt, tvb, 0, tvb_length(tvb), FALSE); mgt_tree = proto_item_add_subtree (ti, ett_80211_mgt); switch (COMPOSE_FRAME_TYPE(fcf)) { case MGT_ASSOC_REQ: fixed_tree = get_fixed_parameter_tree (mgt_tree, tvb, 0, 4); add_fixed_field (fixed_tree, tvb, 0, FIELD_CAP_INFO); add_fixed_field (fixed_tree, tvb, 2, FIELD_LISTEN_IVAL); next_idx = 4; /* Size of fixed fields */ tagged_parameter_tree_len = tvb_reported_length_remaining(tvb, next_idx + 4); tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx, tagged_parameter_tree_len); while (tagged_parameter_tree_len > 0) { if ((next_len=add_tagged_field (tagged_tree, tvb, next_idx))==0) break; next_idx +=next_len; tagged_parameter_tree_len -= next_len; } break; case MGT_ASSOC_RESP: fixed_tree = get_fixed_parameter_tree (mgt_tree, tvb, 0, 6); add_fixed_field (fixed_tree, tvb, 0, FIELD_CAP_INFO); add_fixed_field (fixed_tree, tvb, 2, FIELD_STATUS_CODE); add_fixed_field (fixed_tree, tvb, 4, FIELD_ASSOC_ID); next_idx = 6; /* Size of fixed fields */ tagged_parameter_tree_len = tvb_reported_length_remaining(tvb, next_idx + 4); tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx, tagged_parameter_tree_len); while (tagged_parameter_tree_len > 0) { if ((next_len=add_tagged_field (tagged_tree, tvb, next_idx))==0) break; next_idx +=next_len; tagged_parameter_tree_len -= next_len; } break; case MGT_REASSOC_REQ: fixed_tree = get_fixed_parameter_tree (mgt_tree, tvb, 0, 10); add_fixed_field (fixed_tree, tvb, 0, FIELD_CAP_INFO); add_fixed_field (fixed_tree, tvb, 2, FIELD_LISTEN_IVAL); add_fixed_field (fixed_tree, tvb, 4, FIELD_CURRENT_AP_ADDR); next_idx = 10; /* Size of fixed fields */ tagged_parameter_tree_len = tvb_reported_length_remaining(tvb, next_idx + 4); tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx, tagged_parameter_tree_len); while (tagged_parameter_tree_len > 0) { if ((next_len=add_tagged_field (tagged_tree, tvb, next_idx))==0) break; next_idx +=next_len; tagged_parameter_tree_len -= next_len; } break; case MGT_REASSOC_RESP: fixed_tree = get_fixed_parameter_tree (mgt_tree, tvb, 0, 10); add_fixed_field (fixed_tree, tvb, 0, FIELD_CAP_INFO); add_fixed_field (fixed_tree, tvb, 2, FIELD_STATUS_CODE); add_fixed_field (fixed_tree, tvb, 4, FIELD_ASSOC_ID); next_idx = 6; /* Size of fixed fields */ tagged_parameter_tree_len = tvb_reported_length_remaining(tvb, next_idx + 4); tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx, tagged_parameter_tree_len); while (tagged_parameter_tree_len > 0) { if ((next_len=add_tagged_field (tagged_tree, tvb, next_idx))==0) break; next_idx +=next_len; tagged_parameter_tree_len -= next_len; } break; case MGT_PROBE_REQ: next_idx = 0; tagged_parameter_tree_len = tvb_reported_length_remaining(tvb, next_idx + 4); tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx, tagged_parameter_tree_len); while (tagged_parameter_tree_len > 0) { if ((next_len=add_tagged_field (tagged_tree, tvb, next_idx))==0) break; next_idx +=next_len; tagged_parameter_tree_len -= next_len; } break; case MGT_PROBE_RESP: fixed_tree = get_fixed_parameter_tree (mgt_tree, tvb, 0, 12); add_fixed_field (fixed_tree, tvb, 0, FIELD_TIMESTAMP); add_fixed_field (fixed_tree, tvb, 8, FIELD_BEACON_INTERVAL); add_fixed_field (fixed_tree, tvb, 10, FIELD_CAP_INFO); next_idx = 12; /* Size of fixed fields */ tagged_parameter_tree_len = tvb_reported_length_remaining(tvb, next_idx + 4); tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx, tagged_parameter_tree_len); while (tagged_parameter_tree_len > 0) { if ((next_len=add_tagged_field (tagged_tree, tvb, next_idx))==0) break; next_idx +=next_len; tagged_parameter_tree_len -= next_len; } break; case MGT_BEACON: /* Dissect protocol payload fields */ fixed_tree = get_fixed_parameter_tree (mgt_tree, tvb, 0, 12); add_fixed_field (fixed_tree, tvb, 0, FIELD_TIMESTAMP); add_fixed_field (fixed_tree, tvb, 8, FIELD_BEACON_INTERVAL); add_fixed_field (fixed_tree, tvb, 10, FIELD_CAP_INFO); next_idx = 12; /* Size of fixed fields */ tagged_parameter_tree_len = tvb_reported_length_remaining(tvb, next_idx + 4); tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx, tagged_parameter_tree_len); while (tagged_parameter_tree_len > 0) { if ((next_len=add_tagged_field (tagged_tree, tvb, next_idx))==0) break; next_idx +=next_len; tagged_parameter_tree_len -= next_len; } break; case MGT_ATIM: break; case MGT_DISASS: fixed_tree = get_fixed_parameter_tree (mgt_tree, tvb, 0, 2); add_fixed_field (fixed_tree, tvb, 0, FIELD_REASON_CODE); break; case MGT_AUTHENTICATION: fixed_tree = get_fixed_parameter_tree (mgt_tree, tvb, 0, 6); add_fixed_field (fixed_tree, tvb, 0, FIELD_AUTH_ALG); add_fixed_field (fixed_tree, tvb, 2, FIELD_AUTH_TRANS_SEQ); add_fixed_field (fixed_tree, tvb, 4, FIELD_STATUS_CODE); next_idx = 6; /* Size of fixed fields */ tagged_parameter_tree_len = tvb_reported_length_remaining(tvb, next_idx + 4); if (tagged_parameter_tree_len != 0) { tagged_tree = get_tagged_parameter_tree (mgt_tree, tvb, next_idx, tagged_parameter_tree_len); while (tagged_parameter_tree_len > 0) { if ((next_len=add_tagged_field (tagged_tree, tvb, next_idx))==0) break; next_idx +=next_len; tagged_parameter_tree_len -= next_len; } } break; case MGT_DEAUTHENTICATION: fixed_tree = get_fixed_parameter_tree (mgt_tree, tvb, 0, 2); add_fixed_field (fixed_tree, tvb, 0, FIELD_REASON_CODE); break; } } } static void set_src_addr_cols(packet_info *pinfo, const guint8 *addr, char *type) { if (check_col(pinfo->fd, COL_RES_DL_SRC)) col_add_fstr(pinfo->fd, COL_RES_DL_SRC, "%s (%s)", get_ether_name(addr), type); if (check_col(pinfo->fd, COL_UNRES_DL_SRC)) col_add_fstr(pinfo->fd, COL_UNRES_DL_SRC, "%s (%s)", ether_to_str(addr), type); } static void set_dst_addr_cols(packet_info *pinfo, const guint8 *addr, char *type) { if (check_col(pinfo->fd, COL_RES_DL_DST)) col_add_fstr(pinfo->fd, COL_RES_DL_DST, "%s (%s)", get_ether_name(addr), type); if (check_col(pinfo->fd, COL_UNRES_DL_DST)) col_add_fstr(pinfo->fd, COL_UNRES_DL_DST, "%s (%s)", ether_to_str(addr), type); } /* ************************************************************************* */ /* Dissect 802.11 frame */ /* ************************************************************************* */ static void dissect_ieee80211 (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) { guint16 fcf, flags, frame_type_subtype; const guint8 *src = NULL, *dst = NULL; proto_item *ti = NULL; proto_item *flag_item; proto_item *fc_item; proto_tree *hdr_tree = NULL; proto_tree *flag_tree; proto_tree *fc_tree; guint16 hdr_len; tvbuff_t *next_tvb; guint32 addr_type; 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); fcf = tvb_get_letohs (tvb, 0); hdr_len = find_header_length (fcf); frame_type_subtype = COMPOSE_FRAME_TYPE(fcf); COL_SHOW_INFO_CONST (pinfo->fd, val_to_str(frame_type_subtype, frame_type_subtype_vals, "Unrecognized (Reserved frame)")); /* Add the FC to the current tree */ if (tree) { 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); proto_tree_add_uint (hdr_tree, hf_fc_frame_type_subtype, tvb, 0, 1, frame_type_subtype); fc_item = proto_tree_add_uint_format (hdr_tree, hf_fc_field, tvb, 0, 2, fcf, "Frame Control: 0x%04X", fcf); fc_tree = proto_item_add_subtree (fc_item, ett_fc_tree); proto_tree_add_uint (fc_tree, hf_fc_proto_version, tvb, 0, 1, COOK_PROT_VERSION (fcf)); proto_tree_add_uint (fc_tree, hf_fc_frame_type, tvb, 0, 1, COOK_FRAME_TYPE (fcf)); proto_tree_add_uint (fc_tree, hf_fc_frame_subtype, tvb, 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, 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, COOK_DS_STATUS (flags)); proto_tree_add_boolean (flag_tree, hf_fc_more_frag, tvb, 1, 1, flags); proto_tree_add_boolean (flag_tree, hf_fc_retry, tvb, 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_more_data, tvb, 1, 1, flags); proto_tree_add_boolean (flag_tree, hf_fc_wep, tvb, 1, 1, flags); proto_tree_add_boolean (flag_tree, hf_fc_order, tvb, 1, 1, flags); 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) { case MGT_ASSOC_REQ: case MGT_ASSOC_RESP: case MGT_REASSOC_REQ: case MGT_REASSOC_RESP: case MGT_PROBE_REQ: case MGT_PROBE_RESP: case MGT_BEACON: case MGT_ATIM: case MGT_DISASS: case MGT_AUTHENTICATION: case MGT_DEAUTHENTICATION: /* * All management frame types have the same header. */ src = tvb_get_ptr (tvb, 10, 6); dst = tvb_get_ptr (tvb, 4, 6); SET_ADDRESS(&pinfo->dl_src, AT_ETHER, 6, src); SET_ADDRESS(&pinfo->src, AT_ETHER, 6, src); SET_ADDRESS(&pinfo->dl_dst, AT_ETHER, 6, dst); SET_ADDRESS(&pinfo->dst, AT_ETHER, 6, dst); if (tree) { proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 4, 6, dst); proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 10, 6, src); proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 16, 6, tvb_get_ptr (tvb, 16, 6)); proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2, COOK_FRAGMENT_NUMBER (tvb_get_letohs (tvb, 22))); proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2, COOK_SEQUENCE_NUMBER (tvb_get_letohs (tvb, 22))); } break; case CTRL_PS_POLL: src = tvb_get_ptr (tvb, 10, 6); dst = tvb_get_ptr (tvb, 4, 6); set_src_addr_cols(pinfo, src, "BSSID"); set_dst_addr_cols(pinfo, dst, "BSSID"); if (tree) { proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 4, 6, dst); 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); 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); proto_tree_add_ether (hdr_tree, hf_addr_ta, tvb, 10, 6, src); } break; case CTRL_CTS: dst = tvb_get_ptr (tvb, 4, 6); set_dst_addr_cols(pinfo, dst, "RA"); if (tree) proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6, dst); break; case CTRL_ACKNOWLEDGEMENT: dst = tvb_get_ptr (tvb, 4, 6); set_dst_addr_cols(pinfo, dst, "RA"); if (tree) proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6, dst); break; case CTRL_CFP_END: src = tvb_get_ptr (tvb, 10, 6); dst = tvb_get_ptr (tvb, 4, 6); set_src_addr_cols(pinfo, src, "BSSID"); set_dst_addr_cols(pinfo, dst, "RA"); if (tree) { proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6, dst); proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 10, 6, src); } break; case CTRL_CFP_ENDACK: src = tvb_get_ptr (tvb, 10, 6); dst = tvb_get_ptr (tvb, 4, 6); set_src_addr_cols(pinfo, src, "BSSID"); set_dst_addr_cols(pinfo, dst, "RA"); if (tree) { proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6, dst); proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 10, 6, src); } break; case DATA: case DATA_CF_ACK: case DATA_CF_POLL: case DATA_CF_ACK_POLL: addr_type = COOK_ADDR_SELECTOR (fcf); /* In order to show src/dst address we must always do the following */ switch (addr_type) { case DATA_ADDR_T1: src = tvb_get_ptr (tvb, 10, 6); dst = tvb_get_ptr (tvb, 4, 6); break; case DATA_ADDR_T2: src = tvb_get_ptr (tvb, 16, 6); dst = tvb_get_ptr (tvb, 4, 6); break; case DATA_ADDR_T3: src = tvb_get_ptr (tvb, 10, 6); dst = tvb_get_ptr (tvb, 16, 6); break; case DATA_ADDR_T4: src = tvb_get_ptr (tvb, 24, 6); dst = tvb_get_ptr (tvb, 16, 6); break; } SET_ADDRESS(&pinfo->dl_src, AT_ETHER, 6, src); SET_ADDRESS(&pinfo->src, AT_ETHER, 6, src); SET_ADDRESS(&pinfo->dl_dst, AT_ETHER, 6, dst); SET_ADDRESS(&pinfo->dst, AT_ETHER, 6, dst); /* Now if we have a tree we start adding stuff */ if (tree) { switch (addr_type) { case DATA_ADDR_T1: proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 4, 6, dst); proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 10, 6, src); proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 16, 6, tvb_get_ptr (tvb, 16, 6)); proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2, COOK_FRAGMENT_NUMBER (tvb_get_letohs (tvb, 22))); proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2, COOK_SEQUENCE_NUMBER (tvb_get_letohs (tvb, 22))); 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))); proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2, COOK_SEQUENCE_NUMBER (tvb_get_letohs (tvb, 22))); break; case DATA_ADDR_T3: proto_tree_add_ether (hdr_tree, hf_addr_bssid, tvb, 4, 6, tvb_get_ptr (tvb, 4, 6)); proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 10, 6, src); proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 16, 6, dst); proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2, COOK_FRAGMENT_NUMBER (tvb_get_letohs (tvb, 22))); proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2, COOK_SEQUENCE_NUMBER (tvb_get_letohs (tvb, 22))); break; case DATA_ADDR_T4: proto_tree_add_ether (hdr_tree, hf_addr_ra, tvb, 4, 6, tvb_get_ptr (tvb, 4, 6)); proto_tree_add_ether (hdr_tree, hf_addr_ta, tvb, 10, 6, tvb_get_ptr (tvb, 10, 6)); proto_tree_add_ether (hdr_tree, hf_addr_da, tvb, 16, 6, dst); proto_tree_add_uint (hdr_tree, hf_frag_number, tvb, 22, 2, COOK_FRAGMENT_NUMBER (tvb_get_letohs (tvb, 22))); proto_tree_add_uint (hdr_tree, hf_seq_number, tvb, 22, 2, COOK_SEQUENCE_NUMBER (tvb_get_letohs (tvb, 22))); proto_tree_add_ether (hdr_tree, hf_addr_sa, tvb, 24, 6, src); break; } } break; } /* * Only management and data frames have a body, so we don't have * anything more to do for other types of frames. */ switch (COOK_FRAME_TYPE (fcf)) { case MGT_FRAME: case DATA_FRAME: 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 (tree) { get_wep_parameter_tree (tree, tvb, hdr_len, pkt_len); pkt_len -= hdr_len + 4; cap_len -= hdr_len + 4; /* * OK, pkt_len and cap_len have had the length of the 802.11 * header and WEP parameters subtracted. * * If there's anything left: * * if cap_len is greater than or equal to pkt_len (i.e., we * captured the entire packet), subtract the length of the * WEP CRC from cap_len; * * if cap_len is from 1 to 3 bytes less than pkt_len (i.e., * we captured some but not all of the WEP CRC), subtract * the length of the part of the WEP CRC we captured from * crc_len; * * otherwise, (i.e., we captured none of the WEP CRC), * leave cap_len alone; * * and subtract the length of the WEP CRC from pkt_len. */ if (cap_len >= pkt_len) cap_len -= 4; else if ((pkt_len - cap_len) >= 1 && (pkt_len - cap_len) <= 3) cap_len -= 4 - (pkt_len - cap_len); pkt_len -= 4; if (cap_len > 0 && pkt_len > 0) dissect_data (tvb, hdr_len + 4, pinfo, tree); } return; } /* * Now dissect the body of a non-WEP-encrypted frame. */ next_tvb = tvb_new_subset (tvb, hdr_len, -1, -1); switch (COOK_FRAME_TYPE (fcf)) { case MGT_FRAME: dissect_ieee80211_mgt (fcf, next_tvb, pinfo, tree); break; case DATA_FRAME: call_dissector (llc_handle, next_tvb, pinfo, tree); break; } } void proto_register_wlan (void) { static const value_string frame_type[] = { {MGT_FRAME, "Management frame"}, {CONTROL_FRAME, "Control frame"}, {DATA_FRAME, "Data frame"}, {0, NULL} }; static const value_string tofrom_ds[] = { {0, "Not leaving DS or network is operating in AD-HOC mode (To DS: 0 From DS: 0)"}, {FLAG_TO_DS, "Frame is entering DS (To DS: 1 From DS: 0)"}, {FLAG_FROM_DS, "Frame is exiting DS (To DS: 0 From DS: 1)"}, {FLAG_TO_DS|FLAG_FROM_DS, "Frame part of WDS (To DS: 1 From DS: 1)"}, {0, NULL} }; static const true_false_string tods_flag = { "TO DS: Should be false", "Not used" }; static const true_false_string fromds_flag = { "FROM DS: Should be false", "Not used" }; static const true_false_string more_frags = { "MSDU/MMPDU is fragmented", "No fragments" }; static const true_false_string retry_flags = { "Frame is being retransmitted", "Frame is not being retransmitted" }; static const true_false_string pm_flags = { "STA will go to sleep", "STA will stay up" }; static const true_false_string md_flags = { "Data is buffered for STA at AP", "No data buffered" }; static const true_false_string wep_flags = { "WEP is enabled", "WEP is disabled" }; static const true_false_string order_flags = { "Strictly ordered", "Not strictly ordered" }; static const true_false_string cf_ess_flags = { "Transmitter is an AP", "Transmitter is a STA" }; static const true_false_string cf_privacy_flags = { "AP/STA can support WEP", "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", "Transmitter belongs to a BSS" }; static const value_string sta_cf_pollable[] = { {0x00, "Station is not CF-Pollable"}, {0x02, "Station is CF-Pollable, " "not requesting to be placed on the CF-polling list"}, {0x01, "Station is CF-Pollable, " "requesting to be placed on the CF-polling list"}, {0x03, "Station is CF-Pollable, requesting never to be polled"}, {0, NULL} }; static const value_string ap_cf_pollable[] = { {0x00, "No point coordinator at AP"}, {0x02, "Point coordinator at AP for delivery only (no polling)"}, {0x01, "Point coordinator at AP for delivery and polling"}, {0x03, "Reserved"}, {0, NULL} }; static const value_string auth_alg[] = { {0x00, "Open System"}, {0x01, "Shared key"}, {0, NULL} }; static const value_string reason_codes[] = { {0x00, "Reserved"}, {0x01, "Unspecified reason"}, {0x02, "Previous authentication no longer valid"}, {0x03, "Deauthenticated because sending STA is leaving (has left) " "IBSS or ESS"}, {0x04, "Disassociated due to inactivity"}, {0x05, "Disassociated because AP is unable to handle all currently " "associated stations"}, {0x06, "Class 2 frame received from nonauthenticated station"}, {0x07, "Class 3 frame received from nonassociated station"}, {0x08, "Disassociated because sending STA is leaving (has left) BSS"}, {0x09, "Station requesting (re)association is not authenticated with " "responding station"}, {0x00, NULL} }; static const value_string status_codes[] = { {0x00, "Successful"}, {0x01, "Unspecified failure"}, {0x0A, "Cannot support all requested capabilities in the " "Capability information field"}, {0x0B, "Reassociation denied due to inability to confirm that " "association exists"}, {0x0C, "Association denied due to reason outside the scope of this " "standard"}, {0x0D, "Responding station does not support the specified authentication " "algorithm"}, {0x0E, "Received an Authentication frame with authentication sequence " "transaction sequence number out of expected sequence"}, {0x0F, "Authentication rejected because of challenge failure"}, {0x10, "Authentication rejected due to timeout waiting for next " "frame in sequence"}, {0x11, "Association denied because AP is unable to handle additional " "associated stations"}, {0x12, "Association denied due to requesting station not supporting all " "of the datarates in the BSSBasicServiceSet Parameter"}, {0x00, NULL} }; static hf_register_info hf[] = { {&hf_fc_field, {"Frame Control Field", "wlan.fc", FT_UINT16, BASE_HEX, NULL, 0, "MAC Frame control", HFILL }}, {&hf_fc_proto_version, {"Version", "wlan.fc.version", FT_UINT8, BASE_DEC, NULL, 0, "MAC Protocol version", HFILL }}, /* 0 */ {&hf_fc_frame_type, {"Type", "wlan.fc.type", FT_UINT8, BASE_DEC, VALS(frame_type), 0, "Frame type", HFILL }}, {&hf_fc_frame_subtype, {"Subtype", "wlan.fc.subtype", FT_UINT8, BASE_DEC, NULL, 0, "Frame subtype", HFILL }}, /* 2 */ {&hf_fc_frame_type_subtype, {"Type/Subtype", "wlan.fc.type_subtype", FT_UINT16, BASE_DEC, VALS(frame_type_subtype_vals), 0, "Type and subtype combined", HFILL }}, {&hf_fc_flags, {"Protocol Flags", "wlan.flags", FT_UINT8, BASE_HEX, NULL, 0, "Protocol flags", HFILL }}, {&hf_fc_data_ds, {"DS status", "wlan.fc.ds", FT_UINT8, BASE_HEX, VALS (&tofrom_ds), 0, "Data-frame DS-traversal status", HFILL }}, /* 3 */ {&hf_fc_to_ds, {"To DS", "wlan.fc.tods", FT_BOOLEAN, 8, TFS (&tods_flag), FLAG_TO_DS, "To DS flag", HFILL }}, /* 4 */ {&hf_fc_from_ds, {"From DS", "wlan.fc.fromds", FT_BOOLEAN, 8, TFS (&fromds_flag), FLAG_FROM_DS, "From DS flag", HFILL }}, /* 5 */ {&hf_fc_more_frag, {"Fragments", "wlan.fc.frag", FT_BOOLEAN, 8, TFS (&more_frags), FLAG_MORE_FRAGMENTS, "More Fragments flag", HFILL }}, /* 6 */ {&hf_fc_retry, {"Retry", "wlan.fc.retry", FT_BOOLEAN, 8, TFS (&retry_flags), FLAG_RETRY, "Retransmission flag", HFILL }}, {&hf_fc_pwr_mgt, {"PWR MGT", "wlan.fc.pwrmgt", FT_BOOLEAN, 8, TFS (&pm_flags), FLAG_POWER_MGT, "Power management status", HFILL }}, {&hf_fc_more_data, {"More Data", "wlan.fc.moredata", FT_BOOLEAN, 8, TFS (&md_flags), FLAG_MORE_DATA, "More data flag", HFILL }}, {&hf_fc_wep, {"WEP flag", "wlan.fc.wep", FT_BOOLEAN, 8, TFS (&wep_flags), FLAG_WEP, "WEP flag", HFILL }}, {&hf_fc_order, {"Order flag", "wlan.fc.order", FT_BOOLEAN, 8, TFS (&order_flags), FLAG_ORDER, "Strictly ordered flag", HFILL }}, {&hf_assoc_id, {"Association ID","wlan.aid",FT_UINT16, BASE_DEC,NULL,0, "Association-ID field", HFILL }}, {&hf_did_duration, {"Duration", "wlan.duration", FT_UINT16, BASE_DEC, NULL, 0, "Duration field", HFILL }}, {&hf_addr_da, {"Destination address", "wlan.da", FT_ETHER, BASE_NONE, NULL, 0, "Destination Hardware address", HFILL }}, {&hf_addr_sa, {"Source address", "wlan.sa", FT_ETHER, BASE_NONE, NULL, 0, "Source Hardware address", HFILL }}, {&hf_addr_ra, {"Receiver address", "wlan.ra", FT_ETHER, BASE_NONE, NULL, 0, "Receiving Station Hardware Address", HFILL }}, {&hf_addr_ta, {"Transmitter address", "wlan.ta", FT_ETHER, BASE_NONE, NULL, 0, "Transmitting Station Hardware Address", HFILL }}, {&hf_addr_bssid, {"BSS Id", "wlan.bssid", FT_ETHER, BASE_NONE, NULL, 0, "Basic Service Set ID", HFILL }}, {&hf_frag_number, {"Fragment number", "wlan.frag", FT_UINT16, BASE_DEC, NULL, 0, "Fragment number", HFILL }}, {&hf_seq_number, {"Sequence number", "wlan.seq", FT_UINT16, BASE_DEC, NULL, 0, "Sequence number", HFILL }}, {&hf_fcs, {"Frame Check Sequence (not verified)", "wlan.fcs", FT_UINT32, BASE_HEX, NULL, 0, "", HFILL }}, {&hf_wep_iv, {"Initialization Vector", "wlan.wep.iv", FT_UINT24, BASE_HEX, NULL, 0, "Initialization Vector", HFILL }}, {&hf_wep_key, {"Key", "wlan.wep.key", FT_UINT8, BASE_DEC, NULL, 0, "Key", HFILL }}, {&hf_wep_crc, {"WEP CRC (not verified)", "wlan.wep.crc", FT_UINT32, BASE_HEX, NULL, 0, "WEP CRC", HFILL }}, }; static hf_register_info ff[] = { {&ff_timestamp, {"Timestamp", "wlan_mgt.fixed.timestamp", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }}, {&ff_auth_alg, {"Authentication Algorithm", "wlan_mgt.fixed.auth.alg", FT_UINT16, BASE_DEC, VALS (&auth_alg), 0, "", HFILL }}, {&ff_beacon_interval, {"Beacon Interval", "wlan_mgt.fixed.beacon", FT_DOUBLE, BASE_DEC, NULL, 0, "", HFILL }}, {&hf_fixed_parameters, {"Fixed parameters", "wlan_mgt.fixed.all", FT_UINT16, BASE_DEC, NULL, 0, "", HFILL }}, {&hf_tagged_parameters, {"Tagged parameters", "wlan_mgt.tagged.all", FT_UINT16, BASE_DEC, NULL, 0, "", HFILL }}, {&ff_capture, {"Capabilities", "wlan_mgt.fixed.capabilities", FT_UINT16, BASE_HEX, NULL, 0, "Capability information", HFILL }}, {&ff_cf_sta_poll, {"CFP participation capabilities", "wlan_mgt.fixed.capabilities.cfpoll.sta", FT_UINT16, BASE_HEX, VALS (&sta_cf_pollable), 0, "CF-Poll capabilities for a STA", HFILL }}, {&ff_cf_ap_poll, {"CFP participation capabilities", "wlan_mgt.fixed.capabilities.cfpoll.ap", FT_UINT16, BASE_HEX, VALS (&ap_cf_pollable), 0, "CF-Poll capabilities for an AP", HFILL }}, {&ff_cf_ess, {"ESS capabilities", "wlan_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 }}, {&ff_cf_preamble, {"Short Preamble", "wlan_mgt.fixed.capabilities.preamble", FT_BOOLEAN, 8, 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 }}, {&ff_cf_agility, {"Channel Agility", "wlan_mgt.fixed.capabilities.agility", FT_BOOLEAN, 8, TFS (&cf_agility_flags), 0x0080, "Channel Agility", HFILL }}, {&ff_auth_seq, {"Authentication SEQ", "wlan_mgt.fixed.auth_seq", FT_UINT16, BASE_HEX, NULL, 0, "Authentication sequence number", HFILL }}, {&ff_assoc_id, {"Association ID", "wlan_mgt.fixed.aid", FT_UINT16, BASE_HEX, NULL, 0, "Association ID", HFILL }}, {&ff_listen_ival, {"Listen Interval", "wlan_mgt.fixed.listen_ival", FT_UINT16, BASE_HEX, NULL, 0, "Listen Interval", HFILL }}, {&ff_current_ap, {"Current AP", "wlan_mgt.fixed.current_ap", FT_ETHER, BASE_NONE, NULL, 0, "MAC address of current AP", HFILL }}, {&ff_reason, {"Reason code", "wlan_mgt.fixed.reason_code", FT_UINT16, BASE_HEX, VALS (&reason_codes), 0, "Reason for unsolicited notification", HFILL }}, {&ff_status_code, {"Status code", "wlan_mgt.fixed.status_code", FT_UINT16, BASE_HEX, VALS (&status_codes), 0, "Status of requested event", HFILL }}, {&tag_number, {"Tag", "wlan_mgt.tag.number", FT_UINT16, BASE_DEC, NULL, 0, "Element ID", HFILL }}, {&tag_length, {"Tag length", "wlan_mgt.tag.length", FT_UINT16, BASE_DEC, NULL, 0, "Length of tag", HFILL }}, {&tag_interpretation, {"Tag interpretation", "wlan_mgt.tag.interpretation", FT_STRING, BASE_NONE, NULL, 0, "Interpretation of tag", HFILL }} }; static gint *tree_array[] = { &ett_80211, &ett_fc_tree, &ett_proto_flags, &ett_80211_mgt, &ett_fixed_parameters, &ett_tagged_parameters, &ett_wep_parameters, &ett_cap_tree, }; proto_wlan = proto_register_protocol ("IEEE 802.11 wireless LAN", "IEEE 802.11", "wlan"); proto_register_field_array (proto_wlan, hf, array_length (hf)); proto_wlan_mgt = proto_register_protocol ("IEEE 802.11 wireless LAN management frame", "802.11 MGT", "wlan_mgt"); proto_register_field_array (proto_wlan_mgt, ff, array_length (ff)); proto_register_subtree_array (tree_array, array_length (tree_array)); } void proto_reg_handoff_wlan(void) { /* * Get a handle for the LLC dissector. */ llc_handle = find_dissector("llc"); dissector_add("wtap_encap", WTAP_ENCAP_IEEE_802_11, dissect_ieee80211, proto_wlan); }