Ethereal-dev: [Ethereal-dev] 802.11 Radio Header

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

From: Chris Waters <chris@xxxxxxxxxxxx>
Date: Tue, 04 Jun 2002 22:30:55 -0700
Hi,

I sent an email a week or so ago about making the new 802.11 radio header
more flexible. I have implemented it the idea I described against the latest
sources. Here is a snippet from a tethereal dump:

...
802.11 Radio Header: FCS Error
    Signal: 0x09
    Silence: 0x09
    Rate: 1 Mbit/s (0x0a)
    Time: 0x0032d8cb
    Type: Normal (0x00)
    PCF: Not CF
    Undecrypted: Unencrypted
    FCS: FCS error, frame is corrupted
IEEE 802.11
    Type/Subtype: Beacon frame (8)
    Frame Control: 0x0080
        Version: 0
        Type: Management frame (0)
        Subtype: 8
        Flags: 0x0
...

The fields that are shown here are the ones that the Intersil PRISM chipset
makes available, and this packet happened to contain a frame check sequence
error. Adding fields that other chipsets support should be easy, and
transparent to any other capture drivers.

I could have implemented this feature with a new WTAP encapsulation type,
but I feel that the small, fixed header than was recently checked in against
the WTAP_ENCAP_IEEE_802_11_WITH_RADIO encapsulation type would quickly
become obsolete. Therefore it makes sense to remove it now. Of course,
whoever submitted that patch would need to change the program that they are
making the captures with, and I can understand that that might be a problem.
If necessary I can define a new encapsulation type.

The header format that I have implemented is very simple and borrows from
the technique used in DHCP options. It is a tag-length-value format, where
each tag is 8-bits, each length is 8-bits (and is the length of the data,
not including the tag or length fields) and the value. Two special tags
define the end of the list and a pad byte. These special tags have no length
or value fields. Here are the fields that I have defined:

#define WLAN_RADIO_HDR_PAD 0 /* Pad. */
#define WLAN_RADIO_HDR_END 1 /* End of the list. */
#define WLAN_RADIO_HDR_SIGNAL 10 /* Signal strength in dBm, signed byte. */
#define WLAN_RADIO_HDR_NOISE 11 /* Noise level in dBm, signed byte. */
#define WLAN_RADIO_HDR_RATE 12 /* Data rate, unsigned byte. */
#define WLAN_RADIO_HDR_TIMESTAMP 13 /* Timestamp in us, unsigned 32-bits
network byte order. */
#define WLAN_RADIO_HDR_MSG_TYPE 14 /* Packet type, unsigned byte. */
#define WLAN_RADIO_HDR_CF 15 /* Whether packet arrived during CF period,
unsigned byte. */
#define WLAN_RADIO_HDR_UN_DECR 16 /* Whether packet could not be decrypted
by MAC, unsigned byte. */
#define WLAN_RADIO_HDR_FCS_ERR 17 /* Whether packet contains an FCS error,
unsigned byte. */

Here is the patch:

cvs diff -u packet-ieee80211.c
Index: packet-ieee80211.c
===================================================================
RCS file: /cvsroot/ethereal/packet-ieee80211.c,v
retrieving revision 1.63
diff -u -r1.63 packet-ieee80211.c
--- packet-ieee80211.c 2002/06/04 07:03:44 1.63
+++ packet-ieee80211.c 2002/06/05 05:26:42
@@ -234,15 +234,25 @@
 };

 static int proto_wlan = -1;
+static int proto_wlan_radio = -1;
+
+/*
************************************************************************* */
+/*                WLAN radio header felds
*/
+/*
************************************************************************* */
+
+static int hf_status_field = -1;
+static int hf_status_msg_type = -1;
+static int hf_status_pcf = -1;
+static int hf_status_mac_port = -1;
+static int hf_status_undecrypted = -1;
+static int hf_status_fcs_error = -1;
+
+static int hf_time = -1;
+static int hf_silence = -1;
+static int hf_signal = -1;
+static int hf_rate = -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_fc_field = -1;
@@ -352,6 +362,7 @@
 /*                               Protocol trees
*/
 /*
************************************************************************* */
 static gint ett_80211 = -1;
+static gint ett_80211_radio = -1;
 static gint ett_proto_flags = -1;
 static gint ett_cap_tree = -1;
 static gint ett_fc_tree = -1;
@@ -1141,6 +1152,115 @@
       col_set_str(pinfo->cinfo, COL_INFO, "[Illegal fragments]");
   }
 }
