2 * Routines for GSM Um packet disassembly
3 * Duncan Salerno <duncan.salerno@googlemail.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include <epan/packet.h>
16 #include <epan/prefs.h>
17 #include <wiretap/wtap.h>
19 void proto_register_gsm_um(void);
20 void proto_reg_handoff_gsm_um(void);
22 static int proto_gsm_um
;
23 static int hf_gsm_um_direction
;
24 static int hf_gsm_um_channel
;
25 static int hf_gsm_um_bsic
;
26 static int hf_gsm_um_arfcn
;
27 static int hf_gsm_um_band
;
28 static int hf_gsm_um_frequency
;
29 static int hf_gsm_um_frame
;
30 static int hf_gsm_um_error
;
31 static int hf_gsm_um_timeshift
;
32 static int hf_gsm_um_l2_pseudo_len
;
34 static int ett_gsm_um
;
36 static dissector_handle_t gsm_um_handle
;
38 static dissector_handle_t lapdm_handle
;
39 static dissector_handle_t dtap_handle
;
41 static bool dcs1800_gsm
= true;
43 #define GSM_UM_L2_PSEUDO_LEN 0xfc
47 decode_arfcn(uint16_t arfcn
, const char **band
, unsigned *uplink
, unsigned *downlink
)
49 /* Decode ARFCN to frequency using GSM 05.05 */
50 if( arfcn
>= 1 && arfcn
<= 124 ) {
52 *uplink
= 890000 + 200 * arfcn
;
53 *downlink
= *uplink
+ 45000;
55 else if( arfcn
== 0 ) {
57 *uplink
= 890000 + 200 * arfcn
;
58 *downlink
= *uplink
+ 45000;
60 else if( arfcn
>= 975 && arfcn
<= 1023 ) {
62 *uplink
= 890000 + 200 * (arfcn
- 1024);
63 *downlink
= *uplink
+ 45000;
65 else if( arfcn
>= 955 && arfcn
<= 974 ) {
67 *uplink
= 890000 + 200 * (arfcn
- 1024);
68 *downlink
= *uplink
+ 45000;
70 else if( arfcn
>= 512 && arfcn
<= 885 && dcs1800_gsm
) {
72 *uplink
= 1710200 + 200 * (arfcn
- 512);
73 *downlink
= *uplink
+ 95000;
75 else if( arfcn
>= 512 && arfcn
<= 810 && !dcs1800_gsm
) {
77 *uplink
= 1850200 + 200 * (arfcn
- 512);
78 *downlink
= *uplink
+ 80000;
80 else if( arfcn
>= 259 && arfcn
<= 293 ) {
82 *uplink
= 450600 + 200 * (arfcn
- 259);
83 *downlink
= *uplink
+ 10000;
85 else if( arfcn
>= 306 && arfcn
<= 340 ) {
87 *uplink
= 479000 + 200 * (arfcn
- 306);
88 *downlink
= *uplink
+ 10000;
90 else if( arfcn
>= 128 && arfcn
<= 251 ) {
92 *uplink
= 824200 + 200 * (arfcn
- 128);
93 *downlink
= *uplink
+ 45000;
97 *uplink
= *downlink
= 0;
103 dissect_gsm_um(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
105 proto_tree
*gsm_um_tree
= NULL
;
108 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "GSM Um");
110 if (pinfo
->pseudo_header
->gsm_um
.uplink
) {
111 col_set_str(pinfo
->cinfo
, COL_RES_DL_DST
, "BTS");
112 col_set_str(pinfo
->cinfo
, COL_RES_DL_SRC
, "MS");
115 switch (pinfo
->pseudo_header
->gsm_um
.channel
) {
116 case GSM_UM_CHANNEL_BCCH
:
117 case GSM_UM_CHANNEL_CCCH
:
118 case GSM_UM_CHANNEL_PCH
:
119 case GSM_UM_CHANNEL_AGCH
:
120 col_set_str(pinfo
->cinfo
, COL_RES_DL_DST
, "Broadcast");
123 col_set_str(pinfo
->cinfo
, COL_RES_DL_DST
, "MS");
126 col_set_str(pinfo
->cinfo
, COL_RES_DL_SRC
, "BTS");
132 ti
= proto_tree_add_item(tree
, proto_gsm_um
, tvb
, 0, 0, ENC_NA
);
133 gsm_um_tree
= proto_item_add_subtree(ti
, ett_gsm_um
);
135 switch( pinfo
->pseudo_header
->gsm_um
.channel
) {
136 case GSM_UM_CHANNEL_BCCH
: channel
= "BCCH"; break;
137 case GSM_UM_CHANNEL_CCCH
: channel
= "CCCH"; break;
138 case GSM_UM_CHANNEL_PCH
: channel
= "PCH"; break;
139 case GSM_UM_CHANNEL_AGCH
: channel
= "AGCH"; break;
140 case GSM_UM_CHANNEL_SACCH
: channel
= "SACCH"; break;
141 case GSM_UM_CHANNEL_FACCH
: channel
= "FACCH"; break;
142 case GSM_UM_CHANNEL_SDCCH
: channel
= "SDCCH"; break;
143 default: channel
= "Unknown"; break;
146 if( pinfo
->pseudo_header
->gsm_um
.uplink
) {
147 proto_tree_add_string(gsm_um_tree
, hf_gsm_um_direction
, tvb
, 0, 0, "Uplink");
150 proto_tree_add_string(gsm_um_tree
, hf_gsm_um_direction
, tvb
, 0, 0, "Downlink");
153 proto_tree_add_string(gsm_um_tree
, hf_gsm_um_channel
, tvb
, 0, 0, channel
);
155 /* Show the other fields, if we have them (ie. downlink, BTS->MS) */
156 if( !pinfo
->pseudo_header
->gsm_um
.uplink
) {
158 unsigned downlink
, uplink
;
160 decode_arfcn(pinfo
->pseudo_header
->gsm_um
.arfcn
, &band
, &uplink
, &downlink
);
162 proto_tree_add_uint(gsm_um_tree
, hf_gsm_um_arfcn
, tvb
, 0, 0,
163 pinfo
->pseudo_header
->gsm_um
.arfcn
);
164 proto_tree_add_string(gsm_um_tree
, hf_gsm_um_band
, tvb
, 0, 0,
166 proto_tree_add_uint_format_value(gsm_um_tree
, hf_gsm_um_frequency
, tvb
, 0, 0,
167 downlink
, "%u.%03uMHz", downlink
/ 1000, downlink
% 1000);
168 proto_tree_add_uint(gsm_um_tree
, hf_gsm_um_bsic
, tvb
, 0, 0,
169 pinfo
->pseudo_header
->gsm_um
.bsic
);
170 proto_tree_add_uint(gsm_um_tree
, hf_gsm_um_frame
, tvb
, 0, 0,
171 pinfo
->pseudo_header
->gsm_um
.tdma_frame
);
172 proto_tree_add_uint(gsm_um_tree
, hf_gsm_um_error
, tvb
, 0, 0,
173 pinfo
->pseudo_header
->gsm_um
.error
);
174 proto_tree_add_uint(gsm_um_tree
, hf_gsm_um_timeshift
, tvb
, 0, 0,
175 pinfo
->pseudo_header
->gsm_um
.timeshift
);
179 /* TODO: If CCCH downlink could work out of PCH or AGCH by peeking at next bytes, uplink is RACH */
181 switch( pinfo
->pseudo_header
->gsm_um
.channel
) {
182 case GSM_UM_CHANNEL_BCCH
:
183 case GSM_UM_CHANNEL_CCCH
:
184 case GSM_UM_CHANNEL_PCH
:
185 case GSM_UM_CHANNEL_AGCH
:
186 if( !pinfo
->pseudo_header
->gsm_um
.uplink
) {
188 uint8_t pseudo_len
, len_left
, len_byte
;
190 len_left
= tvb_reported_length(tvb
);
191 len_byte
= tvb_get_uint8(tvb
, 0);
192 pseudo_len
= len_byte
>> 2;
193 next_tvb
= tvb_new_subset_length_caplen(tvb
, 1, MIN(len_left
, pseudo_len
), -1);
196 proto_tree_add_uint(gsm_um_tree
, hf_gsm_um_l2_pseudo_len
, tvb
, 0, 1,
200 /* Only dissect non-empty frames */
201 if( tvb_reported_length(next_tvb
) ) {
202 call_dissector(dtap_handle
, next_tvb
, pinfo
, tree
);
206 /* Either RACH, or something invalid */
207 call_data_dissector(tvb
, pinfo
, tree
);
210 case GSM_UM_CHANNEL_SACCH
:
211 case GSM_UM_CHANNEL_FACCH
:
212 case GSM_UM_CHANNEL_SDCCH
:
213 call_dissector(lapdm_handle
, tvb
, pinfo
, tree
);
216 call_data_dissector(tvb
, pinfo
, tree
);
219 return tvb_captured_length(tvb
);
223 proto_register_gsm_um(void)
225 static hf_register_info hf
[] = {
226 { &hf_gsm_um_direction
,
227 { "Direction", "gsm_um.direction", FT_STRINGZ
, BASE_NONE
,
228 NULL
, 0x0, NULL
, HFILL
}},
230 { &hf_gsm_um_channel
,
231 { "Channel", "gsm_um.channel", FT_STRINGZ
, BASE_NONE
,
232 NULL
, 0x0, NULL
, HFILL
}},
235 { "BSIC", "gsm_um.bsic", FT_UINT8
, BASE_DEC
,
236 NULL
, 0x0, "Base station identity code", HFILL
}},
239 { "ARFCN", "gsm_um.arfcn", FT_UINT16
, BASE_DEC
,
240 NULL
, 0x0, "Absolute radio frequency channel number", HFILL
}},
243 { "Band", "gsm_um.band", FT_STRING
, BASE_NONE
,
244 NULL
, 0x0, NULL
, HFILL
}},
246 { &hf_gsm_um_frequency
,
247 { "Frequency", "gsm_um.frequency", FT_UINT32
, BASE_DEC
,
248 NULL
, 0x0, NULL
, HFILL
}},
251 { "TDMA Frame", "gsm_um.frame", FT_UINT32
, BASE_DEC
,
252 NULL
, 0x0, NULL
, HFILL
}},
255 { "Error", "gsm_um.error", FT_UINT8
, BASE_DEC
,
256 NULL
, 0x0, NULL
, HFILL
}},
258 { &hf_gsm_um_timeshift
,
259 { "Timeshift", "gsm_um.timeshift", FT_UINT16
, BASE_DEC
,
260 NULL
, 0x0, NULL
, HFILL
}},
262 { &hf_gsm_um_l2_pseudo_len
,
263 { "L2 Pseudo Length", "gsm_um.l2_pseudo_len", FT_UINT8
, BASE_DEC
,
264 NULL
, GSM_UM_L2_PSEUDO_LEN
, NULL
, HFILL
}}
267 static int *ett
[] = {
270 module_t
*gsm_um_module
;
272 proto_gsm_um
= proto_register_protocol("GSM Um Interface", "GSM Um", "gsm_um");
273 proto_register_field_array(proto_gsm_um
, hf
, array_length(hf
));
274 proto_register_subtree_array(ett
, array_length(ett
));
276 gsm_um_module
= prefs_register_protocol(proto_gsm_um
, NULL
);
277 prefs_register_bool_preference(gsm_um_module
, "dcs1800",
278 "Treat ARFCN 512-810 as DCS 1800 rather than PCS 1900",
279 "Treat ARFCN 512-810 as DCS 1800 rather than PCS 1900",
282 gsm_um_handle
= register_dissector("gsm_um", dissect_gsm_um
, proto_gsm_um
);
286 proto_reg_handoff_gsm_um(void)
288 lapdm_handle
= find_dissector_add_dependency("lapdm", proto_gsm_um
);
289 dtap_handle
= find_dissector_add_dependency("gsm_a_dtap", proto_gsm_um
);
291 dissector_add_uint("wtap_encap", WTAP_ENCAP_GSM_UM
, gsm_um_handle
);
295 * Editor modelines - https://www.wireshark.org/tools/modelines.html
300 * indent-tabs-mode: t
303 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
304 * :indentSize=8:tabSize=8:noTabs=false: