Rename the routines that handle dissector tables with unsigned integer
[obnox/wireshark/wip.git] / epan / dissectors / packet-gsmtap.c
1 /* packet-gsmtap.c
2  * Routines for GSMTAP captures
3  *
4  * (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
5  *
6  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25  * 02111-1307, USA.
26  *
27  */
28
29 /* GSMTAP is a generic header format for GSM protocol captures,
30  * it uses the IANA-assigned UDP port number 4729 and carries
31  * payload in various formats of GSM interfaces such as Um MAC
32  * blocks or Um bursts.
33  *
34  * Example programs generating GSMTAP data are airprobe
35  * (http://airprobe.org/) or OsmocomBB (http://bb.osmocom.org/)
36  */
37
38 #ifdef HAVE_CONFIG_H
39 # include "config.h"
40 #endif
41
42 #include <glib.h>
43 #include <epan/packet.h>
44 #include <epan/prefs.h>
45
46 #define GSMTAP_TYPE_UM                  0x01
47 #define GSMTAP_TYPE_ABIS                0x02
48 #define GSMTAP_TYPE_UM_BURST    0x03    /* raw burst bits */
49
50 #define GSMTAP_BURST_UNKNOWN            0x00
51 #define GSMTAP_BURST_FCCH                       0x01
52 #define GSMTAP_BURST_PARTIAL_SCH        0x02
53 #define GSMTAP_BURST_SCH                        0x03
54 #define GSMTAP_BURST_CTS_SCH            0x04
55 #define GSMTAP_BURST_COMPACT_SCH        0x05
56 #define GSMTAP_BURST_NORMAL                     0x06
57 #define GSMTAP_BURST_DUMMY                      0x07
58 #define GSMTAP_BURST_ACCESS                     0x08
59 #define GSMTAP_BURST_NONE                       0x09
60
61 #define GSMTAP_CHANNEL_UNKNOWN  0x00
62 #define GSMTAP_CHANNEL_BCCH             0x01
63 #define GSMTAP_CHANNEL_CCCH             0x02
64 #define GSMTAP_CHANNEL_RACH             0x03
65 #define GSMTAP_CHANNEL_AGCH             0x04
66 #define GSMTAP_CHANNEL_PCH              0x05
67 #define GSMTAP_CHANNEL_SDCCH    0x06
68 #define GSMTAP_CHANNEL_SDCCH4   0x07
69 #define GSMTAP_CHANNEL_SDCCH8   0x08
70 #define GSMTAP_CHANNEL_TCH_F    0x09
71 #define GSMTAP_CHANNEL_TCH_H    0x0a
72 #define GSMTAP_CHANNEL_ACCH             0x80
73
74 #define GSMTAP_ARFCN_F_PCS              0x8000
75 #define GSMTAP_ARFCN_F_UPLINK   0x4000
76 #define GSMTAP_ARFCN_MASK               0x3fff
77
78 #define GSMTAP_UDP_PORT                 4729
79
80 /* This is the header as it is used by gsmtap-generating software.
81  * It is not used by the wireshark dissector and provided for reference only.
82 struct gsmtap_hdr {
83         guint8 version;         // version, set to 0x01 currently
84         guint8 hdr_len;         // length in number of 32bit words
85         guint8 type;            // see GSMTAP_TYPE_*
86         guint8 timeslot;        // timeslot (0..7 on Um)
87
88         guint16 arfcn;          // ARFCN (frequency)
89         gint8 signal_dbm;       // signal level in dBm
90         gint8 snr_db;           // signal/noise ratio in dB
91
92         guint32 frame_number;   // GSM Frame Number (FN)
93
94         guint8 sub_type;        // Type of burst/channel, see above
95         guint8 antenna_nr;      // Antenna Number
96         guint8 sub_slot;        // sub-slot within timeslot
97         guint8 res;             // reserved for future use (RFU)
98 }
99  */
100
101 static int proto_gsmtap = -1;
102
103 static int hf_gsmtap_version = -1;
104 static int hf_gsmtap_hdrlen = -1;
105 static int hf_gsmtap_type = -1;
106 static int hf_gsmtap_timeslot = -1;
107 static int hf_gsmtap_subslot = -1;
108 static int hf_gsmtap_arfcn = -1;
109 static int hf_gsmtap_uplink = -1;
110 static int hf_gsmtap_noise_dbm = -1;
111 static int hf_gsmtap_signal_dbm = -1;
112 static int hf_gsmtap_frame_nr = -1;
113 static int hf_gsmtap_burst_type = -1;
114 static int hf_gsmtap_channel_type = -1;
115 static int hf_gsmtap_antenna = -1;
116
117 static int hf_sacch_l1h_power_lev = -1;
118 static int hf_sacch_l1h_fpc = -1;
119 static int hf_sacch_l1h_ta = -1;
120
121 static gint ett_gsmtap = -1;
122
123 enum {
124         GSMTAP_SUB_DATA = 0,
125         GSMTAP_SUB_UM,
126         GSMTAP_SUB_UM_LAPDM,
127         GSMTAP_SUB_ABIS,
128
129         GSMTAP_SUB_MAX
130 };
131
132 static dissector_handle_t sub_handles[GSMTAP_SUB_MAX];
133
134 static const value_string gsmtap_bursts[] = {
135         { GSMTAP_BURST_UNKNOWN,         "UNKNOWN" },
136         { GSMTAP_BURST_FCCH,            "FCCH" },
137         { GSMTAP_BURST_PARTIAL_SCH,     "PARTIAL SCH" },
138         { GSMTAP_BURST_SCH,                     "SCH" },
139         { GSMTAP_BURST_CTS_SCH,         "CTS SCH" },
140         { GSMTAP_BURST_COMPACT_SCH,     "COMPACT SCH" },
141         { GSMTAP_BURST_NORMAL,          "NORMAL" },
142         { GSMTAP_BURST_DUMMY,           "DUMMY" },
143         { GSMTAP_BURST_ACCESS,          "RACH" },
144         { 0,                            NULL },
145 };
146
147 static const value_string gsmtap_channels[] = {
148         { GSMTAP_CHANNEL_UNKNOWN,       "UNKNOWN" },
149         { GSMTAP_CHANNEL_BCCH,          "BCCH" },
150         { GSMTAP_CHANNEL_CCCH,          "CCCH" },
151         { GSMTAP_CHANNEL_RACH,          "RACH" },
152         { GSMTAP_CHANNEL_AGCH,          "AGCH" },
153         { GSMTAP_CHANNEL_PCH,           "PCH" },
154         { GSMTAP_CHANNEL_SDCCH,         "SDCCH" },
155         { GSMTAP_CHANNEL_SDCCH4,        "SDCCH/4" },
156         { GSMTAP_CHANNEL_SDCCH8,        "SDCCH/8" },
157         { GSMTAP_CHANNEL_TCH_F,         "FACCH/F" },
158         { GSMTAP_CHANNEL_TCH_H,         "FACCH/H" },
159         { GSMTAP_CHANNEL_ACCH|
160           GSMTAP_CHANNEL_SDCCH,         "LSACCH" },
161         { GSMTAP_CHANNEL_ACCH|
162           GSMTAP_CHANNEL_SDCCH4,        "SACCH/4" },
163         { GSMTAP_CHANNEL_ACCH|
164           GSMTAP_CHANNEL_SDCCH8,        "SACCH/8" },
165         { GSMTAP_CHANNEL_ACCH|
166           GSMTAP_CHANNEL_TCH_F,         "SACCH/F" },
167         { GSMTAP_CHANNEL_ACCH|
168           GSMTAP_CHANNEL_TCH_F,         "SACCH/H" },
169         { 0,                            NULL },
170 };
171
172 static const value_string gsmtap_types[] = {
173         { GSMTAP_TYPE_UM,       "GSM Um (MS<->BTS)" },
174         { GSMTAP_TYPE_ABIS,     "GSM Abis (BTS<->BSC)" },
175         { GSMTAP_TYPE_UM_BURST, "GSM Um burst (MS<->BTS)" },
176         { 0,                    NULL },
177 };
178
179 /* dissect a SACCH L1 header which is included in the first 2 bytes
180  * of every SACCH frame (according to TS 04.04) */
181 static void
182 dissect_sacch_l1h(tvbuff_t *tvb, proto_tree *tree)
183 {
184         proto_item *ti;
185         proto_tree *l1h_tree = NULL;
186
187         if (!tree)
188                 return;
189
190         ti = proto_tree_add_protocol_format(tree, proto_gsmtap, tvb, 0, 2,
191                         "SACCH L1 Header, Power Level: %u, Timing Advance: %u",
192                         tvb_get_guint8(tvb, 0) & 0x1f,
193                         tvb_get_guint8(tvb, 1));
194         l1h_tree = proto_item_add_subtree(ti, ett_gsmtap);
195         /* Power Level */
196         proto_tree_add_item(l1h_tree, hf_sacch_l1h_power_lev, tvb, 0, 1, FALSE);
197         /* Fast Power Control */
198         proto_tree_add_item(l1h_tree, hf_sacch_l1h_fpc, tvb, 0, 1, FALSE);
199         /* Acutal Timing Advance */
200         proto_tree_add_item(l1h_tree, hf_sacch_l1h_ta, tvb, 1, 1, FALSE);
201 }
202
203 /* dissect a GSMTAP header and hand payload off to respective dissector */
204 static void
205 dissect_gsmtap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
206 {
207         int sub_handle, len, offset = 0;
208         proto_item *ti;
209         proto_tree *gsmtap_tree = NULL;
210         tvbuff_t *payload_tvb, *l1h_tvb = NULL;
211         guint8 hdr_len, type, sub_type;
212         guint16 arfcn;
213
214         len = tvb_length(tvb);
215
216         hdr_len = tvb_get_guint8(tvb, offset + 1) <<2;
217         type = tvb_get_guint8(tvb, offset + 2);
218         sub_type = tvb_get_guint8(tvb, offset + 12);
219         arfcn = tvb_get_ntohs(tvb, offset + 4);
220
221         /* In case of a SACCH, there is a two-byte L1 header in front
222          * of the packet (see TS 04.04) */
223         if (type == GSMTAP_TYPE_UM &&
224             sub_type & GSMTAP_CHANNEL_ACCH) {
225                 l1h_tvb = tvb_new_subset(tvb, hdr_len, 2, 2);
226                 payload_tvb = tvb_new_subset(tvb, hdr_len+2, len-(hdr_len+2),
227                                              len-(hdr_len+2));
228         } else {
229                 payload_tvb = tvb_new_subset(tvb, hdr_len, len-hdr_len,
230                                              len-hdr_len);
231         }
232
233         /* We don't want any UDP related info left in the INFO field, as the
234          * gsm_a_dtap dissector will not clear but only append */
235         col_clear(pinfo->cinfo, COL_INFO);
236
237         col_set_str(pinfo->cinfo, COL_PROTOCOL, "GSMTAP");
238
239         if (arfcn & GSMTAP_ARFCN_F_UPLINK) {
240                 col_append_str(pinfo->cinfo, COL_RES_NET_SRC, "MS");
241                 col_append_str(pinfo->cinfo, COL_RES_NET_DST, "BTS");
242                 /* p2p_dir is used by the LAPDm dissector */
243                 pinfo->p2p_dir = P2P_DIR_SENT;
244         } else {
245                 col_set_str(pinfo->cinfo, COL_RES_NET_SRC, "BTS");
246                 switch (sub_type & ~GSMTAP_CHANNEL_ACCH) {
247                 case GSMTAP_CHANNEL_BCCH:
248                 case GSMTAP_CHANNEL_CCCH:
249                 case GSMTAP_CHANNEL_PCH:
250                 case GSMTAP_CHANNEL_AGCH:
251                         col_set_str(pinfo->cinfo, COL_RES_NET_DST, "Broadcast");
252                         break;
253                 default:
254                         col_set_str(pinfo->cinfo, COL_RES_NET_DST, "MS");
255                         break;
256                 }
257                 /* p2p_dir is used by the LAPDm dissector */
258                 pinfo->p2p_dir = P2P_DIR_RECV;
259         }
260
261         if (tree) {
262                 ti = proto_tree_add_protocol_format(tree, proto_gsmtap, tvb, 0, hdr_len,
263                         "GSM TAP Header, ARFCN: %u (%s), TS: %u, Channel: %s (%u)",
264                         arfcn & GSMTAP_ARFCN_MASK,
265                         arfcn & GSMTAP_ARFCN_F_UPLINK ? "Uplink" : "Downlink",
266                         tvb_get_guint8(tvb, offset+3),
267                         val_to_str(tvb_get_guint8(tvb, offset+12), gsmtap_channels, "Unknown: %d"),
268                         tvb_get_guint8(tvb, offset+14));
269                 gsmtap_tree = proto_item_add_subtree(ti, ett_gsmtap);
270                 proto_tree_add_item(gsmtap_tree, hf_gsmtap_version,
271                                     tvb, offset, 1, FALSE);
272                 proto_tree_add_uint_format(gsmtap_tree, hf_gsmtap_hdrlen,
273                                     tvb, offset+1, 1, hdr_len,
274                                     "Header length: %u bytes", hdr_len);
275                 proto_tree_add_item(gsmtap_tree, hf_gsmtap_type,
276                                     tvb, offset+2, 1, FALSE);
277                 proto_tree_add_item(gsmtap_tree, hf_gsmtap_timeslot,
278                                     tvb, offset+3, 1, FALSE);
279                 proto_tree_add_item(gsmtap_tree, hf_gsmtap_arfcn,
280                                     tvb, offset+4, 2, FALSE);
281                 proto_tree_add_item(gsmtap_tree, hf_gsmtap_uplink,
282                                     tvb, offset+4, 2, FALSE);
283                 proto_tree_add_item(gsmtap_tree, hf_gsmtap_noise_dbm,
284                                     tvb, offset+6, 1, FALSE);
285                 proto_tree_add_item(gsmtap_tree, hf_gsmtap_signal_dbm,
286                                     tvb, offset+7, 1, FALSE);
287                 proto_tree_add_item(gsmtap_tree, hf_gsmtap_frame_nr,
288                                     tvb, offset+8, 4, FALSE);
289                 if (type == GSMTAP_TYPE_UM_BURST)
290                         proto_tree_add_item(gsmtap_tree, hf_gsmtap_burst_type,
291                                             tvb, offset+12, 1, FALSE);
292                 else if (type == GSMTAP_TYPE_UM)
293                         proto_tree_add_item(gsmtap_tree, hf_gsmtap_channel_type,
294                                             tvb, offset+12, 1, FALSE);
295                 proto_tree_add_item(gsmtap_tree, hf_gsmtap_antenna,
296                                     tvb, offset+13, 1, FALSE);
297                 proto_tree_add_item(gsmtap_tree, hf_gsmtap_subslot,
298                                     tvb, offset+14, 1, FALSE);
299         }
300
301         switch (type) {
302         case GSMTAP_TYPE_UM:
303                 if (l1h_tvb)
304                         dissect_sacch_l1h(l1h_tvb, tree);
305                 switch (sub_type & ~GSMTAP_CHANNEL_ACCH) {
306                 case GSMTAP_CHANNEL_BCCH:
307                 case GSMTAP_CHANNEL_CCCH:
308                 case GSMTAP_CHANNEL_PCH:
309                 case GSMTAP_CHANNEL_AGCH:
310                         /* FIXME: we might want to skip idle frames */
311                         sub_handle = GSMTAP_SUB_UM;
312                         break;
313                 case GSMTAP_CHANNEL_SDCCH:
314                 case GSMTAP_CHANNEL_SDCCH4:
315                 case GSMTAP_CHANNEL_SDCCH8:
316                 case GSMTAP_CHANNEL_TCH_F:
317                 case GSMTAP_CHANNEL_TCH_H:
318                         sub_handle = GSMTAP_SUB_UM_LAPDM;
319                         break;
320                 case GSMTAP_CHANNEL_RACH:
321                 default:
322                         sub_handle = GSMTAP_SUB_DATA;
323                         break;
324                 }
325                 break;
326         case GSMTAP_TYPE_UM_BURST:
327         default:
328                 sub_handle = GSMTAP_SUB_DATA;
329                 break;
330         }
331         call_dissector(sub_handles[sub_handle], payload_tvb, pinfo, tree);
332 }
333
334 static const true_false_string sacch_l1h_fpc_mode_vals = {
335         "In use",
336         "Not in use"
337 };
338
339 void
340 proto_register_gsmtap(void)
341 {
342         static hf_register_info hf[] = {
343                 { &hf_gsmtap_version, { "Version", "gsmtap.version",
344                   FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
345                 { &hf_gsmtap_hdrlen, { "Header Length", "gsmtap.hdr_len",
346                   FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
347                 { &hf_gsmtap_type, { "Payload Type", "gsmtap.type",
348                   FT_UINT8, BASE_DEC, VALS(gsmtap_types), 0, NULL, HFILL } },
349                 { &hf_gsmtap_timeslot, { "Time Slot", "gsmtap.ts",
350                   FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
351                 { &hf_gsmtap_arfcn, { "ARFCN", "gsmtap.arfcn",
352                   FT_UINT16, BASE_DEC, NULL, GSMTAP_ARFCN_MASK, NULL, HFILL } },
353                 { &hf_gsmtap_uplink, { "Uplink", "gsmtap.uplink",
354                   FT_UINT16, BASE_DEC, NULL, GSMTAP_ARFCN_F_UPLINK, NULL, HFILL } },
355                 { &hf_gsmtap_noise_dbm, { "Signal/Noise Ratio (dB)", "gsmtap.snr_db",
356                   FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
357                 { &hf_gsmtap_signal_dbm, { "Signal Level (dBm)", "gsmtap.signal_dbm",
358                   FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
359                 { &hf_gsmtap_frame_nr, { "GSM Frame Number", "gsmtap.frame_nr",
360                   FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
361                 { &hf_gsmtap_burst_type, { "Burst Type", "gsmtap.burst_type",
362                   FT_UINT8, BASE_DEC, VALS(gsmtap_bursts), 0, NULL, HFILL }},
363                 { &hf_gsmtap_channel_type, { "Channel Type", "gsmtap.chan_type",
364                   FT_UINT8, BASE_DEC, VALS(gsmtap_channels), 0, NULL, HFILL }},
365                 { &hf_gsmtap_antenna, { "Antenna Number", "gsmtap.antenna",
366                   FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
367                 { &hf_gsmtap_subslot, { "Sub-Slot", "gsmtap.sub_slot",
368                   FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
369
370                 { &hf_sacch_l1h_power_lev, { "MS power level", "gsmtap.sacch_l1.power_lev",
371                   FT_UINT8, BASE_DEC, NULL, 0x1f, NULL, HFILL } },
372                 { &hf_sacch_l1h_fpc, { "FPC", "gsmtap.sacch_l1.fpc",
373                   FT_BOOLEAN, 8, TFS(&sacch_l1h_fpc_mode_vals), 0x04,
374                   NULL, HFILL } },
375                 { &hf_sacch_l1h_ta, { "Actual Timing Advance", "gsmtap.sacch_l1.ta",
376                   FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
377         };
378         static gint *ett[] = {
379                 &ett_gsmtap
380         };
381
382         proto_gsmtap = proto_register_protocol("GSM Radiotap", "GSMTAP", "gsmtap");
383         proto_register_field_array(proto_gsmtap, hf, array_length(hf));
384         proto_register_subtree_array(ett, array_length(ett));
385 }
386
387 void
388 proto_reg_handoff_gsmtap(void)
389 {
390         dissector_handle_t gsmtap_handle;
391
392         sub_handles[GSMTAP_SUB_DATA] = find_dissector("data");
393         sub_handles[GSMTAP_SUB_UM] = find_dissector("gsm_a_ccch");
394         sub_handles[GSMTAP_SUB_UM_LAPDM] = find_dissector("lapdm");
395         sub_handles[GSMTAP_SUB_ABIS] = find_dissector("gsm_a_dtap");
396         gsmtap_handle = create_dissector_handle(dissect_gsmtap, proto_gsmtap);
397         dissector_add_uint("udp.port", GSMTAP_UDP_PORT, gsmtap_handle);
398 }