+
+/*
************************************************************************* */
+/*                          Dissect 802.11 radio header
*/
+/*
************************************************************************* */
+
+#define WLAN_RADIO_HDR_PAD 0 /* Pad. */
+#define WLAN_RADIO_HDR_END 1 /* End of the list. */
+#define WLAN_RADIO_HDR_SIGNAL 10 /* Signal strength in dBm, signed byte. */
+#define WLAN_RADIO_HDR_NOISE 11 /* Noise level in dBm, signed byte. */
+#define WLAN_RADIO_HDR_RATE 12 /* Data rate, unsigned byte. */
+#define WLAN_RADIO_HDR_TIMESTAMP 13 /* Timestamp in us, unsigned 32-bits
network byte order. */
+#define WLAN_RADIO_HDR_MSG_TYPE 14 /* Packet type, unsigned byte. */
+#define WLAN_RADIO_HDR_CF 15 /* Whether packet arrived during CF period,
unsigned byte. */
+#define WLAN_RADIO_HDR_UN_DECR 16 /* Whether packet could not be decrypted
by MAC, unsigned byte. */
+#define WLAN_RADIO_HDR_FCS_ERR 17 /* Whether packet contains an FCS error,
unsigned byte. */
+
+static int add_radio_info(tvbuff_t * tvb, packet_info * pinfo,
+     proto_tree * tree)
+{
+ guint8 tag, length, fcs_err = 0, encr = 0;
+ proto_item *ti = NULL;
+ int pos = 0;
+ proto_tree *hdr_tree;
+
+ ti = proto_tree_add_protocol_format (tree, proto_wlan, tvb, 0,
tvb_length(tvb),
+        "802.11 Radio Header: ");
+  hdr_tree = proto_item_add_subtree (ti, ett_80211_radio);
+
+ /*
+  * Read all tags in an endless loop. If the packet is malformed this
+  * loop might be a problem.
+  */
+ while (TRUE) {
+  tag = tvb_get_guint8(tvb, pos++);
+
+  switch (tag) {
+  case WLAN_RADIO_HDR_PAD:
+   length = 0;
+   break;
+
+  case WLAN_RADIO_HDR_END:
+   /* Fill in header with information from other tags. */
+   proto_item_append_text(ti,"%s", fcs_err?"FCS
Error":(encr?"Encrypted":"Good"));
+   return pos;
+
+  case WLAN_RADIO_HDR_SIGNAL:
+   length = tvb_get_guint8(tvb, pos++);
+   proto_tree_add_uint_format (hdr_tree, hf_signal, tvb, pos-2, 3,
+        tvb_get_guint8(tvb, pos),
+         "Signal: 0x%02X",
+         tvb_get_guint8(tvb, pos));
+   pos += length;
+   break;
+
+  case WLAN_RADIO_HDR_NOISE:
+   length = tvb_get_guint8(tvb, pos++);
+   proto_tree_add_uint_format (hdr_tree, hf_silence, tvb, pos-2, 3,
+        tvb_get_guint8(tvb, pos),
+         "Silence: 0x%02X",
+         tvb_get_guint8(tvb, pos));
+   pos += length;
+   break;
+
+  case WLAN_RADIO_HDR_RATE:
+   length = tvb_get_guint8(tvb, pos++);
+   proto_tree_add_uint (hdr_tree, hf_rate, tvb, pos-2, 3,
+      tvb_get_guint8(tvb, pos));
+   pos += length;
+   break;
+
+  case WLAN_RADIO_HDR_TIMESTAMP:
+   length = tvb_get_guint8(tvb, pos++);
+   proto_tree_add_uint (hdr_tree, hf_time, tvb, pos-2, 6,
+     tvb_get_ntohl(tvb, pos));
+   pos += length;
+   break;
+
+  case WLAN_RADIO_HDR_MSG_TYPE:
+   length = tvb_get_guint8(tvb, pos++);
+   proto_tree_add_uint (hdr_tree, hf_status_msg_type, tvb, pos-2, 3,
+      tvb_get_guint8(tvb, pos));
+   pos += length;
+   break;
+
+  case WLAN_RADIO_HDR_CF:
+   length = tvb_get_guint8(tvb, pos++);
+   proto_tree_add_boolean (hdr_tree, hf_status_pcf, tvb, pos-2, 3,
+      tvb_get_guint8(tvb, pos));
+   pos += length;
+   break;
+
+  case WLAN_RADIO_HDR_UN_DECR:
+   length = tvb_get_guint8(tvb, pos++);
+   proto_tree_add_boolean (hdr_tree, hf_status_undecrypted, tvb, pos-2, 3,
+      tvb_get_guint8(tvb, pos));
+   encr = tvb_get_guint8(tvb, pos);
+   pos += length;
+   break;
+
+  case WLAN_RADIO_HDR_FCS_ERR:
+   length = tvb_get_guint8(tvb, pos++);
+   proto_tree_add_boolean (hdr_tree, hf_status_fcs_error, tvb, pos-2, 3,
+      tvb_get_guint8(tvb, pos));
+   fcs_err = tvb_get_guint8(tvb, pos);
+   pos += length;
+   break;
+  }
+ }
+}

 /*
************************************************************************* */
 /*                          Dissect 802.11 frame
*/
@@ -1165,52 +1285,44 @@
   gboolean save_fragmented;
   tvbuff_t *volatile next_tvb;
   guint32 addr_type;
-  volatile gboolean is_802_2;
+  volatile gboolean is_802_2;
+ guint16 pos;

   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);
