Set the svn:eol-style property on all text files to "native", so that
[obnox/wireshark/wip.git] / packet-prism.c
1 /*
2  *  packet-prism.c
3  *      Decode packets with a Prism header
4  *
5  * Prism II-based wlan devices have a monitoring mode that sticks
6  * a proprietary header on each packet with lots of good
7  * information.  This file is responsible for decoding that
8  * data.
9  *
10  * By Tim Newsham
11  *
12  * $Id$
13  *
14  * Ethereal - Network traffic analyzer
15  * By Gerald Combs <gerald@ethereal.com>
16  * Copyright 1998 Gerald Combs
17  *
18  * Copied from README.developer
19  *
20  * This program is free software; you can redistribute it and/or
21  * modify it under the terms of the GNU General Public License
22  * as published by the Free Software Foundation; either version 2
23  * of the License, or (at your option) any later version.
24  *
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28  * GNU General Public License for more details.
29  *
30  * You should have received a copy of the GNU General Public License
31  * along with this program; if not, write to the Free Software
32  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33  */
34
35 #ifdef HAVE_CONFIG_H
36 # include "config.h"
37 #endif
38
39 #include <glib.h>
40
41 #include <epan/packet.h>
42 #include "packet-ieee80211.h"
43 #include "packet-prism.h"
44 #include "packet-wlancap.h"
45
46 /* protocol */
47 static int proto_prism = -1;
48
49 /* header fields */
50 static int hf_prism_msgcode = -1;
51 static int hf_prism_msglen = -1;
52
53 /*
54  * A value from the header.
55  *
56  * It appears from looking at the linux-wlan-ng and Prism II HostAP
57  * drivers, and various patches to the orinoco_cs drivers to add
58  * Prism headers, that:
59  *
60  *      the "did" identifies what the value is (i.e., what it's the value
61  *      of);
62  *
63  *      "status" is 0 if the value is present or 1 if it's absent;
64  *
65  *      "len" is the length of the value (always 4, in that code);
66  *
67  *      "data" is the value of the data (or 0 if not present).
68  *
69  * Note: all of those values are in the *host* byte order of the machine
70  * on which the capture was written.
71  */
72 struct val_80211 {
73     unsigned int did;
74     unsigned short status, len;
75     unsigned int data;
76 };
77
78 /*
79  * Header attached during Prism monitor mode.
80  *
81  * At least according to one paper I've seen, the Prism 2.5 chip set
82  * provides:
83  *
84  *      RSSI (receive signal strength indication) is "the total power
85  *      received by the radio hardware while receiving the frame,
86  *      including signal, interfereence, and background noise";
87  *
88  *      "silence value" is "the total power observed just before the
89  *      start of the frame".
90  *
91  * None of the drivers I looked at supply the "rssi" or "sq" value,
92  * but they do supply "signal" and "noise" values, along with a "rate"
93  * value that's 1/5 of the raw value from what is presumably a raw
94  * HFA384x frame descriptor, with the comment "set to 802.11 units",
95  * which presumably means the units are 500 Kb/s.
96  *
97  * I infer from the current NetBSD "wi" driver that "signal" and "noise"
98  * are adjusted dBm values, with the dBm value having 100 added to it
99  * for the Prism II cards (although the NetBSD code has an XXX comment
100  * for the #define for WI_PRISM_DBM_OFFSET) and 149 (with no XXX comment)
101  * for the Orinoco cards.
102  */
103 struct prism_hdr {
104     unsigned int msgcode, msglen;
105     char devname[16];
106     struct val_80211 hosttime, mactime, channel, rssi, sq, signal,
107         noise, rate, istx, frmlen;
108 };
109
110 #define VALFIELDS(name) \
111     static int hf_prism_ ## name ## _data = -1
112 VALFIELDS(hosttime);
113 VALFIELDS(mactime);
114 VALFIELDS(channel);
115 VALFIELDS(rssi);
116 VALFIELDS(sq);
117 VALFIELDS(signal);
118 VALFIELDS(noise);
119 VALFIELDS(rate);
120 VALFIELDS(istx);
121 VALFIELDS(frmlen);
122
123 static gint ett_prism = -1;
124
125 static dissector_handle_t ieee80211_handle;
126 static dissector_handle_t wlancap_handle;
127
128 void
129 capture_prism(const guchar *pd, int offset, int len, packet_counts *ld)
130 {
131     guint32 cookie = 0;
132     guint32 length = 0;
133     if (!BYTES_ARE_IN_FRAME(offset, len, sizeof(guint32) *2 )) {
134         ld->other++;
135         return;
136     }
137
138     cookie = pntohl(pd);
139     length = pntohl(pd+sizeof(guint32));
140
141     /* Handle the new type of capture format */
142     if (cookie == WLANCAP_MAGIC_COOKIE_V1) {
143       if(!BYTES_ARE_IN_FRAME(offset, len, length)) {
144         ld->other++;
145         return;
146       }
147       offset += length;
148     } else {
149       /* We have an old capture format */
150       if(!BYTES_ARE_IN_FRAME(offset, len, (int)sizeof(struct prism_hdr))) {
151         ld->other++;
152         return;
153       }
154       offset += sizeof(struct prism_hdr);
155     }
156
157     /* 802.11 header follows */
158     capture_ieee80211(pd, offset, len, ld);
159
160 }
161
162 /*
163  * yah, I know, macros, ugh, but it makes the code
164  * below more readable
165  */
166 #define IFHELP(size, name, var, str) \
167         if(tree) {                                                \
168             proto_tree_add_uint_format(prism_tree, hf_prism_ ## name, \
169                 tvb, offset, size, hdr.var, str, hdr.var);                \
170         }                                                                 \
171         offset += (size)
172 #define INTFIELD(size, name, str)       IFHELP(size, name, name, str)
173 #define VALFIELD(name, str) \
174         if (hdr.name.status == 0) {                               \
175             if(tree) {                                            \
176                 proto_tree_add_uint_format(prism_tree, hf_prism_ ## name ## _data, \
177                     tvb, offset, 12, hdr.name.data,                        \
178                     str ": 0x%x (DID 0x%x, Status 0x%x, Length 0x%x)",     \
179                     hdr.name.data, hdr.name.did,                           \
180                     hdr.name.status, hdr.name.len);                        \
181             }                                                              \
182         }                                                                  \
183         offset += 12
184
185 static void
186 dissect_prism(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
187 {
188     struct prism_hdr hdr;
189     proto_tree *prism_tree = NULL;
190     proto_item *ti;
191     tvbuff_t *next_tvb;
192     int offset;
193     guint32 msgcode;
194
195     offset = 0;
196
197     /* handle the new capture type. */
198     msgcode = tvb_get_ntohl(tvb, offset);
199     if (msgcode == WLANCAP_MAGIC_COOKIE_V1) {
200             call_dissector(wlancap_handle, tvb, pinfo, tree);
201             return;
202     }
203       
204     tvb_memcpy(tvb, (guint8 *)&hdr, offset, sizeof(hdr));
205
206     if(check_col(pinfo->cinfo, COL_PROTOCOL))
207         col_set_str(pinfo->cinfo, COL_PROTOCOL, "Prism");
208     if(check_col(pinfo->cinfo, COL_INFO))
209         col_clear(pinfo->cinfo, COL_INFO);
210
211     if(check_col(pinfo->cinfo, COL_INFO))
212         col_add_fstr(pinfo->cinfo, COL_INFO, "Device: %.16s  "
213                      "Message 0x%x, Length %d", hdr.devname,
214                      hdr.msgcode, hdr.msglen);
215
216     if(tree) {
217         ti = proto_tree_add_protocol_format(tree, proto_prism,
218             tvb, 0, sizeof hdr, "Prism Monitoring Header");
219         prism_tree = proto_item_add_subtree(ti, ett_prism);
220     }
221
222     INTFIELD(4, msgcode, "Message Code: %d");
223     INTFIELD(4, msglen, "Message Length: %d");
224     if(tree) {
225         proto_tree_add_text(prism_tree, tvb, offset, sizeof hdr.devname,
226             "Device: %s", hdr.devname);
227     }
228     offset += sizeof hdr.devname;
229
230     VALFIELD(hosttime, "Host Time");
231     VALFIELD(mactime, "MAC Time");
232     VALFIELD(channel, "Channel");
233     if (hdr.rate.status == 0) {
234       if (check_col(pinfo->cinfo, COL_RSSI))
235         col_add_fstr(pinfo->cinfo, COL_RSSI, "%d", hdr.rssi.data);
236       if (tree) {
237         proto_tree_add_uint_format(prism_tree, hf_prism_rssi_data,
238             tvb, offset, 12, hdr.rssi.data,
239             "RSSI: 0x%x (DID 0x%x, Status 0x%x, Length 0x%x)",
240             hdr.rssi.data, hdr.rssi.did, hdr.rssi.status, hdr.rssi.len);
241       }
242     }
243     offset += 12;
244     VALFIELD(sq, "SQ");
245     VALFIELD(signal, "Signal");
246     VALFIELD(noise, "Noise");
247     if (hdr.rate.status == 0) {
248       if (check_col(pinfo->cinfo, COL_TX_RATE)) {
249         col_add_fstr(pinfo->cinfo, COL_TX_RATE, "%u.%u",
250                   hdr.rate.data / 2, hdr.rate.data & 1 ? 5 : 0);
251       }
252       if (tree) {
253           proto_tree_add_uint_format(prism_tree, hf_prism_rate_data,
254                   tvb, offset, 12, hdr.rate.data,
255                   "Data Rate: %u.%u Mb/s",
256                   hdr.rate.data / 2, hdr.rate.data & 1 ? 5 : 0);
257       }
258     }
259     offset += 12;
260     VALFIELD(istx, "IsTX");
261     VALFIELD(frmlen, "Frame Length");
262
263     /* dissect the 802.11 header next */
264     next_tvb = tvb_new_subset(tvb, sizeof hdr, -1, -1);
265     call_dissector(ieee80211_handle, next_tvb, pinfo, tree);
266 }
267
268 #define IFHELP2(size, name, var, str) \
269         { &hf_prism_ ## name, {                                    \
270             str, "prism." #var, size, BASE_HEX, NULL, 0x0, "", HFILL } },
271 #define INTFIELD2(size, name, str)      IFHELP2(size, name, name, str)
272 #define VALFIELD2(name, str) \
273    IFHELP2(FT_UINT32, name ## _data, name.data, str " Field")
274
275 void
276 proto_register_prism(void)
277 {
278     static hf_register_info hf[] = {
279         INTFIELD2(FT_UINT32, msgcode, "Message Code")
280         INTFIELD2(FT_UINT32, msglen, "Message Length")
281         VALFIELD2(hosttime, "Host Time")
282         VALFIELD2(mactime, "MAC Time")
283         VALFIELD2(channel, "Channel")
284         VALFIELD2(rssi, "RSSI")
285         VALFIELD2(sq, "SQ")
286         VALFIELD2(signal, "Signal")
287         VALFIELD2(noise, "Noise")
288         VALFIELD2(rate, "Rate")
289         VALFIELD2(istx, "IsTX")
290         VALFIELD2(frmlen, "Frame Length")
291
292     };
293     static gint *ett[] = {
294         &ett_prism
295     };
296
297     proto_prism = proto_register_protocol("Prism", "Prism", "prism");
298     proto_register_field_array(proto_prism, hf, array_length(hf));
299     proto_register_subtree_array(ett, array_length(ett));
300 }
301
302 void
303 proto_reg_handoff_prism(void)
304 {
305     dissector_handle_t prism_handle;
306
307     /* handle for 802.11 dissector */
308     ieee80211_handle = find_dissector("wlan");
309     wlancap_handle = find_dissector("wlancap");
310
311     prism_handle = create_dissector_handle(dissect_prism, proto_prism);
312     dissector_add("wtap_encap", WTAP_ENCAP_PRISM_HEADER, prism_handle);
313 }