a91a2fb4fab5220e1ec1833cc0f23f74777cdc96
[metze/wireshark/wip.git] / epan / dissectors / packet-ieee80211-netmon.c
1 /*
2  *  packet-ieee80211-netmon.c
3  *       Decode packets with a Network Monitor 802.11 radio header
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 #include "config.h"
25
26 #include <epan/packet.h>
27
28 #include <wiretap/wtap.h>
29
30 #include <wsutil/frequency-utils.h>
31
32 void proto_register_netmon_802_11(void);
33 void proto_reg_handoff_netmon_802_11(void);
34
35 /* protocol */
36 static int proto_netmon_802_11 = -1;
37
38 #define MIN_HEADER_LEN  32
39
40 /* op_mode */
41 #define OP_MODE_STA     0x00000001      /* station mode */
42 #define OP_MODE_AP      0x00000002      /* AP mode */
43 #define OP_MODE_STA_EXT 0x00000004      /* extensible station mode */
44 #define OP_MODE_MON     0x80000000      /* monitor mode */
45
46 /* phy_type */
47 /*
48  * Augmented with phy types from
49  *
50  *    https://msdn.microsoft.com/en-us/library/windows/hardware/ff548741(v=vs.85).aspx
51  */
52 #define PHY_TYPE_UNKNOWN     0
53 #define PHY_TYPE_FHSS        1
54 #define PHY_TYPE_DSSS        2
55 #define PHY_TYPE_IR_BASEBAND 3
56 #define PHY_TYPE_OFDM        4 /* 802.11a */
57 #define PHY_TYPE_HR_DSSS     5 /* 802.11b */
58 #define PHY_TYPE_ERP         6 /* 802.11g */
59 #define PHY_TYPE_HT          7 /* 802.11n */
60 #define PHY_TYPE_VHT         8 /* 802.11ac */
61
62 static int hf_netmon_802_11_version = -1;
63 static int hf_netmon_802_11_length = -1;
64 static int hf_netmon_802_11_op_mode = -1;
65 static int hf_netmon_802_11_op_mode_sta = -1;
66 static int hf_netmon_802_11_op_mode_ap = -1;
67 static int hf_netmon_802_11_op_mode_sta_ext = -1;
68 static int hf_netmon_802_11_op_mode_mon = -1;
69 /* static int hf_netmon_802_11_flags = -1; */
70 static int hf_netmon_802_11_phy_type = -1;
71 static int hf_netmon_802_11_channel = -1;
72 static int hf_netmon_802_11_frequency = -1;
73 static int hf_netmon_802_11_rssi = -1;
74 static int hf_netmon_802_11_datarate = -1;
75 static int hf_netmon_802_11_timestamp = -1;
76
77 static gint ett_netmon_802_11 = -1;
78 static gint ett_netmon_802_11_op_mode = -1;
79
80 static dissector_handle_t ieee80211_radio_handle;
81
82 static int
83 dissect_netmon_802_11(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
84 {
85   struct ieee_802_11_phdr *phdr = (struct ieee_802_11_phdr *)data;
86   proto_tree *wlan_tree = NULL, *opmode_tree;
87   proto_item *ti;
88   tvbuff_t   *next_tvb;
89   int         offset;
90   guint8      version;
91   guint16     length;
92   guint32     phy_type;
93   guint32     flags;
94   guint32     channel;
95   gint        calc_channel;
96   gint32      rssi;
97   guint8      rate;
98
99   col_set_str(pinfo->cinfo, COL_PROTOCOL, "WLAN");
100   col_clear(pinfo->cinfo, COL_INFO);
101   offset = 0;
102
103   version = tvb_get_guint8(tvb, offset);
104   length = tvb_get_letohs(tvb, offset+1);
105   col_add_fstr(pinfo->cinfo, COL_INFO, "NetMon WLAN Capture v%u, Length %u",
106                version, length);
107   if (version != 2) {
108     /* XXX - complain */
109     goto skip;
110   }
111   if (length < MIN_HEADER_LEN) {
112     /* XXX - complain */
113     goto skip;
114   }
115
116   /* Dissect the packet */
117   ti = proto_tree_add_item(tree, proto_netmon_802_11, tvb, 0, length,
118                            ENC_NA);
119   wlan_tree = proto_item_add_subtree(ti, ett_netmon_802_11);
120
121   /*
122    * XXX - is this the NDIS_OBJECT_HEADER structure:
123    *
124    *    https://msdn.microsoft.com/en-us/library/windows/hardware/ff566588(v=vs.85).aspx
125    *
126    * at the beginning of a DOT11_EXTSTA_RECV_CONTEXT structure:
127    *
128    *    https://msdn.microsoft.com/en-us/library/windows/hardware/ff548626(v=vs.85).aspx
129    *
130    * If so, the byte at an offset of 0 would be the appropriate type for the
131    * structure following it, i.e. NDIS_OBJECT_TYPE_DEFAULT.
132    */
133   proto_tree_add_item(wlan_tree, hf_netmon_802_11_version, tvb, offset, 1,
134                       ENC_LITTLE_ENDIAN);
135   offset += 1;
136   proto_tree_add_item(wlan_tree, hf_netmon_802_11_length, tvb, offset, 2,
137                       ENC_LITTLE_ENDIAN);
138   offset += 2;
139
140   /*
141    * This isn't in the DOT11_EXTSTA_RECV_CONTEXT structure.
142    */
143   ti = proto_tree_add_item(wlan_tree, hf_netmon_802_11_op_mode, tvb, offset,
144                       4, ENC_LITTLE_ENDIAN);
145   opmode_tree = proto_item_add_subtree(ti, ett_netmon_802_11_op_mode);
146   proto_tree_add_item(opmode_tree, hf_netmon_802_11_op_mode_sta, tvb, offset,
147                       4, ENC_LITTLE_ENDIAN);
148   proto_tree_add_item(opmode_tree, hf_netmon_802_11_op_mode_ap, tvb, offset,
149                       4, ENC_LITTLE_ENDIAN);
150   proto_tree_add_item(opmode_tree, hf_netmon_802_11_op_mode_sta_ext, tvb,
151                       offset, 4, ENC_LITTLE_ENDIAN);
152   proto_tree_add_item(opmode_tree, hf_netmon_802_11_op_mode_mon, tvb, offset,
153                       4, ENC_LITTLE_ENDIAN);
154   offset += 4;
155
156   /*
157    * uReceiveFlags?
158    */
159   flags = tvb_get_letohl(tvb, offset);
160   offset += 4;
161   if (flags != 0xffffffff) {
162     /*
163      * uPhyId?
164      */
165     phy_type = tvb_get_letohl(tvb, offset);
166     switch (phy_type) {
167
168     case PHY_TYPE_UNKNOWN:
169         phdr->phy = PHDR_802_11_PHY_UNKNOWN;
170         break;
171
172     case PHY_TYPE_FHSS:
173         phdr->phy = PHDR_802_11_PHY_11_FHSS;
174         phdr->phy_info.info_11_fhss.presence_flags = 0;
175         break;
176
177     case PHY_TYPE_IR_BASEBAND:
178         phdr->phy = PHDR_802_11_PHY_11_IR;
179         break;
180
181     case PHY_TYPE_DSSS:
182         phdr->phy = PHDR_802_11_PHY_11_DSSS;
183         break;
184
185     case PHY_TYPE_HR_DSSS:
186         phdr->phy = PHDR_802_11_PHY_11B;
187         phdr->phy_info.info_11b.presence_flags = 0;
188         break;
189
190     case PHY_TYPE_OFDM:
191         phdr->phy = PHDR_802_11_PHY_11A;
192         phdr->phy_info.info_11a.presence_flags = 0;
193         break;
194
195     case PHY_TYPE_ERP:
196         phdr->phy = PHDR_802_11_PHY_11G;
197         phdr->phy_info.info_11g.presence_flags = 0;
198         break;
199
200     case PHY_TYPE_HT:
201         phdr->phy = PHDR_802_11_PHY_11N;
202         phdr->phy_info.info_11n.presence_flags = 0;
203         break;
204
205     case PHY_TYPE_VHT:
206         phdr->phy = PHDR_802_11_PHY_11AC;
207         phdr->phy_info.info_11ac.presence_flags = 0;
208         break;
209
210     default:
211         phdr->phy = PHDR_802_11_PHY_UNKNOWN;
212         break;
213     }
214     proto_tree_add_item(wlan_tree, hf_netmon_802_11_phy_type, tvb, offset, 4,
215                         ENC_LITTLE_ENDIAN);
216     offset += 4;
217
218     /*
219      * uChCenterFrequency?
220      */
221     channel = tvb_get_letohl(tvb, offset);
222     if (channel < 1000) {
223       if (channel == 0) {
224         proto_tree_add_uint_format_value(wlan_tree, hf_netmon_802_11_channel,
225                                          tvb, offset, 4, channel,
226                                          "Unknown");
227       } else {
228         guint frequency;
229
230         phdr->presence_flags |= PHDR_802_11_HAS_CHANNEL;
231         phdr->channel = channel;
232         proto_tree_add_uint(wlan_tree, hf_netmon_802_11_channel,
233                             tvb, offset, 4, channel);
234         switch (phdr->phy) {
235
236         case PHDR_802_11_PHY_11B:
237         case PHDR_802_11_PHY_11G:
238           /* 2.4 GHz channel */
239           frequency = ieee80211_chan_to_mhz(channel, TRUE);
240           break;
241
242         case PHDR_802_11_PHY_11A:
243           /* 5 GHz channel */
244           frequency = ieee80211_chan_to_mhz(channel, FALSE);
245           break;
246
247         default:
248           frequency = 0;
249           break;
250         }
251         if (frequency != 0) {
252           phdr->presence_flags |= PHDR_802_11_HAS_FREQUENCY;
253           phdr->frequency = frequency;
254         }
255       }
256     } else {
257       phdr->presence_flags |= PHDR_802_11_HAS_FREQUENCY;
258       phdr->frequency = channel;
259       proto_tree_add_uint_format_value(wlan_tree, hf_netmon_802_11_frequency,
260                                        tvb, offset, 4, channel,
261                                        "%u Mhz", channel);
262       calc_channel = ieee80211_mhz_to_chan(channel);
263       if (calc_channel != -1) {
264         phdr->presence_flags |= PHDR_802_11_HAS_CHANNEL;
265         phdr->channel = calc_channel;
266       }
267     }
268     offset += 4;
269
270     /*
271      * usNumberOfMPDUsReceived is missing.
272      */
273
274     /*
275      * lRSSI?
276      */
277     rssi = tvb_get_letohl(tvb, offset);
278     if (rssi == 0) {
279       proto_tree_add_int_format_value(wlan_tree, hf_netmon_802_11_rssi,
280                                       tvb, offset, 4, rssi,
281                                       "Unknown");
282     } else {
283       phdr->presence_flags |= PHDR_802_11_HAS_SIGNAL_DBM;
284       phdr->signal_dbm = rssi;
285       proto_tree_add_int_format_value(wlan_tree, hf_netmon_802_11_rssi,
286                                       tvb, offset, 4, rssi,
287                                       "%d dBm", rssi);
288     }
289     offset += 4;
290
291     /*
292      * ucDataRate?
293      */
294     rate = tvb_get_guint8(tvb, offset);
295     if (rate == 0) {
296       proto_tree_add_uint_format_value(wlan_tree, hf_netmon_802_11_datarate,
297                                        tvb, offset, 1, rate,
298                                        "Unknown");
299     } else {
300       phdr->presence_flags |= PHDR_802_11_HAS_DATA_RATE;
301       phdr->data_rate = rate;
302       proto_tree_add_uint_format_value(wlan_tree, hf_netmon_802_11_datarate,
303                                        tvb, offset, 1, rate,
304                                        "%f Mb/s", rate*.5);
305     }
306     offset += 1;
307   } else
308     offset += 13;
309
310   /*
311    * ullTimestamp?
312    *
313    * If so, should this check the presense flag in flags?
314    */
315   phdr->presence_flags |= PHDR_802_11_HAS_TSF_TIMESTAMP;
316   phdr->tsf_timestamp = tvb_get_letoh64(tvb, offset);
317   proto_tree_add_item(wlan_tree, hf_netmon_802_11_timestamp, tvb, offset, 8,
318                       ENC_LITTLE_ENDIAN);
319   /*offset += 8;*/
320
321 skip:
322   offset = length;
323
324   /* dissect the 802.11 packet next */
325   next_tvb = tvb_new_subset_remaining(tvb, offset);
326   call_dissector_with_data(ieee80211_radio_handle, next_tvb, pinfo, tree, phdr);
327   return offset;
328 }
329
330 void
331 proto_register_netmon_802_11(void)
332 {
333   static const value_string phy_type[] = {
334     { PHY_TYPE_UNKNOWN,     "Unknown" },
335     { PHY_TYPE_FHSS,        "802.11 FHSS" },
336     { PHY_TYPE_DSSS,        "802.11 DSSS" },
337     { PHY_TYPE_IR_BASEBAND, "802.11 IR" },
338     { PHY_TYPE_OFDM,        "802.11a" },
339     { PHY_TYPE_HR_DSSS,     "802.11b" },
340     { PHY_TYPE_ERP,         "802.11g" },
341     { PHY_TYPE_HT,          "802.11n" },
342     { PHY_TYPE_VHT,         "802.11ac" },
343     { 0, NULL },
344   };
345
346   static hf_register_info hf[] = {
347     { &hf_netmon_802_11_version, { "Header revision", "netmon_802_11.version", FT_UINT8,
348                           BASE_DEC, NULL, 0x0, NULL, HFILL } },
349     { &hf_netmon_802_11_length, { "Header length", "netmon_802_11.length", FT_UINT16,
350                           BASE_DEC, NULL, 0x0, NULL, HFILL } },
351     { &hf_netmon_802_11_op_mode, { "Operation mode", "netmon_802_11.op_mode", FT_UINT32,
352                           BASE_HEX, NULL, 0x0, NULL, HFILL } },
353     { &hf_netmon_802_11_op_mode_sta, { "Station mode", "netmon_802_11.op_mode.sta", FT_UINT32,
354                           BASE_HEX, NULL, OP_MODE_STA, NULL, HFILL } },
355     { &hf_netmon_802_11_op_mode_ap, { "AP mode", "netmon_802_11.op_mode.ap", FT_UINT32,
356                           BASE_HEX, NULL, OP_MODE_AP, NULL, HFILL } },
357     { &hf_netmon_802_11_op_mode_sta_ext, { "Extensible station mode", "netmon_802_11.op_mode.sta_ext", FT_UINT32,
358                           BASE_HEX, NULL, OP_MODE_STA_EXT, NULL, HFILL } },
359     { &hf_netmon_802_11_op_mode_mon, { "Monitor mode", "netmon_802_11.op_mode.on", FT_UINT32,
360                           BASE_HEX, NULL, OP_MODE_MON, NULL, HFILL } },
361 #if 0
362     { &hf_netmon_802_11_flags, { "Flags", "netmon_802_11.flags", FT_UINT32,
363                           BASE_HEX, NULL, 0x0, NULL, HFILL } },
364 #endif
365     { &hf_netmon_802_11_phy_type, { "PHY type", "netmon_802_11.phy_type", FT_UINT32,
366                           BASE_DEC, VALS(phy_type), 0x0, NULL, HFILL } },
367     { &hf_netmon_802_11_channel, { "Channel", "netmon_802_11.channel", FT_UINT32,
368                           BASE_DEC, NULL, 0x0, NULL, HFILL } },
369     { &hf_netmon_802_11_frequency, { "Center frequency", "netmon_802_11.frequency", FT_UINT32,
370                           BASE_DEC, NULL, 0x0, NULL, HFILL } },
371     { &hf_netmon_802_11_rssi, { "RSSI", "netmon_802_11.rssi", FT_INT32,
372                           BASE_DEC, NULL, 0x0, NULL, HFILL } },
373     { &hf_netmon_802_11_datarate, { "Data rate", "netmon_802_11.datarate", FT_UINT32,
374                           BASE_DEC, NULL, 0x0, NULL, HFILL } },
375     /*
376      * XXX - is this host, or MAC, time stamp?
377      * It might be a FILETIME.
378      */
379     { &hf_netmon_802_11_timestamp, { "Timestamp", "netmon_802_11.timestamp", FT_UINT64,
380                           BASE_DEC, NULL, 0x0, NULL, HFILL } },
381   };
382   static gint *ett[] = {
383     &ett_netmon_802_11,
384     &ett_netmon_802_11_op_mode
385   };
386
387   proto_netmon_802_11 = proto_register_protocol("NetMon 802.11 capture header",
388                                                 "NetMon 802.11",
389                                                 "netmon_802_11");
390   proto_register_field_array(proto_netmon_802_11, hf, array_length(hf));
391   proto_register_subtree_array(ett, array_length(ett));
392 }
393
394 void
395 proto_reg_handoff_netmon_802_11(void)
396 {
397   dissector_handle_t netmon_802_11_handle;
398
399   /* handle for 802.11+radio information dissector */
400   ieee80211_radio_handle = find_dissector("wlan_radio");
401   netmon_802_11_handle = create_dissector_handle(dissect_netmon_802_11,
402                                                  proto_netmon_802_11);
403   dissector_add_uint("wtap_encap", WTAP_ENCAP_IEEE_802_11_NETMON, netmon_802_11_handle);
404 }
405
406 /*
407  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
408  *
409  * Local Variables:
410  * c-basic-offset: 2
411  * tab-width: 8
412  * indent-tabs-mode: nil
413  * End:
414  *
415  * ex: set shiftwidth=2 tabstop=8 expandtab:
416  * :indentSize=2:tabSize=8:noTabs=true:
417  */