Don't guard col_set_str (COL_PROTOCOL) with col_check
[obnox/wireshark/wip.git] / epan / dissectors / packet-turbocell.c
1 /* packet-turbocell.c
2  * Routines for Turbocell Header dissection
3  * Copyright 2004, Colin Slater <kiltedtaco@xxxxxxxxx>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  */
25
26 /* This dissector was written entirely from reverse engineering captured
27  * packets. No documentation was used or supplied by Karlnet. Hence, this
28  * dissector is very incomplete. If you have any insight into decoding
29  * these packets, or if you can supply packet captures from turbocell 
30  * networks, contact kiltedtaco@xxxxxxxxx */
31
32 /* 2008-08-05 : Added support for aggregate frames.
33  * AP mode, NWID and sat mode fiels identification were
34  * taken from http://aphopper.sourceforge.net/turbocell.html
35  * everything else is based on (educated) guesses.
36 */
37
38 #ifdef HAVE_CONFIG_H
39 # include "config.h"
40 #endif
41
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45
46 #include <glib.h>
47
48 #include <epan/packet.h>
49 #include <epan/strutil.h>
50
51 #include "oui.h"
52
53 #define TURBOCELL_TYPE_BEACON_NON_POLLING  0x00
54 #define TURBOCELL_TYPE_BEACON_NORMAL       0x40
55 #define TURBOCELL_TYPE_BEACON_POLLING      0x80
56 #define TURBOCELL_TYPE_BEACON_ISP          0xA0
57
58 #define TURBOCELL_TYPE_DATA             0x01
59 #define TURBOCELL_TYPE_MANAGEMENT       0x11
60
61 #define TURBOCELL_SATTELITE_MODE_DENY  0x1
62 #define TURBOCELL_SATTELITE_MODE_ALLOW 0x2
63
64 #define STATION(i) \
65             { &hf_turbocell_station[i], \
66             { "Station " #i , "turbocell.station", \
67             FT_ETHER, BASE_NONE, NULL, 0, \
68             "connected stations / satellites ?", HFILL } \
69         }
70
71 /* Initialize the protocol and registered fields */
72
73 static int proto_turbocell = -1;
74 static int proto_aggregate = -1;
75
76 static int hf_turbocell_type = -1;
77 static int hf_turbocell_dst = -1;
78 static int hf_turbocell_counter = -1;
79 static int hf_turbocell_name = -1;
80 static int hf_turbocell_nwid = -1;
81 static int hf_turbocell_satmode = -1;
82 static int hf_turbocell_unknown = -1;
83 static int hf_turbocell_timestamp  = -1;
84 static int hf_turbocell_station[32]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
85 static int hf_turbocell_ip = -1;
86
87 static int hf_turbocell_aggregate_msdu_header_text = -1;
88 static int hf_turbocell_aggregate_msdu_len = -1;
89 static int hf_turbocell_aggregate_unknown1 = -1;
90 static int hf_turbocell_aggregate_unknown2 = -1;
91 static int hf_turbocell_aggregate_len = -1;
92
93 /* Initialize the subtree pointers */
94 static gint ett_turbocell = -1;
95 static gint ett_network = -1;
96 static gint ett_msdu_aggregation_parent_tree = -1;
97 static gint ett_msdu_aggregation_subframe_tree = -1;
98
99 /* The ethernet dissector we hand off to */
100 static dissector_handle_t eth_handle;
101
102 static dissector_handle_t data_handle;
103
104 static const value_string turbocell_type_values[] = {
105     { TURBOCELL_TYPE_BEACON_NON_POLLING, "Beacon (Non-Polling Base Station)" },
106     { TURBOCELL_TYPE_BEACON_NORMAL,      "Beacon (Normal Base Station)" },
107     { TURBOCELL_TYPE_BEACON_POLLING,     "Beacon (Polling Base Station)" },
108     { TURBOCELL_TYPE_BEACON_ISP,         "Beacon (ISP Base Station)" },
109     { TURBOCELL_TYPE_DATA,               "Data Packet" },
110     { TURBOCELL_TYPE_MANAGEMENT,         "Management Packet" },
111     { 0, NULL }
112 };
113
114 static const value_string turbocell_satmode_values[] = {
115     { TURBOCELL_SATTELITE_MODE_DENY,     "Allowed to connect" },
116     { TURBOCELL_SATTELITE_MODE_ALLOW,    "NOT allowed to connect" },
117     { 0, NULL }
118 };
119
120
121 static void dissect_turbocell(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
122 {
123
124     proto_item *ti, *name_item;
125     proto_tree *turbocell_tree, *network_tree;
126     tvbuff_t   *next_tvb;
127     int i=0;
128     guint8 packet_type;
129     guint8 * str_name;
130     guint str_len;
131
132     packet_type = tvb_get_guint8(tvb, 0);
133
134     if (!(packet_type & 0x0F)){
135         if (check_col(pinfo->cinfo, COL_INFO))
136             col_set_str(pinfo->cinfo, COL_INFO, "Turbocell Packet (Beacon)");
137         col_set_str(pinfo->cinfo, COL_PROTOCOL, "Turbocell");
138     }  else if ( packet_type == TURBOCELL_TYPE_MANAGEMENT ) {
139         if (check_col(pinfo->cinfo, COL_INFO))
140             col_set_str(pinfo->cinfo, COL_INFO, "Turbocell Packet (Management)");
141         col_set_str(pinfo->cinfo, COL_PROTOCOL, "Turbocell");
142     } else if ( packet_type == TURBOCELL_TYPE_DATA ) {
143         if (check_col(pinfo->cinfo, COL_INFO))
144             col_set_str(pinfo->cinfo, COL_INFO, "Turbocell Packet (Data)");
145         col_set_str(pinfo->cinfo, COL_PROTOCOL, "Turbocell");
146     } else {
147         if (check_col(pinfo->cinfo, COL_INFO))
148             col_set_str(pinfo->cinfo, COL_INFO, "Turbocell Packet (Unknown)");
149         col_set_str(pinfo->cinfo, COL_PROTOCOL, "Turbocell");
150     }
151
152     if (tree) {
153         gint remaining_length;
154         ti = proto_tree_add_item(tree, proto_turbocell, tvb, 0, 20, FALSE);
155
156         turbocell_tree = proto_item_add_subtree(ti, ett_turbocell);
157
158         proto_tree_add_item(turbocell_tree, hf_turbocell_type, tvb, 0, 1, FALSE);
159         proto_tree_add_item(turbocell_tree, hf_turbocell_satmode, tvb, 1, 1, FALSE);
160         proto_tree_add_item(turbocell_tree, hf_turbocell_nwid, tvb, 1, 1, FALSE);
161
162         /* it seem when we have this magic number,that means an alternate header version */
163
164         if (tvb_get_bits64(tvb, 64,48,FALSE) != G_GINT64_CONSTANT(0x000001fe23dc45ba)){ 
165         proto_tree_add_item(turbocell_tree, hf_turbocell_counter, tvb, 0x02, 2, FALSE);
166         proto_tree_add_item(turbocell_tree, hf_turbocell_dst, tvb, 0x04, 6, FALSE);
167         proto_tree_add_item(turbocell_tree, hf_turbocell_timestamp, tvb, 0x0A, 3, FALSE);
168
169         } else {
170         proto_tree_add_item(turbocell_tree, hf_turbocell_timestamp, tvb, 0x02, 3, FALSE);
171         proto_tree_add_item(turbocell_tree, hf_turbocell_counter, tvb, 0x05, 3, FALSE);
172         proto_tree_add_item(turbocell_tree, hf_turbocell_dst, tvb, 0x08, 6, FALSE);
173         }
174
175         proto_tree_add_item(turbocell_tree, hf_turbocell_unknown, tvb, 0x0E, 2, FALSE);
176         proto_tree_add_item(turbocell_tree, hf_turbocell_ip, tvb, 0x10, 4, FALSE);
177
178
179         remaining_length=tvb_length_remaining(tvb, 0x14);
180
181         if (remaining_length > 6) {
182
183             /* If the first character is a printable character that means we have a payload with network info */
184             /* I couldn't find anything in the header that would definitvely indicate if payload is either data or network info */
185             /* Since the frame size is limited this should work ok */
186
187             if (tvb_get_guint8(tvb, 0x14)>=0x20){
188                 name_item = proto_tree_add_item(turbocell_tree, hf_turbocell_name, tvb, 0x14, 30, FALSE);
189                 network_tree = proto_item_add_subtree(name_item, ett_network);
190
191                 str_name=tvb_get_ephemeral_stringz(tvb, 0x14, &str_len);
192                 if (check_col (pinfo->cinfo, COL_INFO) && str_len > 0) 
193                     col_append_fstr(pinfo->cinfo, COL_INFO, ", Network=\"%s\"",format_text(str_name, str_len-1));
194
195                 while(tvb_get_guint8(tvb, 0x34 + 8*i)==0x00 && (tvb_length_remaining(tvb,0x34 + 8*i) > 6) && (i<32)) {
196                     proto_tree_add_item(network_tree, hf_turbocell_station[i], tvb, 0x34+8*i, 6, FALSE);
197                     i++;
198                 }
199
200                 /*Couldn't make sense of the apparently random data in the end*/
201
202                 next_tvb = tvb_new_subset(tvb, 0x34 + 8*i, -1, -1);
203                 call_dissector(data_handle, next_tvb, pinfo, tree);
204
205             } else {
206
207                 tvbuff_t *volatile msdu_tvb = NULL,*next_tvb;
208                 guint32 msdu_offset = 0x04;
209                 guint16 j = 1;
210                 guint16 msdu_length;
211
212                 proto_item *parent_item;
213                 proto_tree *mpdu_tree;
214                 proto_tree *subframe_tree;
215
216                 next_tvb = tvb_new_subset(tvb, 0x14, -1, tvb_get_ntohs(tvb, 0x14));
217                 parent_item = proto_tree_add_protocol_format(tree, proto_aggregate, next_tvb, 0,
218                               tvb_reported_length_remaining(next_tvb, 0), "Turbocell Aggregate Frames");
219                 mpdu_tree = proto_item_add_subtree(parent_item, ett_msdu_aggregation_parent_tree);
220                 proto_tree_add_item(mpdu_tree, hf_turbocell_aggregate_len, next_tvb, 0x00, 2, FALSE);
221                 proto_tree_add_item(mpdu_tree, hf_turbocell_aggregate_unknown1, next_tvb, 0x02, 2, FALSE);
222
223                 remaining_length=tvb_length_remaining(next_tvb, msdu_offset);
224
225                 do {
226                     msdu_length = (tvb_get_letohs(next_tvb, msdu_offset) & 0x0FFF);
227                     if (msdu_length==0) break;
228                     parent_item = proto_tree_add_uint_format(mpdu_tree, hf_turbocell_aggregate_msdu_header_text,
229                     next_tvb,msdu_offset, msdu_length + 0x02,j, "A-MSDU Subframe #%u", j);
230
231                     subframe_tree = proto_item_add_subtree(parent_item, ett_msdu_aggregation_subframe_tree);
232                     j++;
233
234                     proto_tree_add_uint_format(subframe_tree, hf_turbocell_aggregate_msdu_len, next_tvb, msdu_offset, 2,
235                     msdu_length, "MSDU length: %u (0x%04X)", msdu_length,msdu_length);
236                     proto_tree_add_item(subframe_tree, hf_turbocell_aggregate_unknown2, next_tvb, msdu_offset+1, 1, FALSE);
237
238                     msdu_offset += 0x02;
239                     remaining_length -= 0x02;
240                     msdu_tvb = tvb_new_subset(next_tvb, msdu_offset, (msdu_length>remaining_length)?remaining_length:msdu_length, msdu_length);
241                     call_dissector(eth_handle, msdu_tvb, pinfo, subframe_tree);
242                     msdu_offset += msdu_length;
243                     remaining_length -= msdu_length;
244                 } while (remaining_length > 6);
245
246                 if (remaining_length > 2) {
247                     next_tvb = tvb_new_subset(next_tvb, msdu_offset, -1, -1);
248                     call_dissector(data_handle, next_tvb, pinfo, tree);
249                 }
250             }
251         }
252     }
253 }
254
255 /* Register the protocol with Wireshark */
256
257 void proto_register_turbocell(void)
258 {
259
260     static hf_register_info hf[] = {
261         { &hf_turbocell_type,
262             { "Packet Type", "turbocell.type",
263             FT_UINT8, BASE_HEX, VALS(turbocell_type_values), 0,
264             NULL, HFILL }
265         },
266         { &hf_turbocell_satmode,
267             { "Satellite Mode", "turbocell.satmode",
268             FT_UINT8, BASE_HEX, VALS(turbocell_satmode_values), 0xF0,
269             NULL, HFILL }
270         },
271         { &hf_turbocell_nwid,
272             { "Network ID", "turbocell.nwid",
273             FT_UINT8, BASE_DEC, NULL, 0x0F,
274             NULL, HFILL }
275         },
276         { &hf_turbocell_counter,
277             { "Counter", "turbocell.counter",
278             FT_UINT24, BASE_DEC_HEX, NULL, 0,
279             "Increments every frame (per station)", HFILL }
280         },
281         { &hf_turbocell_dst,
282             { "Destination", "turbocell.dst",
283             FT_ETHER, BASE_NONE, NULL, 0,
284             "Seems to be the destination", HFILL }
285         },
286
287         { &hf_turbocell_ip,
288             { "IP", "turbocell.ip",
289             FT_IPv4, BASE_NONE, NULL, 0,
290             "IP adress of base station ?", HFILL }
291         },
292
293         { &hf_turbocell_unknown,
294             { "Unknown", "turbocell.unknown",
295             FT_UINT16, BASE_HEX, NULL, 0,
296             "Always 0000", HFILL }
297         },
298
299         { &hf_turbocell_timestamp,
300             { "Timestamp (in 10 ms)", "turbocell.timestamp",
301             FT_UINT24, BASE_DEC_HEX, NULL, 0,
302             "Timestamp per station (since connection?)", HFILL }
303         },
304         { &hf_turbocell_name,
305             { "Network Name", "turbocell.name",
306             FT_STRINGZ, BASE_NONE, NULL, 0,
307             NULL, HFILL }
308         },
309         STATION(0),STATION(1),STATION(2),STATION(3),STATION(4),STATION(5),STATION(6),STATION(7),STATION(8),STATION(9),
310         STATION(10),STATION(11),STATION(12),STATION(13),STATION(14),STATION(15),STATION(16),STATION(17),STATION(18),STATION(19),
311         STATION(20),STATION(21),STATION(22),STATION(23),STATION(24),STATION(25),STATION(26),STATION(27),STATION(28),STATION(29),
312         STATION(30),STATION(31)
313     };
314
315   static hf_register_info aggregate_fields[] = {
316         { &hf_turbocell_aggregate_msdu_header_text,
317             {"MAC Service Data Unit (MSDU)",    "turbocell_aggregate.msduheader",
318             FT_UINT16, BASE_DEC, 0, 0x0000, NULL, HFILL }
319         },
320         { &hf_turbocell_aggregate_msdu_len,
321             {"MSDU length", "turbocell_aggregate.msdulen",
322             FT_UINT16, BASE_DEC_HEX, 0, 0x0FFF, NULL, HFILL }
323         },
324         { &hf_turbocell_aggregate_len,
325             { "Total Length", "turbocell_aggregate.len",
326             FT_UINT16, BASE_DEC_HEX, NULL, 0,
327             "Total reported length", HFILL }
328         },
329         { &hf_turbocell_aggregate_unknown1,
330             { "Unknown", "turbocell_aggregate.unknown1",
331             FT_UINT16, BASE_HEX, NULL, 0,
332             "Always 0x7856", HFILL }
333         },
334         { &hf_turbocell_aggregate_unknown2,
335             { "Unknown", "turbocell_aggregate.unknown2",
336             FT_UINT8, BASE_HEX, NULL, 0xF0,
337             "have the values 0x4,0xC or 0x8", HFILL }
338         },
339   };
340
341     static gint *ett[] = {
342         &ett_turbocell,
343         &ett_network,
344         &ett_msdu_aggregation_parent_tree,
345         &ett_msdu_aggregation_subframe_tree
346     };
347
348     proto_turbocell = proto_register_protocol("Turbocell Header", "Turbocell", "turbocell");
349     
350     proto_aggregate = proto_register_protocol("Turbocell Aggregate Data",
351     "Turbocell Aggregate Data", "turbocell_aggregate");
352     proto_register_field_array(proto_aggregate, aggregate_fields, array_length(aggregate_fields));
353     
354     register_dissector("turbocell", dissect_turbocell, proto_turbocell);
355
356     proto_register_field_array(proto_turbocell, hf, array_length(hf));
357     proto_register_subtree_array(ett, array_length(ett));
358
359 }
360
361
362 void proto_reg_handoff_turbocell(void)
363 {
364     eth_handle = find_dissector("eth_withoutfcs");
365     data_handle = find_dissector("data");
366 }
367