-  if (fixed_length_header)
-    hdr_len = DATA_LONG_HDR_LEN;
-  else
-    hdr_len = find_header_length (fcf);
-  frame_type_subtype = COMPOSE_FRAME_TYPE(fcf);
-
-  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)"));
-
-  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);
+
+      if (has_radio_information) {
+    pos = add_radio_info(tvb, pinfo, tree);
+    tvb = tvb_new_subset(tvb, pos, -1,tvb_reported_length_remaining(tvb,
pos));
       }
+  }
+
+  fcf = tvb_get_letohs (tvb, 0);
+  if (fixed_length_header)
+    hdr_len = DATA_LONG_HDR_LEN;
+  else
+    hdr_len = find_header_length (fcf);
+  frame_type_subtype = COMPOSE_FRAME_TYPE(fcf);
+
+  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)"));
+
+  flags = COOK_FLAGS (fcf);
+  more_frags = HAVE_FRAGMENTS (flags);
+
+ 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,
@@ -1952,18 +2064,6 @@
   };

   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 }},
@@ -2214,7 +2314,72 @@

   };

-  static gint *tree_array[] = {
+ static const value_string msg_type[] = {
+    {0,     "Normal"},
+    {1,   "RFC1042 encoded"},
+    {2,     "Bridge-tunnel encoded"},
+    {4,     "802.11 management frame"},
+    {0,     NULL}
+  };
+
+  static const true_false_string pcf_flag = {
+    "CF: Frame received during CF period",
+    "Not CF"
+  };
+
+  static const true_false_string undecr_flag = {
+    "Encrypted frame could not be decrypted",
+    "Unencrypted"
+  };
+
+  static const true_false_string fcs_err_flag = {
+    "FCS error, frame is corrupted",
+    "Frame is valid"
+  };
+
+  static const value_string rates[] = {
+    {0x0A, "1 Mbit/s"},
+    {0x14, "2 Mbit/s"},
+    {0x37, "5.5 Mbit/s"},
+    {0x6E, "11 Mbit/s"},
+    {0, NULL}
+  };
+
+ static hf_register_info rf[] = {
+  { &hf_status_field, {
+   "Status", "wlan_radio.status", FT_UINT16, BASE_HEX,
+    NULL, 0, "Status", HFILL }},
+  { &hf_status_msg_type, {
+   "Type", "wlan_radio.status.msg_type", FT_UINT8, BASE_HEX,
+   VALS(msg_type), 0, "Message type", HFILL }},
+  { &hf_status_mac_port, {
+   "Port", "wlan_radio.status.mac_port", FT_UINT8, BASE_DEC,
+   NULL, 0, "MAC port", HFILL }},
+  { &hf_status_pcf, {
+   "PCF", "wlan_radio.status.pcf", FT_BOOLEAN, BASE_HEX,
+   VALS (&pcf_flag), 0, "Point Coordination Function", HFILL }},
+  { &hf_status_undecrypted, {
+   "Undecrypted", "wlan_radio.status.undecrypted", FT_BOOLEAN, BASE_HEX,
+   VALS (&undecr_flag), 0, "Undecrypted", HFILL }},
+  { &hf_status_fcs_error, {
+   "FCS", "wlan_radio.status.fcs_err", FT_BOOLEAN, BASE_HEX,
+   VALS (&fcs_err_flag), 0, "Frame check sequence", HFILL }},
+  { &hf_time, {
+   "Time", "wlan_radio.time", FT_UINT32, BASE_HEX,
+   NULL, 0, "Time", HFILL }},
+  { &hf_silence, {
+   "Silence", "wlan_radio.silence", FT_UINT8, BASE_HEX,
+   NULL, 0, "Silence", HFILL }},
+  { &hf_signal, {
+   "Signal", "wlan_radio.signal", FT_UINT8, BASE_HEX,
+   NULL, 0, "Signal", HFILL }},
+  { &hf_rate, {
+   "Rate", "wlan_radio.rate", FT_UINT8, BASE_HEX,
+   VALS(rates), 0, "Rate", HFILL }}
+  };
+
+  static gint *tree_array[] = {
+  &ett_80211_radio,
     &ett_80211,
     &ett_fc_tree,
     &ett_proto_flags,
@@ -2228,6 +2393,8 @@
   };
   module_t *wlan_module;

+  proto_wlan_radio = proto_register_protocol ("IEEE 802.11 wireless LAN
Radio",
+     "IEEE 802.11 Radio", "wlan_radio");
   proto_wlan = proto_register_protocol ("IEEE 802.11 wireless LAN",
      "IEEE 802.11", "wlan");
   proto_register_field_array (proto_wlan, hf, array_length (hf));
@@ -2235,8 +2402,10 @@
      "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));
+ proto_register_field_array(proto_wlan_radio, rf, array_length(rf));

   register_dissector("wlan", dissect_ieee80211, proto_wlan);
+  register_dissector("wlan_radio", dissect_ieee80211_radio, proto_wlan);
   register_dissector("wlan_fixed", dissect_ieee80211_fixed, proto_wlan);
   register_init_routine(wlan_defragment_init);