Coverage Report

Created: 2026-05-14 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-turbocell.c
Line
Count
Source
1
/* packet-turbocell.c
2
 * Routines for Turbocell Header dissection
3
 * Copyright 2004, Colin Slater <kiltedtaco@xxxxxxxxx>
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
/* This dissector was written entirely from reverse engineering captured
13
 * packets. No documentation was used or supplied by Karlnet. Hence, this
14
 * dissector is very incomplete. If you have any insight into decoding
15
 * these packets, or if you can supply packet captures from turbocell
16
 * networks, contact kiltedtaco@xxxxxxxxx */
17
18
/* 2008-08-05 : Added support for aggregate frames.
19
 * AP mode, NWID and sat mode fields identification were
20
 * taken from http://aphopper.sourceforge.net/turbocell.html
21
 * everything else is based on (educated) guesses.
22
*/
23
24
#include "config.h"
25
26
#include <epan/packet.h>
27
#include <epan/strutil.h>
28
29
#define TURBOCELL_TYPE_BEACON_NON_POLLING  0x00
30
#define TURBOCELL_TYPE_BEACON_NORMAL       0x40
31
#define TURBOCELL_TYPE_BEACON_POLLING      0x80
32
#define TURBOCELL_TYPE_BEACON_ISP          0xA0
33
34
0
#define TURBOCELL_TYPE_DATA             0x01
35
0
#define TURBOCELL_TYPE_MANAGEMENT       0x11
36
37
#define TURBOCELL_SATTELITE_MODE_DENY  0x1
38
#define TURBOCELL_SATTELITE_MODE_ALLOW 0x2
39
40
void proto_register_turbocell(void);
41
void proto_reg_handoff_turbocell(void);
42
43
static int proto_turbocell;
44
static int proto_aggregate;
45
46
static int hf_turbocell_type;
47
static int hf_turbocell_dst;
48
static int hf_turbocell_counter;
49
static int hf_turbocell_name;
50
static int hf_turbocell_nwid;
51
static int hf_turbocell_satmode;
52
static int hf_turbocell_unknown;
53
static int hf_turbocell_timestamp;
54
static int hf_turbocell_station;
55
static int hf_turbocell_ip;
56
57
static int hf_turbocell_aggregate_msdu_header_text;
58
static int hf_turbocell_aggregate_msdu_len;
59
static int hf_turbocell_aggregate_unknown1;
60
static int hf_turbocell_aggregate_unknown2;
61
static int hf_turbocell_aggregate_len;
62
63
static int ett_turbocell;
64
static int ett_network;
65
static int ett_msdu_aggregation_parent_tree;
66
static int ett_msdu_aggregation_subframe_tree;
67
68
/* The ethernet dissector we hand off to */
69
static dissector_handle_t eth_handle;
70
71
static const value_string turbocell_type_values[] = {
72
    { TURBOCELL_TYPE_BEACON_NON_POLLING, "Beacon (Non-Polling Base Station)" },
73
    { TURBOCELL_TYPE_BEACON_NORMAL,      "Beacon (Normal Base Station)" },
74
    { TURBOCELL_TYPE_BEACON_POLLING,     "Beacon (Polling Base Station)" },
75
    { TURBOCELL_TYPE_BEACON_ISP,         "Beacon (ISP Base Station)" },
76
    { TURBOCELL_TYPE_DATA,               "Data Packet" },
77
    { TURBOCELL_TYPE_MANAGEMENT,         "Management Packet" },
78
    { 0, NULL }
79
};
80
81
static const value_string turbocell_satmode_values[] = {
82
    { TURBOCELL_SATTELITE_MODE_DENY,     "Allowed to connect" },
83
    { TURBOCELL_SATTELITE_MODE_ALLOW,    "NOT allowed to connect" },
84
    { 0, NULL }
85
};
86
87
88
static int
89
dissect_turbocell(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
90
0
{
91
92
0
    proto_item *ti, *name_item;
93
0
    proto_tree *turbocell_tree = NULL, *network_tree;
94
0
    tvbuff_t   *next_tvb;
95
0
    int i=0;
96
0
    uint8_t packet_type;
97
0
    char* str_name;
98
0
    int str_len;
99
0
    int remaining_length;
100
101
0
    packet_type = tvb_get_uint8(tvb, 0);
102
103
0
    if (!(packet_type & 0x0F)){
104
0
        col_set_str(pinfo->cinfo, COL_INFO, "Turbocell Packet (Beacon)");
105
0
        col_set_str(pinfo->cinfo, COL_PROTOCOL, "Turbocell");
106
0
    }  else if ( packet_type == TURBOCELL_TYPE_MANAGEMENT ) {
107
0
        col_set_str(pinfo->cinfo, COL_INFO, "Turbocell Packet (Management)");
108
0
        col_set_str(pinfo->cinfo, COL_PROTOCOL, "Turbocell");
109
0
    } else if ( packet_type == TURBOCELL_TYPE_DATA ) {
110
0
        col_set_str(pinfo->cinfo, COL_INFO, "Turbocell Packet (Data)");
111
0
        col_set_str(pinfo->cinfo, COL_PROTOCOL, "Turbocell");
112
0
    } else {
113
0
        col_set_str(pinfo->cinfo, COL_INFO, "Turbocell Packet (Unknown)");
114
0
        col_set_str(pinfo->cinfo, COL_PROTOCOL, "Turbocell");
115
0
    }
116
117
0
    if (tree) {
118
0
        ti = proto_tree_add_item(tree, proto_turbocell, tvb, 0, 20, ENC_NA);
119
120
0
        turbocell_tree = proto_item_add_subtree(ti, ett_turbocell);
121
122
0
        proto_tree_add_item(turbocell_tree, hf_turbocell_type, tvb, 0, 1, ENC_BIG_ENDIAN);
123
0
        proto_tree_add_item(turbocell_tree, hf_turbocell_satmode, tvb, 1, 1, ENC_BIG_ENDIAN);
124
0
        proto_tree_add_item(turbocell_tree, hf_turbocell_nwid, tvb, 1, 1, ENC_BIG_ENDIAN);
125
126
        /* it seem when we have this magic number,that means an alternate header version */
127
128
0
        if (tvb_get_bits64(tvb, 64,48,ENC_BIG_ENDIAN) != INT64_C(0x000001fe23dc45ba)){
129
0
        proto_tree_add_item(turbocell_tree, hf_turbocell_counter, tvb, 0x02, 2, ENC_BIG_ENDIAN);
130
0
        proto_tree_add_item(turbocell_tree, hf_turbocell_dst, tvb, 0x04, 6, ENC_NA);
131
0
        proto_tree_add_item(turbocell_tree, hf_turbocell_timestamp, tvb, 0x0A, 3, ENC_BIG_ENDIAN);
132
133
0
        } else {
134
0
        proto_tree_add_item(turbocell_tree, hf_turbocell_timestamp, tvb, 0x02, 3, ENC_BIG_ENDIAN);
135
0
        proto_tree_add_item(turbocell_tree, hf_turbocell_counter, tvb, 0x05, 3, ENC_BIG_ENDIAN);
136
0
        proto_tree_add_item(turbocell_tree, hf_turbocell_dst, tvb, 0x08, 6, ENC_NA);
137
0
        }
138
139
0
        proto_tree_add_item(turbocell_tree, hf_turbocell_unknown, tvb, 0x0E, 2, ENC_BIG_ENDIAN);
140
0
        proto_tree_add_item(turbocell_tree, hf_turbocell_ip, tvb, 0x10, 4, ENC_BIG_ENDIAN);
141
142
0
    }
143
144
0
    remaining_length=tvb_reported_length_remaining(tvb, 0x14);
145
146
0
    if (remaining_length > 6) {
147
148
        /* If the first character is a printable character that means we have a payload with network info */
149
        /* I couldn't find anything in the header that would definitively indicate if payload is either data or network info */
150
        /* Since the frame size is limited this should work ok */
151
152
0
        if (tvb_get_uint8(tvb, 0x14)>=0x20){
153
0
            name_item = proto_tree_add_item_ret_string_and_length(turbocell_tree, hf_turbocell_name, tvb, 0x14, 30, ENC_ASCII, pinfo->pool, (const uint8_t**)&str_name, &str_len);
154
0
            network_tree = proto_item_add_subtree(name_item, ett_network);
155
156
0
            col_append_fstr(pinfo->cinfo, COL_INFO, ", Network=\"%s\"", format_text(pinfo->pool, str_name, str_len-1));
157
158
0
            while(tvb_get_uint8(tvb, 0x34 + 8*i)==0x00 && (tvb_reported_length_remaining(tvb,0x34 + 8*i) > 6) && (i<32)) {
159
0
                proto_tree_add_item(network_tree, hf_turbocell_station, tvb, 0x34 + 8*i, 6, ENC_NA);
160
0
                i++;
161
0
            }
162
163
            /*Couldn't make sense of the apparently random data in the end*/
164
165
0
            next_tvb = tvb_new_subset_remaining(tvb, 0x34 + 8*i);
166
0
            call_data_dissector(next_tvb, pinfo, tree);
167
168
0
        } else {
169
170
0
            tvbuff_t *msdu_tvb = NULL;
171
0
            uint32_t msdu_offset = 0x04;
172
0
            uint16_t j = 1;
173
0
            uint16_t msdu_length;
174
175
0
            proto_item *parent_item;
176
0
            proto_tree *mpdu_tree;
177
0
            proto_tree *subframe_tree;
178
179
0
            next_tvb = tvb_new_subset_length(tvb, 0x14, tvb_get_ntohs(tvb, 0x14));
180
0
            parent_item = proto_tree_add_protocol_format(tree, proto_aggregate, next_tvb, 0,
181
0
                                                         tvb_reported_length_remaining(next_tvb, 0), "Turbocell Aggregate Frames");
182
0
            mpdu_tree = proto_item_add_subtree(parent_item, ett_msdu_aggregation_parent_tree);
183
0
            proto_tree_add_item(mpdu_tree, hf_turbocell_aggregate_len, next_tvb, 0x00, 2, ENC_BIG_ENDIAN);
184
0
            proto_tree_add_item(mpdu_tree, hf_turbocell_aggregate_unknown1, next_tvb, 0x02, 2, ENC_BIG_ENDIAN);
185
186
0
            remaining_length=tvb_reported_length_remaining(next_tvb, msdu_offset);
187
188
0
            do {
189
0
                msdu_length = (tvb_get_letohs(next_tvb, msdu_offset) & 0x0FFF);
190
0
                if (msdu_length==0) break;
191
0
                parent_item = proto_tree_add_uint_format(mpdu_tree, hf_turbocell_aggregate_msdu_header_text,
192
0
                                                         next_tvb,msdu_offset, msdu_length + 0x02,j, "A-MSDU Subframe #%u", j);
193
194
0
                subframe_tree = proto_item_add_subtree(parent_item, ett_msdu_aggregation_subframe_tree);
195
0
                j++;
196
197
0
                proto_tree_add_item(subframe_tree, hf_turbocell_aggregate_msdu_len, next_tvb, msdu_offset, 2, ENC_LITTLE_ENDIAN);
198
0
                proto_tree_add_item(subframe_tree, hf_turbocell_aggregate_unknown2, next_tvb, msdu_offset+1, 1, ENC_BIG_ENDIAN);
199
200
0
                msdu_offset += 0x02;
201
0
                remaining_length -= 0x02;
202
0
                msdu_tvb = tvb_new_subset_length(next_tvb, msdu_offset, msdu_length);
203
0
                call_dissector(eth_handle, msdu_tvb, pinfo, subframe_tree);
204
0
                msdu_offset += msdu_length;
205
0
                remaining_length -= msdu_length;
206
0
            } while (remaining_length > 6);
207
208
0
            if (remaining_length > 2) {
209
0
                next_tvb = tvb_new_subset_remaining(next_tvb, msdu_offset);
210
0
                call_data_dissector(next_tvb, pinfo, tree);
211
0
            }
212
0
        }
213
0
    }
214
0
    return tvb_captured_length(tvb);
215
0
}
216
217
/* Register the protocol with Wireshark */
218
219
void proto_register_turbocell(void)
220
15
{
221
222
15
    static hf_register_info hf[] = {
223
15
        { &hf_turbocell_type,
224
15
          { "Packet Type", "turbocell.type",
225
15
            FT_UINT8, BASE_HEX, VALS(turbocell_type_values), 0,
226
15
            NULL, HFILL }
227
15
        },
228
15
        { &hf_turbocell_satmode,
229
15
          { "Satellite Mode", "turbocell.satmode",
230
15
            FT_UINT8, BASE_HEX, VALS(turbocell_satmode_values), 0xF0,
231
15
            NULL, HFILL }
232
15
        },
233
15
        { &hf_turbocell_nwid,
234
15
          { "Network ID", "turbocell.nwid",
235
15
            FT_UINT8, BASE_DEC, NULL, 0x0F,
236
15
            NULL, HFILL }
237
15
        },
238
15
        { &hf_turbocell_counter,
239
15
          { "Counter", "turbocell.counter",
240
15
            FT_UINT24, BASE_DEC_HEX, NULL, 0,
241
15
            "Increments every frame (per station)", HFILL }
242
15
        },
243
15
        { &hf_turbocell_dst,
244
15
          { "Destination", "turbocell.dst",
245
15
            FT_ETHER, BASE_NONE, NULL, 0,
246
15
            "Seems to be the destination", HFILL }
247
15
        },
248
249
15
        { &hf_turbocell_ip,
250
15
          { "IP", "turbocell.ip",
251
15
            FT_IPv4, BASE_NONE, NULL, 0,
252
15
            "IP address of base station ?", HFILL }
253
15
        },
254
255
15
        { &hf_turbocell_unknown,
256
15
          { "Unknown", "turbocell.unknown",
257
15
            FT_UINT16, BASE_HEX, NULL, 0,
258
15
            "Always 0000", HFILL }
259
15
        },
260
261
15
        { &hf_turbocell_timestamp,
262
15
          { "Timestamp (in 10 ms)", "turbocell.timestamp",
263
15
            FT_UINT24, BASE_DEC_HEX, NULL, 0,
264
15
            "Timestamp per station (since connection?)", HFILL }
265
15
        },
266
15
        { &hf_turbocell_name,
267
15
          { "Network Name", "turbocell.name",
268
15
            FT_STRINGZTRUNC, BASE_NONE, NULL, 0,
269
15
            NULL, HFILL }
270
15
        },
271
15
        { &hf_turbocell_station,
272
15
            { "Station", "turbocell.station",
273
15
            FT_ETHER, BASE_NONE, NULL, 0,
274
15
            "connected stations / satellites ?", HFILL },
275
15
        }
276
15
    };
277
278
15
    static hf_register_info aggregate_fields[] = {
279
15
        { &hf_turbocell_aggregate_msdu_header_text,
280
15
          {"MAC Service Data Unit (MSDU)", "turbocell_aggregate.msduheader",
281
15
           FT_UINT16, BASE_DEC, 0, 0x0, NULL, HFILL }
282
15
        },
283
15
        { &hf_turbocell_aggregate_msdu_len,
284
15
          {"MSDU length", "turbocell_aggregate.msdulen",
285
15
           FT_UINT16, BASE_DEC_HEX, 0, 0x0FFF, NULL, HFILL }
286
15
        },
287
15
        { &hf_turbocell_aggregate_len,
288
15
          { "Total Length", "turbocell_aggregate.len",
289
15
            FT_UINT16, BASE_DEC_HEX, NULL, 0,
290
15
            "Total reported length", HFILL }
291
15
        },
292
15
        { &hf_turbocell_aggregate_unknown1,
293
15
          { "Unknown", "turbocell_aggregate.unknown1",
294
15
            FT_UINT16, BASE_HEX, NULL, 0,
295
15
            "Always 0x7856", HFILL }
296
15
        },
297
15
        { &hf_turbocell_aggregate_unknown2,
298
15
          { "Unknown", "turbocell_aggregate.unknown2",
299
15
            FT_UINT8, BASE_HEX, NULL, 0xF0,
300
15
            "have the values 0x4,0xC or 0x8", HFILL }
301
15
        },
302
15
    };
303
304
15
    static int *ett[] = {
305
15
        &ett_turbocell,
306
15
        &ett_network,
307
15
        &ett_msdu_aggregation_parent_tree,
308
15
        &ett_msdu_aggregation_subframe_tree
309
15
    };
310
311
15
    proto_turbocell = proto_register_protocol("Turbocell Header", "Turbocell", "turbocell");
312
313
15
    proto_aggregate = proto_register_protocol("Turbocell Aggregate Data",
314
15
                                              "Turbocell Aggregate Data", "turbocell_aggregate");
315
15
    proto_register_field_array(proto_aggregate, aggregate_fields, array_length(aggregate_fields));
316
317
15
    register_dissector("turbocell", dissect_turbocell, proto_turbocell);
318
319
15
    proto_register_field_array(proto_turbocell, hf, array_length(hf));
320
15
    proto_register_subtree_array(ett, array_length(ett));
321
322
15
}
323
324
325
void proto_reg_handoff_turbocell(void)
326
15
{
327
15
    eth_handle = find_dissector_add_dependency("eth_withoutfcs", proto_turbocell);
328
15
}
329
330
/*
331
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
332
 *
333
 * Local variables:
334
 * c-basic-offset: 4
335
 * tab-width: 8
336
 * indent-tabs-mode: nil
337
 * End:
338
 *
339
 * vi: set shiftwidth=4 tabstop=8 expandtab:
340
 * :indentSize=4:tabSize=8:noTabs=true:
341
 */