As Sam Leffler notes, the radiotap header isn't BSD-only, it's also used
[obnox/wireshark/wip.git] / epan / dissectors / packet-radiotap.c
1 /*
2  *  packet-radiotap.c
3  *      Decode packets with a Radiotap header
4  *
5  * $Id$
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copied from README.developer
12  *
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.
17  *
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.
22  *
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.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <glib.h>
33 #include <string.h>
34
35 #include <epan/packet.h>
36 #include "packet-ieee80211.h"
37 #include "packet-radiotap.h"
38
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.
44                                  */
45     guint8      it_pad;
46     guint16     it_len;         /* length of the whole
47                                  * header in bytes, including
48                                  * it_version, it_pad,
49                                  * it_len, and data fields.
50                                  */
51     guint32   it_present;       /* A bitmap telling which
52                                  * fields are present. Set bit 31
53                                  * (0x80000000) to extend the
54                                  * bitmap by another 32 bits.
55                                  * Additional extensions are made
56                                  * by setting bit 31.
57                                  */
58 };
59
60 enum ieee80211_radiotap_type {
61     IEEE80211_RADIOTAP_TSFT = 0,
62     IEEE80211_RADIOTAP_FLAGS = 1,
63     IEEE80211_RADIOTAP_RATE = 2,
64     IEEE80211_RADIOTAP_CHANNEL = 3,
65     IEEE80211_RADIOTAP_FHSS = 4,
66     IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
67     IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
68     IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
69     IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
70     IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
71     IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
72     IEEE80211_RADIOTAP_ANTENNA = 11,
73     IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
74     IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
75     IEEE80211_RADIOTAP_EXT = 31
76 };
77
78 /* Channel flags. */
79 #define IEEE80211_CHAN_TURBO    0x0010  /* Turbo channel */
80 #define IEEE80211_CHAN_CCK      0x0020  /* CCK channel */
81 #define IEEE80211_CHAN_OFDM     0x0040  /* OFDM channel */
82 #define IEEE80211_CHAN_2GHZ     0x0080  /* 2 GHz spectrum channel. */
83 #define IEEE80211_CHAN_5GHZ     0x0100  /* 5 GHz spectrum channel */
84 #define IEEE80211_CHAN_PASSIVE  0x0200  /* Only passive scan allowed */
85 #define IEEE80211_CHAN_DYN      0x0400  /* Dynamic CCK-OFDM channel */
86 #define IEEE80211_CHAN_GFSK     0x0800  /* GFSK channel (FHSS PHY) */
87
88 /*
89  * Useful combinations of channel characteristics.
90  */
91 #define IEEE80211_CHAN_FHSS \
92         (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_GFSK)
93 #define IEEE80211_CHAN_A \
94         (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM)
95 #define IEEE80211_CHAN_B \
96         (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK)
97 #define IEEE80211_CHAN_PUREG \
98         (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM)
99 #define IEEE80211_CHAN_G \
100         (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
101 #define IEEE80211_CHAN_T \
102         (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO)
103 #define IEEE80211_CHAN_108G \
104         (IEEE80211_CHAN_G | IEEE80211_CHAN_TURBO)
105 #define IEEE80211_CHAN_108PUREG \
106         (IEEE80211_CHAN_PUREG | IEEE80211_CHAN_TURBO)
107
108 /* For IEEE80211_RADIOTAP_FLAGS */
109 #define IEEE80211_RADIOTAP_F_CFP        0x01    /* sent/received
110                                                  * during CFP
111                                                  */
112 #define IEEE80211_RADIOTAP_F_SHORTPRE   0x02    /* sent/received
113                                                  * with short
114                                                  * preamble
115                                                  */
116 #define IEEE80211_RADIOTAP_F_WEP        0x04    /* sent/received
117                                                  * with WEP encryption
118                                                  */
119 #define IEEE80211_RADIOTAP_F_FRAG       0x08    /* sent/received
120                                                  * with fragmentation
121                                                  */
122
123 /* protocol */
124 static int proto_radiotap = -1;
125
126 static int hf_radiotap_version = -1;
127 static int hf_radiotap_length = -1;
128 static int hf_radiotap_mactime = -1;
129 static int hf_radiotap_channel_frequency = -1;
130 static int hf_radiotap_channel_flags = -1;
131 static int hf_radiotap_datarate = -1;
132 static int hf_radiotap_antenna = -1;
133 static int hf_radiotap_antsignal = -1;
134 static int hf_radiotap_antnoise = -1;
135 static int hf_radiotap_txpower = -1;
136 static int hf_radiotap_preamble = -1;
137
138 static gint ett_radiotap = -1;
139
140 static dissector_handle_t ieee80211_handle;
141
142 static void
143 dissect_radiotap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
144
145 void
146 capture_radiotap(const guchar *pd, int offset, int len, packet_counts *ld)
147 {
148     const struct ieee80211_radiotap_header *hdr;
149
150     if(!BYTES_ARE_IN_FRAME(offset, len, (int)sizeof(*hdr))) {
151         ld->other ++;
152         return;
153     }
154     hdr = (const struct ieee80211_radiotap_header *)pd;
155     if(!BYTES_ARE_IN_FRAME(offset, len, hdr->it_len)) {
156         ld->other ++;
157         return;
158     }
159
160     /* 802.11 header follows */
161     capture_ieee80211(pd, offset + hdr->it_len, len, ld);
162 }
163
164 void
165 proto_register_radiotap(void)
166 {
167   static const value_string phy_type[] = {
168     { 0, "Unknown" },
169     { IEEE80211_CHAN_A,         "802.11a" },
170     { IEEE80211_CHAN_B,         "802.11b" },
171     { IEEE80211_CHAN_PUREG,     "802.11g (pure-g)" },
172     { IEEE80211_CHAN_G,         "802.11g" },
173     { IEEE80211_CHAN_T,         "802.11a (turbo)" },
174     { IEEE80211_CHAN_108PUREG,  "802.11g (pure-g, turbo)" },
175     { IEEE80211_CHAN_108G,      "802.11g (turbo)" },
176     { IEEE80211_CHAN_FHSS,      "FHSS" },
177     { 0, NULL },
178   };
179
180   static const value_string preamble_type[] = {
181     { 0, "Long" },
182     { 1, "Short" },
183     { 0, NULL },
184   };
185
186   static hf_register_info hf[] = {
187     { &hf_radiotap_version,
188       { "Header revision", "radiotap.version",
189         FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL } },
190     { &hf_radiotap_length,
191        { "Header length", "radiotap.length",
192          FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL } },
193
194     { &hf_radiotap_preamble,
195       { "Preamble", "radiotap.flags.preamble",
196         FT_UINT32, BASE_DEC, VALS(preamble_type), 0x0, "", HFILL } },
197
198     { &hf_radiotap_mactime,
199        { "MAC timestamp", "radiotap.mactime",
200          FT_UINT64, BASE_DEC, NULL, 0x0, "", HFILL } },
201     { &hf_radiotap_channel_frequency,
202       { "Channel frequency", "radiotap.channel.freq",
203         FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL } },
204     { &hf_radiotap_channel_flags,
205       { "Channel type", "radiotap.channel.flags",
206         FT_UINT32, BASE_HEX, VALS(phy_type), 0x0, "", HFILL } },
207     { &hf_radiotap_datarate,
208       { "Data rate", "radiotap.datarate",
209         FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL } },
210     { &hf_radiotap_antenna,
211       { "Antenna", "radiotap.antenna",
212         FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL } },
213     { &hf_radiotap_antsignal,
214       { "SSI Signal", "radiotap.antsignal",
215         FT_INT32, BASE_DEC, NULL, 0x0, "", HFILL } },
216     { &hf_radiotap_antnoise,
217       { "SSI Noise", "radiotap.antnoise",
218         FT_INT32, BASE_DEC, NULL, 0x0, "", HFILL } },
219     { &hf_radiotap_txpower,
220       { "Transmit power", "radiotap.txpower",
221         FT_INT32, BASE_DEC, NULL, 0x0, "", HFILL } },
222   };
223   static gint *ett[] = {
224     &ett_radiotap
225   };
226
227   proto_radiotap = proto_register_protocol("IEEE 802.11 Radiotap Capture header", "802.11 Radiotap", "radiotap");
228   proto_register_field_array(proto_radiotap, hf, array_length(hf));
229   proto_register_subtree_array(ett, array_length(ett));
230   register_dissector("radiotap", dissect_radiotap, proto_radiotap);
231
232 }
233
234 /*
235  * Convert MHz frequency to IEEE channel number.
236  */
237 static int
238 ieee80211_mhz2ieee(int freq, int flags)
239 {
240     if (flags & IEEE80211_CHAN_2GHZ) {          /* 2GHz band */
241         if (freq == 2484)
242             return 14;
243         if (freq < 2484)
244             return (freq - 2407) / 5;
245         else
246             return 15 + ((freq - 2512) / 20);
247     } else if (flags & IEEE80211_CHAN_5GHZ) {   /* 5Ghz band */
248         return (freq - 5000) / 5;
249     } else {                                    /* either, guess */
250         if (freq == 2484)
251             return 14;
252         if (freq < 2484)
253             return (freq - 2407) / 5;
254         if (freq < 5000)
255             return 15 + ((freq - 2512) / 20);
256         return (freq - 5000) / 5;
257     }
258 }
259
260 static void
261 dissect_radiotap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
262 {
263 #define BITNO_32(x) (((x) >> 16) ? 16 + BITNO_16((x) >> 16) : BITNO_16((x)))
264 #define BITNO_16(x) (((x) >> 8) ? 8 + BITNO_8((x) >> 8) : BITNO_8((x)))
265 #define BITNO_8(x) (((x) >> 4) ? 4 + BITNO_4((x) >> 4) : BITNO_4((x)))
266 #define BITNO_4(x) (((x) >> 2) ? 2 + BITNO_2((x) >> 2) : BITNO_2((x)))
267 #define BITNO_2(x) (((x) & 2) ? 1 : 0)
268 #define BIT(n)  (1 << n)
269     proto_tree *radiotap_tree = NULL;
270     proto_item *ti;
271     int offset;
272     guint32 version;
273     guint32 length;
274     guint32 rate, freq, flags;
275     guint32 present, next_present;
276     int bit;
277
278     if(check_col(pinfo->cinfo, COL_PROTOCOL))
279         col_set_str(pinfo->cinfo, COL_PROTOCOL, "WLAN");
280     if(check_col(pinfo->cinfo, COL_INFO))
281         col_clear(pinfo->cinfo, COL_INFO);
282     offset = 0;
283
284     version = tvb_get_guint8(tvb, offset);
285     length = tvb_get_letohs(tvb, offset+2);
286     present = tvb_get_letohl(tvb, offset+4);
287     offset+=sizeof(struct ieee80211_radiotap_header);
288
289     if(check_col(pinfo->cinfo, COL_INFO))
290         col_add_fstr(pinfo->cinfo, COL_INFO, "Radiotap Capture v%x, Length %d",
291                 version, length);
292
293     /* Dissect the packet */
294     if (tree) {
295         ti = proto_tree_add_protocol_format(tree, proto_radiotap,
296               tvb, 0, length, "Radiotap Header");
297         radiotap_tree = proto_item_add_subtree(ti, ett_radiotap);
298     }
299
300     for (; present; present = next_present) {
301         /* clear the least significant bit that is set */
302         next_present = present & (present - 1);
303
304         /* extract the least significant bit that is set */
305         bit = BITNO_32(present ^ next_present);
306
307         switch (bit) {
308         case IEEE80211_RADIOTAP_FLAGS:
309             if (tree) {
310                 proto_tree_add_uint(radiotap_tree, hf_radiotap_preamble,
311                         tvb, 0, 0, (tvb_get_guint8(tvb, offset) &
312                                 IEEE80211_RADIOTAP_F_SHORTPRE) != 0);
313             }
314             offset++;
315             /* XXX CFP, WEP, FRAG */
316 #if 0
317       capability = tvb_get_letohs (tvb, offset);
318
319       cap_item = proto_tree_add_uint_format (tree, ff_capture,
320                                              tvb, offset, 2,
321                                              capability,
322                                              "Capability Information: 0x%04X",
323                                              capability);
324       cap_tree = proto_item_add_subtree (cap_item, ett_cap_tree);
325       proto_tree_add_boolean (cap_tree, ff_cf_ess, tvb, offset, 2,
326                               capability);
327       proto_tree_add_boolean (cap_tree, ff_cf_ibss, tvb, offset, 2,
328                               capability);
329       if (ESS_SET (capability) != 0)    /* This is an AP */
330         proto_tree_add_uint (cap_tree, ff_cf_ap_poll, tvb, offset, 2,
331                              capability);
332
333       else                      /* This is a STA */
334         proto_tree_add_uint (cap_tree, ff_cf_sta_poll, tvb, offset, 2,
335                              capability);
336       proto_tree_add_boolean (cap_tree, ff_cf_privacy, tvb, offset, 2,
337                               capability);
338       proto_tree_add_boolean (cap_tree, ff_cf_preamble, tvb, offset, 2,
339                               capability);
340       proto_tree_add_boolean (cap_tree, ff_cf_pbcc, tvb, offset, 2,
341                               capability);
342       proto_tree_add_boolean (cap_tree, ff_cf_agility, tvb, offset, 2,
343                               capability);
344       proto_tree_add_boolean (cap_tree, ff_short_slot_time, tvb, offset, 2,
345                               capability);
346       proto_tree_add_boolean (cap_tree, ff_dsss_ofdm, tvb, offset, 2,
347                               capability);
348 #endif
349             break;
350         case IEEE80211_RADIOTAP_RATE:
351             rate = tvb_get_guint8(tvb, offset) & 0x7f;
352             if (check_col(pinfo->cinfo, COL_TX_RATE)) {
353                 col_add_fstr(pinfo->cinfo, COL_TX_RATE, "%d.%d",
354                     rate / 2, rate & 1 ? 5 : 0);
355             }
356             if (tree) {
357                 proto_tree_add_uint_format(radiotap_tree, hf_radiotap_datarate,
358                         tvb, offset, 1, tvb_get_guint8(tvb, offset), 
359                         "Data Rate: %d.%d Mb/s", rate / 2, rate & 1 ? 5 : 0);
360             }
361             offset++;
362             break;
363         case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
364         case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
365             /* XXX distinguish units */
366             if (check_col(pinfo->cinfo, COL_RSSI)) {
367                 col_add_fstr(pinfo->cinfo, COL_RSSI, "%d",
368                     tvb_get_guint8(tvb, offset));
369             }
370             if (tree) {
371                 proto_tree_add_int(radiotap_tree, hf_radiotap_antsignal,
372                                    tvb, offset, 1, tvb_get_guint8(tvb, offset));
373             }
374             offset++;
375             break;
376         case IEEE80211_RADIOTAP_DBM_ANTNOISE:
377         case IEEE80211_RADIOTAP_DB_ANTNOISE:
378             /* XXX distinguish units */
379             if (tree) {
380                 proto_tree_add_int(radiotap_tree, hf_radiotap_antnoise,
381                                    tvb, offset, 1, tvb_get_guint8(tvb, offset));
382             }
383             offset++;
384             break;
385         case IEEE80211_RADIOTAP_ANTENNA:
386             if (tree) {
387                 proto_tree_add_uint(radiotap_tree, hf_radiotap_antenna,
388                                    tvb, offset, 1, tvb_get_guint8(tvb, offset));
389             }
390             offset++;
391             break;
392         case IEEE80211_RADIOTAP_DBM_TX_POWER:
393             if (tree) {
394                 proto_tree_add_int(radiotap_tree, hf_radiotap_txpower,
395                                    tvb, offset, 1, tvb_get_guint8(tvb, offset));
396             }
397             offset++;
398             break;
399         case IEEE80211_RADIOTAP_CHANNEL:
400             if (tree) {
401                 freq = tvb_get_letohs(tvb, offset);
402                 flags = tvb_get_letohs(tvb, offset+2);
403                 proto_tree_add_uint_format(radiotap_tree, hf_radiotap_channel_frequency,
404                         tvb, offset, 2, freq,
405                         "Channel: %u (chan %u)", freq, ieee80211_mhz2ieee(freq, flags));
406                 proto_tree_add_uint(radiotap_tree, hf_radiotap_channel_flags,
407                         tvb, offset+2, 2, flags);
408             }
409             offset+=4;
410             break;
411         case IEEE80211_RADIOTAP_FHSS:
412         case IEEE80211_RADIOTAP_LOCK_QUALITY:
413         case IEEE80211_RADIOTAP_TX_ATTENUATION:
414         case IEEE80211_RADIOTAP_DB_TX_ATTENUATION:
415 #if 0
416             tvb_get_letohs(tvb, offset);
417 #endif
418             offset+=2;
419             break;
420         case IEEE80211_RADIOTAP_TSFT:
421             if (tree) {
422                 proto_tree_add_item(radiotap_tree, hf_radiotap_mactime,
423                                     tvb, offset, 8, FALSE);
424             }
425             offset+=8;
426             break;
427         default:
428             /*
429              * This indicates a field whose size we do not
430              * know, so we cannot proceed.
431              */
432             next_present = 0;
433             continue;
434         }
435     }
436
437     /* dissect the 802.11 header next */
438     call_dissector(ieee80211_handle,
439         tvb_new_subset(tvb, length, -1, -1), pinfo, tree);
440 #undef BITNO_32
441 #undef BITNO_16
442 #undef BITNO_8
443 #undef BITNO_4
444 #undef BITNO_2
445 #undef BIT
446 }
447
448 void
449 proto_reg_handoff_radiotap(void)
450 {
451     dissector_handle_t radiotap_handle;
452
453     /* handle for 802.11 dissector */
454     ieee80211_handle = find_dissector("wlan");
455
456     radiotap_handle = create_dissector_handle(dissect_radiotap, proto_radiotap);
457
458     dissector_add("wtap_encap", WTAP_ENCAP_IEEE_802_11_WLAN_RADIOTAP, radiotap_handle);
459 }