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  * SPDX-License-Identifier: GPL-2.0-or-later
10  */
11 
12 #include "config.h"
13 
14 #include <epan/packet.h>
15 
16 #include <wiretap/wtap.h>
17 
18 #include <wsutil/802_11-utils.h>
19 
20 void proto_register_netmon_802_11(void);
21 void proto_reg_handoff_netmon_802_11(void);
22 
23 /* protocol */
24 static int proto_netmon_802_11 = -1;
25 
26 /* Dissector */
27 static dissector_handle_t netmon_802_11_handle;
28 
29 #define MIN_HEADER_LEN  32
30 
31 /* op_mode */
32 #define OP_MODE_STA     0x00000001      /* station mode */
33 #define OP_MODE_AP      0x00000002      /* AP mode */
34 #define OP_MODE_STA_EXT 0x00000004      /* extensible station mode */
35 #define OP_MODE_MON     0x80000000      /* monitor mode */
36 
37 /* phy_type */
38 /*
39  * Augmented with phy types from
40  *
41  *    https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/windot11/ne-windot11-_dot11_phy_type
42  */
43 #define PHY_TYPE_UNKNOWN     0
44 #define PHY_TYPE_FHSS        1
45 #define PHY_TYPE_DSSS        2
46 #define PHY_TYPE_IR_BASEBAND 3
47 #define PHY_TYPE_OFDM        4 /* 802.11a */
48 #define PHY_TYPE_HR_DSSS     5 /* 802.11b */
49 #define PHY_TYPE_ERP         6 /* 802.11g */
50 #define PHY_TYPE_HT          7 /* 802.11n */
51 #define PHY_TYPE_VHT         8 /* 802.11ac */
52 
53 static int hf_netmon_802_11_version = -1;
54 static int hf_netmon_802_11_length = -1;
55 static int hf_netmon_802_11_op_mode = -1;
56 static int hf_netmon_802_11_op_mode_sta = -1;
57 static int hf_netmon_802_11_op_mode_ap = -1;
58 static int hf_netmon_802_11_op_mode_sta_ext = -1;
59 static int hf_netmon_802_11_op_mode_mon = -1;
60 /* static int hf_netmon_802_11_flags = -1; */
61 static int hf_netmon_802_11_phy_type = -1;
62 static int hf_netmon_802_11_channel = -1;
63 static int hf_netmon_802_11_frequency = -1;
64 static int hf_netmon_802_11_rssi = -1;
65 static int hf_netmon_802_11_datarate = -1;
66 static int hf_netmon_802_11_timestamp = -1;
67 
68 static gint ett_netmon_802_11 = -1;
69 static gint ett_netmon_802_11_op_mode = -1;
70 
71 static dissector_handle_t ieee80211_radio_handle;
72 
73 static int
dissect_netmon_802_11(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)74 dissect_netmon_802_11(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
75 {
76   struct ieee_802_11_phdr phdr;
77   proto_tree *wlan_tree = NULL, *opmode_tree;
78   proto_item *ti;
79   tvbuff_t   *next_tvb;
80   int         offset;
81   guint8      version;
82   guint16     length;
83   guint32     phy_type;
84   guint32     monitor_mode;
85   guint32     flags;
86   guint32     channel;
87   gint        calc_channel;
88   gint32      rssi;
89   guint8      rate;
90 
91   /*
92    * It appears to be the case that management frames (and control and
93    * extension frames ?) may or may not have an FCS and data frames don't.
94    * (Netmon capture files have been seen for this encapsulation
95    * management frames either completely with or without an FCS. Also:
96    * instances have been  seen where both Management and Control frames
97    * do not have an FCS).  An "FCS length" of -2 means "NetMon weirdness".
98    *
99    * The metadata header also has a bit indicating whether the adapter
100    * was in monitor mode or not; if it isn't, we set "decrypted" to TRUE,
101    * as, for those frames, the Protected bit is preserved in received
102    * frames, but the frame is decrypted.
103    */
104   memset(&phdr, 0, sizeof(phdr));
105   phdr.fcs_len = -2;
106   phdr.decrypted = FALSE;
107   phdr.datapad = FALSE;
108   phdr.phy = PHDR_802_11_PHY_UNKNOWN;
109 
110   col_set_str(pinfo->cinfo, COL_PROTOCOL, "WLAN");
111   col_clear(pinfo->cinfo, COL_INFO);
112   offset = 0;
113 
114   version = tvb_get_guint8(tvb, offset);
115   length = tvb_get_letohs(tvb, offset+1);
116   col_add_fstr(pinfo->cinfo, COL_INFO, "NetMon WLAN Capture v%u, Length %u",
117                version, length);
118   if (version != 2) {
119     /* XXX - complain */
120     goto skip;
121   }
122   if (length < MIN_HEADER_LEN) {
123     /* XXX - complain */
124     goto skip;
125   }
126 
127   /* Dissect the packet */
128   ti = proto_tree_add_item(tree, proto_netmon_802_11, tvb, 0, length,
129                            ENC_NA);
130   wlan_tree = proto_item_add_subtree(ti, ett_netmon_802_11);
131 
132   /*
133    * XXX - is this the NDIS_OBJECT_HEADER structure:
134    *
135    *    https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntddndis/ns-ntddndis-_ndis_object_header
136    *
137    * at the beginning of a DOT11_EXTSTA_RECV_CONTEXT structure:
138    *
139    *    https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/windot11/ns-windot11-dot11_extsta_recv_context
140    *
141    * If so, the byte at an offset of 0 would be the appropriate type for the
142    * structure following it, i.e. NDIS_OBJECT_TYPE_DEFAULT.
143    */
144   proto_tree_add_item(wlan_tree, hf_netmon_802_11_version, tvb, offset, 1,
145                       ENC_LITTLE_ENDIAN);
146   offset += 1;
147   proto_tree_add_item(wlan_tree, hf_netmon_802_11_length, tvb, offset, 2,
148                       ENC_LITTLE_ENDIAN);
149   offset += 2;
150 
151   /*
152    * This isn't in the DOT11_EXTSTA_RECV_CONTEXT structure.
153    */
154   ti = proto_tree_add_item(wlan_tree, hf_netmon_802_11_op_mode, tvb, offset,
155                       4, ENC_LITTLE_ENDIAN);
156   opmode_tree = proto_item_add_subtree(ti, ett_netmon_802_11_op_mode);
157   proto_tree_add_item(opmode_tree, hf_netmon_802_11_op_mode_sta, tvb, offset,
158                       4, ENC_LITTLE_ENDIAN);
159   proto_tree_add_item(opmode_tree, hf_netmon_802_11_op_mode_ap, tvb, offset,
160                       4, ENC_LITTLE_ENDIAN);
161   proto_tree_add_item(opmode_tree, hf_netmon_802_11_op_mode_sta_ext, tvb,
162                       offset, 4, ENC_LITTLE_ENDIAN);
163   proto_tree_add_item_ret_uint(opmode_tree, hf_netmon_802_11_op_mode_mon, tvb, offset,
164                                4, ENC_LITTLE_ENDIAN, &monitor_mode);
165   if (!monitor_mode) {
166     /*
167      * If a NetMon capture is not done in monitor mode, we may see frames
168      * with the Protect bit set (because they were encrypted on the air)
169      * but that aren't encrypted (because they've been decrypted before
170      * being written to the file).  This wasn't done in monitor mode, as
171      * the "monitor mode" flag wasn't set, so supporess treating the
172      * Protect flag as an indication that the frame was encrypted.
173      */
174     phdr.decrypted = TRUE;
175 
176     /*
177      * Furthermore, we may see frames with the A-MSDU Present flag set
178      * in the QoS Control field but that have a regular frame, nto a
179      * sequence of A-MSDUs, in the payload.
180      */
181     phdr.no_a_msdus = TRUE;
182   }
183   offset += 4;
184 
185   /*
186    * uReceiveFlags?
187    */
188   flags = tvb_get_letohl(tvb, offset);
189   offset += 4;
190   if (flags != 0xffffffff) {
191     /*
192      * uPhyId?
193      */
194     phy_type = tvb_get_letohl(tvb, offset);
195     memset(&phdr.phy_info, 0, sizeof(phdr.phy_info));
196 
197     /*
198      * Unlike the channel flags in radiotap, this appears
199      * to correctly indicate the modulation for this packet
200      * (no cases seen where this doesn't match the data rate).
201      */
202     switch (phy_type) {
203 
204     case PHY_TYPE_UNKNOWN:
205         phdr.phy = PHDR_802_11_PHY_UNKNOWN;
206         break;
207 
208     case PHY_TYPE_FHSS:
209         phdr.phy = PHDR_802_11_PHY_11_FHSS;
210         break;
211 
212     case PHY_TYPE_IR_BASEBAND:
213         phdr.phy = PHDR_802_11_PHY_11_IR;
214         break;
215 
216     case PHY_TYPE_DSSS:
217         phdr.phy = PHDR_802_11_PHY_11_DSSS;
218         break;
219 
220     case PHY_TYPE_HR_DSSS:
221         phdr.phy = PHDR_802_11_PHY_11B;
222         break;
223 
224     case PHY_TYPE_OFDM:
225         phdr.phy = PHDR_802_11_PHY_11A;
226         break;
227 
228     case PHY_TYPE_ERP:
229         phdr.phy = PHDR_802_11_PHY_11G;
230         break;
231 
232     case PHY_TYPE_HT:
233         phdr.phy = PHDR_802_11_PHY_11N;
234         break;
235 
236     case PHY_TYPE_VHT:
237         phdr.phy = PHDR_802_11_PHY_11AC;
238         break;
239 
240     default:
241         phdr.phy = PHDR_802_11_PHY_UNKNOWN;
242         break;
243     }
244     proto_tree_add_item(wlan_tree, hf_netmon_802_11_phy_type, tvb, offset, 4,
245                         ENC_LITTLE_ENDIAN);
246     offset += 4;
247 
248     /*
249      * uChCenterFrequency?
250      */
251     channel = tvb_get_letohl(tvb, offset);
252     if (channel < 1000) {
253       if (channel == 0) {
254         proto_tree_add_uint_format_value(wlan_tree, hf_netmon_802_11_channel,
255                                          tvb, offset, 4, channel,
256                                          "Unknown");
257       } else {
258         guint frequency;
259 
260         phdr.has_channel = TRUE;
261         phdr.channel = channel;
262         proto_tree_add_uint(wlan_tree, hf_netmon_802_11_channel,
263                             tvb, offset, 4, channel);
264         switch (phdr.phy) {
265 
266         case PHDR_802_11_PHY_11B:
267         case PHDR_802_11_PHY_11G:
268           /* 2.4 GHz channel */
269           frequency = ieee80211_chan_to_mhz(channel, TRUE);
270           break;
271 
272         case PHDR_802_11_PHY_11A:
273           /* 5 GHz channel */
274           frequency = ieee80211_chan_to_mhz(channel, FALSE);
275           break;
276 
277         default:
278           frequency = 0;
279           break;
280         }
281         if (frequency != 0) {
282           phdr.has_frequency = TRUE;
283           phdr.frequency = frequency;
284         }
285       }
286     } else {
287       phdr.has_frequency = TRUE;
288       phdr.frequency = channel;
289       proto_tree_add_uint(wlan_tree, hf_netmon_802_11_frequency,
290                                        tvb, offset, 4, channel);
291       calc_channel = ieee80211_mhz_to_chan(channel);
292       if (calc_channel != -1) {
293         phdr.has_channel = TRUE;
294         phdr.channel = calc_channel;
295       }
296     }
297     offset += 4;
298 
299     /*
300      * usNumberOfMPDUsReceived is missing.
301      */
302 
303     /*
304      * lRSSI?
305      */
306     rssi = tvb_get_letohl(tvb, offset);
307     if (rssi == 0) {
308       proto_tree_add_int_format_value(wlan_tree, hf_netmon_802_11_rssi,
309                                       tvb, offset, 4, rssi,
310                                       "Unknown");
311     } else {
312       phdr.has_signal_dbm = TRUE;
313       phdr.signal_dbm = rssi;
314       proto_tree_add_int_format_value(wlan_tree, hf_netmon_802_11_rssi,
315                                       tvb, offset, 4, rssi,
316                                       "%d dBm", rssi);
317     }
318     offset += 4;
319 
320     /*
321      * ucDataRate?
322      */
323     rate = tvb_get_guint8(tvb, offset);
324     if (rate == 0) {
325       proto_tree_add_uint_format_value(wlan_tree, hf_netmon_802_11_datarate,
326                                        tvb, offset, 1, rate,
327                                        "Unknown");
328     } else {
329       phdr.has_data_rate = TRUE;
330       phdr.data_rate = rate;
331       proto_tree_add_uint_format_value(wlan_tree, hf_netmon_802_11_datarate,
332                                        tvb, offset, 1, rate,
333                                        "%f Mb/s", rate*.5);
334     }
335     offset += 1;
336   } else
337     offset += 13;
338 
339   /*
340    * ullTimestamp?
341    *
342    * If so, should this check the presense flag in flags?
343    */
344   phdr.has_tsf_timestamp = TRUE;
345   phdr.tsf_timestamp = tvb_get_letoh64(tvb, offset);
346   proto_tree_add_item(wlan_tree, hf_netmon_802_11_timestamp, tvb, offset, 8,
347                       ENC_LITTLE_ENDIAN);
348   /*offset += 8;*/
349 
350 skip:
351   offset = length;
352 
353   /* dissect the 802.11 packet next */
354   next_tvb = tvb_new_subset_remaining(tvb, offset);
355   call_dissector_with_data(ieee80211_radio_handle, next_tvb, pinfo, tree, &phdr);
356   return offset;
357 }
358 
359 void
proto_register_netmon_802_11(void)360 proto_register_netmon_802_11(void)
361 {
362   static const value_string phy_type[] = {
363     { PHY_TYPE_UNKNOWN,     "Unknown" },
364     { PHY_TYPE_FHSS,        "802.11 FHSS" },
365     { PHY_TYPE_DSSS,        "802.11 DSSS" },
366     { PHY_TYPE_IR_BASEBAND, "802.11 IR" },
367     { PHY_TYPE_OFDM,        "802.11a" },
368     { PHY_TYPE_HR_DSSS,     "802.11b" },
369     { PHY_TYPE_ERP,         "802.11g" },
370     { PHY_TYPE_HT,          "802.11n" },
371     { PHY_TYPE_VHT,         "802.11ac" },
372     { 0, NULL },
373   };
374 
375   static hf_register_info hf[] = {
376     { &hf_netmon_802_11_version, { "Header revision", "netmon_802_11.version", FT_UINT8,
377                           BASE_DEC, NULL, 0x0, NULL, HFILL } },
378     { &hf_netmon_802_11_length, { "Header length", "netmon_802_11.length", FT_UINT16,
379                           BASE_DEC, NULL, 0x0, NULL, HFILL } },
380     { &hf_netmon_802_11_op_mode, { "Operation mode", "netmon_802_11.op_mode", FT_UINT32,
381                           BASE_HEX, NULL, 0x0, NULL, HFILL } },
382     { &hf_netmon_802_11_op_mode_sta, { "Station mode", "netmon_802_11.op_mode.sta", FT_UINT32,
383                           BASE_HEX, NULL, OP_MODE_STA, NULL, HFILL } },
384     { &hf_netmon_802_11_op_mode_ap, { "AP mode", "netmon_802_11.op_mode.ap", FT_UINT32,
385                           BASE_HEX, NULL, OP_MODE_AP, NULL, HFILL } },
386     { &hf_netmon_802_11_op_mode_sta_ext, { "Extensible station mode", "netmon_802_11.op_mode.sta_ext", FT_UINT32,
387                           BASE_HEX, NULL, OP_MODE_STA_EXT, NULL, HFILL } },
388     { &hf_netmon_802_11_op_mode_mon, { "Monitor mode", "netmon_802_11.op_mode.mon", FT_UINT32,
389                           BASE_HEX, NULL, OP_MODE_MON, NULL, HFILL } },
390 #if 0
391     { &hf_netmon_802_11_flags, { "Flags", "netmon_802_11.flags", FT_UINT32,
392                           BASE_HEX, NULL, 0x0, NULL, HFILL } },
393 #endif
394     { &hf_netmon_802_11_phy_type, { "PHY type", "netmon_802_11.phy_type", FT_UINT32,
395                           BASE_DEC, VALS(phy_type), 0x0, NULL, HFILL } },
396     { &hf_netmon_802_11_channel, { "Channel", "netmon_802_11.channel", FT_UINT32,
397                           BASE_DEC, NULL, 0x0, NULL, HFILL } },
398     { &hf_netmon_802_11_frequency, { "Center frequency", "netmon_802_11.frequency", FT_UINT32,
399                           BASE_DEC|BASE_UNIT_STRING, &units_mhz, 0x0, NULL, HFILL } },
400     { &hf_netmon_802_11_rssi, { "RSSI", "netmon_802_11.rssi", FT_INT32,
401                           BASE_DEC, NULL, 0x0, NULL, HFILL } },
402     { &hf_netmon_802_11_datarate, { "Data rate", "netmon_802_11.datarate", FT_UINT32,
403                           BASE_DEC, NULL, 0x0, NULL, HFILL } },
404     /*
405      * XXX - is this host, or MAC, time stamp?
406      * It might be a FILETIME.
407      */
408     { &hf_netmon_802_11_timestamp, { "Timestamp", "netmon_802_11.timestamp", FT_UINT64,
409                           BASE_DEC, NULL, 0x0, NULL, HFILL } },
410   };
411   static gint *ett[] = {
412     &ett_netmon_802_11,
413     &ett_netmon_802_11_op_mode
414   };
415 
416   proto_netmon_802_11 = proto_register_protocol("NetMon 802.11 capture header",
417                                                 "NetMon 802.11",
418                                                 "netmon_802_11");
419   netmon_802_11_handle = register_dissector("netmon_802_11", dissect_netmon_802_11, proto_netmon_802_11);
420   proto_register_field_array(proto_netmon_802_11, hf, array_length(hf));
421   proto_register_subtree_array(ett, array_length(ett));
422 }
423 
424 void
proto_reg_handoff_netmon_802_11(void)425 proto_reg_handoff_netmon_802_11(void)
426 {
427   /* handle for 802.11+radio information dissector */
428   ieee80211_radio_handle = find_dissector_add_dependency("wlan_radio", proto_netmon_802_11);
429   dissector_add_uint("wtap_encap", WTAP_ENCAP_IEEE_802_11_NETMON, netmon_802_11_handle);
430 }
431 
432 /*
433  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
434  *
435  * Local Variables:
436  * c-basic-offset: 2
437  * tab-width: 8
438  * indent-tabs-mode: nil
439  * End:
440  *
441  * ex: set shiftwidth=2 tabstop=8 expandtab:
442  * :indentSize=2:tabSize=8:noTabs=true:
443  */
444