3 * Decode packets with a Radiotap header
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@ethereal.com>
9 * Copyright 1998 Gerald Combs
11 * Copied from README.developer
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
35 #include <epan/packet.h>
36 #include "packet-ieee80211.h"
37 #include "packet-radiotap.h"
39 struct ieee80211_radiotap_header {
40 guint8 it_version; /* Version 0. Only increases
41 * for drastic changes,
42 * introduction of compatible
43 * new fields does not count.
46 guint16 it_len; /* length of the whole
47 * header in bytes, including
49 * it_len, and data fields.
52 guint32 it_present[MAX_PRESENT]; /* A bitmap telling which
53 * fields are present. Set bit 31
54 * (0x80000000) to extend the
55 * bitmap by another 32 bits.
56 * Additional extensions are made
61 enum ieee80211_radiotap_type {
62 IEEE80211_RADIOTAP_TSFT = 0,
63 IEEE80211_RADIOTAP_FLAGS = 1,
64 IEEE80211_RADIOTAP_RATE = 2,
65 IEEE80211_RADIOTAP_CHANNEL = 3,
66 IEEE80211_RADIOTAP_FHSS = 4,
67 IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
68 IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
69 IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
70 IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
71 IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
72 IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
73 IEEE80211_RADIOTAP_ANTENNA = 11,
74 IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
75 IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
76 IEEE80211_RADIOTAP_FCS = 14,
77 IEEE80211_RADIOTAP_EXT = 31
81 #define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */
82 #define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */
83 #define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */
84 #define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */
85 #define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */
86 #define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */
87 #define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */
88 #define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */
91 * Useful combinations of channel characteristics.
93 #define IEEE80211_CHAN_FHSS \
94 (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_GFSK)
95 #define IEEE80211_CHAN_A \
96 (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM)
97 #define IEEE80211_CHAN_B \
98 (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK)
99 #define IEEE80211_CHAN_PUREG \
100 (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM)
101 #define IEEE80211_CHAN_G \
102 (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
103 #define IEEE80211_CHAN_T \
104 (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO)
105 #define IEEE80211_CHAN_108G \
106 (IEEE80211_CHAN_G | IEEE80211_CHAN_TURBO)
107 #define IEEE80211_CHAN_108PUREG \
108 (IEEE80211_CHAN_PUREG | IEEE80211_CHAN_TURBO)
110 /* For IEEE80211_RADIOTAP_FLAGS */
111 #define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received
114 #define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received
118 #define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received
119 * with WEP encryption
121 #define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received
126 static int proto_radiotap = -1;
128 static int hf_radiotap_version = -1;
129 static int hf_radiotap_pad = -1;
130 static int hf_radiotap_length = -1;
131 static int hf_radiotap_present1 = -1;
132 static int hf_radiotap_mactime = -1;
133 static int hf_radiotap_channel_frequency = -1;
134 static int hf_radiotap_channel_flags = -1;
135 static int hf_radiotap_datarate = -1;
136 static int hf_radiotap_antenna = -1;
137 static int hf_radiotap_antsignal = -1;
138 static int hf_radiotap_antnoise = -1;
139 static int hf_radiotap_txpower = -1;
140 static int hf_radiotap_preamble = -1;
142 static gint ett_radiotap = -1;
143 static gint ett_radiotap_present = -1;
145 static dissector_handle_t ieee80211_handle;
148 dissect_radiotap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
151 capture_radiotap(const guchar *pd, int offset, int len, packet_counts *ld)
153 const struct ieee80211_radiotap_header *hdr;
155 if(!BYTES_ARE_IN_FRAME(offset, len, (int)sizeof(*hdr))) {
159 hdr = (const struct ieee80211_radiotap_header *)pd;
160 if(!BYTES_ARE_IN_FRAME(offset, len, hdr->it_len)) {
165 /* 802.11 header follows */
166 capture_ieee80211(pd, offset + hdr->it_len, len, ld);
170 proto_register_radiotap(void)
172 static const value_string phy_type[] = {
174 { IEEE80211_CHAN_A, "802.11a" },
175 { IEEE80211_CHAN_B, "802.11b" },
176 { IEEE80211_CHAN_PUREG, "802.11g (pure-g)" },
177 { IEEE80211_CHAN_G, "802.11g" },
178 { IEEE80211_CHAN_T, "802.11a (turbo)" },
179 { IEEE80211_CHAN_108PUREG, "802.11g (pure-g, turbo)" },
180 { IEEE80211_CHAN_108G, "802.11g (turbo)" },
181 { IEEE80211_CHAN_FHSS, "FHSS" },
185 static const value_string preamble_type[] = {
191 static hf_register_info hf[] = {
192 { &hf_radiotap_version,
193 { "Header revision", "radiotap.version",
194 FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL } },
196 { "Header pad", "radiotap.pad",
197 FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL } },
198 { &hf_radiotap_length,
199 { "Header length", "radiotap.length",
200 FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL } },
201 { &hf_radiotap_present1,
202 { "Present elements", "radiotap.present",
203 FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL } },
205 { &hf_radiotap_preamble,
206 { "Preamble", "radiotap.flags.preamble",
207 FT_UINT32, BASE_DEC, VALS(preamble_type), 0x0, "", HFILL } },
209 { &hf_radiotap_mactime,
210 { "MAC timestamp", "radiotap.mactime",
211 FT_UINT64, BASE_DEC, NULL, 0x0, "", HFILL } },
212 { &hf_radiotap_channel_frequency,
213 { "Channel frequency", "radiotap.channel.freq",
214 FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL } },
215 { &hf_radiotap_channel_flags,
216 { "Channel type", "radiotap.channel.flags",
217 FT_UINT16, BASE_HEX, VALS(phy_type), 0x0, "", HFILL } },
218 { &hf_radiotap_datarate,
219 { "Data rate", "radiotap.datarate",
220 FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL } },
221 { &hf_radiotap_antenna,
222 { "Antenna", "radiotap.antenna",
223 FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL } },
224 { &hf_radiotap_antsignal,
225 { "SSI Signal", "radiotap.antsignal",
226 FT_INT32, BASE_DEC, NULL, 0x0, "", HFILL } },
227 { &hf_radiotap_antnoise,
228 { "SSI Noise", "radiotap.antnoise",
229 FT_INT32, BASE_DEC, NULL, 0x0, "", HFILL } },
230 { &hf_radiotap_txpower,
231 { "Transmit power", "radiotap.txpower",
232 FT_INT32, BASE_DEC, NULL, 0x0, "", HFILL } },
234 static gint *ett[] = {
236 &ett_radiotap_present
239 proto_radiotap = proto_register_protocol("IEEE 802.11 Radiotap Capture header", "802.11 Radiotap", "radiotap");
240 proto_register_field_array(proto_radiotap, hf, array_length(hf));
241 proto_register_subtree_array(ett, array_length(ett));
242 register_dissector("radiotap", dissect_radiotap, proto_radiotap);
247 * Convert MHz frequency to IEEE channel number.
250 ieee80211_mhz2ieee(int freq, int flags)
252 if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */
256 return (freq - 2407) / 5;
258 return 15 + ((freq - 2512) / 20);
259 } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5Ghz band */
260 return (freq - 5000) / 5;
261 } else { /* either, guess */
265 return (freq - 2407) / 5;
267 return 15 + ((freq - 2512) / 20);
268 return (freq - 5000) / 5;
273 dissect_radiotap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
275 #define BITNO_32(x) (((x) >> 16) ? 16 + BITNO_16((x) >> 16) : BITNO_16((x)))
276 #define BITNO_16(x) (((x) >> 8) ? 8 + BITNO_8((x) >> 8) : BITNO_8((x)))
277 #define BITNO_8(x) (((x) >> 4) ? 4 + BITNO_4((x) >> 4) : BITNO_4((x)))
278 #define BITNO_4(x) (((x) >> 2) ? 2 + BITNO_2((x) >> 2) : BITNO_2((x)))
279 #define BITNO_2(x) (((x) & 2) ? 1 : 0)
280 #define BIT(n) (1 << n)
281 proto_tree *radiotap_tree = NULL;
282 proto_tree *pt, *present_tree;
285 guint32 version, pad;
287 guint32 rate, freq, flags;
288 guint32 present, next_present;
291 if(check_col(pinfo->cinfo, COL_PROTOCOL))
292 col_set_str(pinfo->cinfo, COL_PROTOCOL, "WLAN");
293 if(check_col(pinfo->cinfo, COL_INFO))
294 col_clear(pinfo->cinfo, COL_INFO);
297 version = tvb_get_guint8(tvb, offset);
298 pad = tvb_get_guint8(tvb, offset+1);
299 length = tvb_get_letohs(tvb, offset+2);
300 present = tvb_get_letohl(tvb, offset+4);
302 if(check_col(pinfo->cinfo, COL_INFO))
303 col_add_fstr(pinfo->cinfo, COL_INFO, "Radiotap Capture v%u, Length %u",
306 /* Dissect the packet */
308 ti = proto_tree_add_protocol_format(tree, proto_radiotap,
309 tvb, 0, length, "Radiotap Header v%u, Length %u", version, length);
310 radiotap_tree = proto_item_add_subtree(ti, ett_radiotap);
311 proto_tree_add_uint(radiotap_tree, hf_radiotap_version,
312 tvb, offset, 1, version);
313 proto_tree_add_uint(radiotap_tree, hf_radiotap_pad,
314 tvb, offset + 1, 1, pad);
315 proto_tree_add_uint(radiotap_tree, hf_radiotap_length,
316 tvb, offset + 2, 2, length);
317 pt = proto_tree_add_uint_format(radiotap_tree, hf_radiotap_present1,
318 tvb, offset + 4, 4, present, "Present flags (0x%08x)", present);
319 present_tree = proto_item_add_subtree(pt, ett_radiotap_present);
322 * FIXME: This only works if there is exactly 1 it_present
323 * field in the header
325 offset += sizeof(struct ieee80211_radiotap_header);
327 for (; present; present = next_present) {
328 /* clear the least significant bit that is set */
329 next_present = present & (present - 1);
331 /* extract the least significant bit that is set */
332 bit = BITNO_32(present ^ next_present);
335 case IEEE80211_RADIOTAP_FLAGS:
337 proto_tree_add_uint(radiotap_tree, hf_radiotap_preamble,
338 tvb, 0, 0, (tvb_get_guint8(tvb, offset) &
339 IEEE80211_RADIOTAP_F_SHORTPRE) != 0);
342 /* XXX CFP, WEP, FRAG */
344 capability = tvb_get_letohs (tvb, offset);
346 cap_item = proto_tree_add_uint_format (tree, ff_capture,
349 "Capability Information: 0x%04X",
351 cap_tree = proto_item_add_subtree (cap_item, ett_cap_tree);
352 proto_tree_add_boolean (cap_tree, ff_cf_ess, tvb, offset, 2,
354 proto_tree_add_boolean (cap_tree, ff_cf_ibss, tvb, offset, 2,
356 if (ESS_SET (capability) != 0) /* This is an AP */
357 proto_tree_add_uint (cap_tree, ff_cf_ap_poll, tvb, offset, 2,
360 else /* This is a STA */
361 proto_tree_add_uint (cap_tree, ff_cf_sta_poll, tvb, offset, 2,
363 proto_tree_add_boolean (cap_tree, ff_cf_privacy, tvb, offset, 2,
365 proto_tree_add_boolean (cap_tree, ff_cf_preamble, tvb, offset, 2,
367 proto_tree_add_boolean (cap_tree, ff_cf_pbcc, tvb, offset, 2,
369 proto_tree_add_boolean (cap_tree, ff_cf_agility, tvb, offset, 2,
371 proto_tree_add_boolean (cap_tree, ff_short_slot_time, tvb, offset, 2,
373 proto_tree_add_boolean (cap_tree, ff_dsss_ofdm, tvb, offset, 2,
377 case IEEE80211_RADIOTAP_RATE:
378 rate = tvb_get_guint8(tvb, offset) & 0x7f;
379 if (check_col(pinfo->cinfo, COL_TX_RATE)) {
380 col_add_fstr(pinfo->cinfo, COL_TX_RATE, "%d.%d",
381 rate / 2, rate & 1 ? 5 : 0);
384 proto_tree_add_uint_format(radiotap_tree, hf_radiotap_datarate,
385 tvb, offset, 1, tvb_get_guint8(tvb, offset),
386 "Data Rate: %d.%d Mb/s", rate / 2, rate & 1 ? 5 : 0);
390 case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
391 case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
392 /* XXX distinguish units */
393 if (check_col(pinfo->cinfo, COL_RSSI)) {
394 col_add_fstr(pinfo->cinfo, COL_RSSI, "%d",
395 tvb_get_guint8(tvb, offset));
398 proto_tree_add_int(radiotap_tree, hf_radiotap_antsignal,
399 tvb, offset, 1, (gint8) tvb_get_guint8(tvb, offset));
403 case IEEE80211_RADIOTAP_DBM_ANTNOISE:
404 case IEEE80211_RADIOTAP_DB_ANTNOISE:
405 /* XXX distinguish units */
407 proto_tree_add_int(radiotap_tree, hf_radiotap_antnoise,
408 tvb, offset, 1, (gint8) tvb_get_guint8(tvb, offset));
412 case IEEE80211_RADIOTAP_ANTENNA:
414 proto_tree_add_uint(radiotap_tree, hf_radiotap_antenna,
415 tvb, offset, 1, tvb_get_guint8(tvb, offset));
419 case IEEE80211_RADIOTAP_DBM_TX_POWER:
421 proto_tree_add_int(radiotap_tree, hf_radiotap_txpower,
422 tvb, offset, 1, tvb_get_guint8(tvb, offset));
426 case IEEE80211_RADIOTAP_CHANNEL:
428 freq = tvb_get_letohs(tvb, offset);
429 flags = tvb_get_letohs(tvb, offset+2);
430 proto_tree_add_uint_format(radiotap_tree, hf_radiotap_channel_frequency,
431 tvb, offset, 2, freq,
432 "Channel: %u (chan %u)", freq, ieee80211_mhz2ieee(freq, flags));
433 proto_tree_add_uint(radiotap_tree, hf_radiotap_channel_flags,
434 tvb, offset+2, 2, flags);
438 case IEEE80211_RADIOTAP_FHSS:
439 case IEEE80211_RADIOTAP_LOCK_QUALITY:
440 case IEEE80211_RADIOTAP_TX_ATTENUATION:
441 case IEEE80211_RADIOTAP_DB_TX_ATTENUATION:
443 tvb_get_letohs(tvb, offset);
447 case IEEE80211_RADIOTAP_TSFT:
449 proto_tree_add_item(radiotap_tree, hf_radiotap_mactime,
450 tvb, offset, 8, FALSE);
456 * This indicates a field whose size we do not
457 * know, so we cannot proceed.
464 /* dissect the 802.11 header next */
465 call_dissector(ieee80211_handle,
466 tvb_new_subset(tvb, length, -1, -1), pinfo, tree);
476 proto_reg_handoff_radiotap(void)
478 dissector_handle_t radiotap_handle;
480 /* handle for 802.11 dissector */
481 ieee80211_handle = find_dissector("wlan");
483 radiotap_handle = create_dissector_handle(dissect_radiotap, proto_radiotap);
485 dissector_add("wtap_encap", WTAP_ENCAP_IEEE_802_11_WLAN_RADIOTAP, radiotap_handle);