2 * Routines for GSM Um packet disassembly
3 * Duncan Salerno <duncan.salerno@googlemail.com>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <epan/packet.h>
31 #include <epan/prefs.h>
32 #include <epan/circuit.h>
34 static int proto_gsm_um
= -1;
35 static int hf_gsm_um_direction
= -1;
36 static int hf_gsm_um_channel
= -1;
37 static int hf_gsm_um_bsic
= -1;
38 static int hf_gsm_um_arfcn
= -1;
39 static int hf_gsm_um_frame
= -1;
40 static int hf_gsm_um_error
= -1;
41 static int hf_gsm_um_timeshift
= -1;
42 static int hf_gsm_um_l2_pseudo_len
= -1;
44 static gint ett_gsm_um
= -1;
46 static dissector_handle_t lapdm_handle
;
47 static dissector_handle_t dtap_handle
;
48 static dissector_handle_t data_handle
;
50 static gboolean dcs1800_gsm
= TRUE
;
52 #define GSM_UM_L2_PSEUDO_LEN 0xfc
56 decode_arfcn(guint16 arfcn
, const char **band
, guint
*uplink
, guint
*downlink
)
58 /* Decode ARFCN to frequency using GSM 05.05 */
59 if( arfcn
>= 1 && arfcn
<= 124 ) {
61 *uplink
= 890000 + 200 * arfcn
;
62 *downlink
= *uplink
+ 45000;
64 else if( arfcn
== 0 ) {
66 *uplink
= 890000 + 200 * arfcn
;
67 *downlink
= *uplink
+ 45000;
69 else if( arfcn
>= 975 && arfcn
<= 1023 ) {
71 *uplink
= 890000 + 200 * (arfcn
- 1024);
72 *downlink
= *uplink
+ 45000;
74 else if( arfcn
>= 955 && arfcn
<= 1023 ) {
76 *uplink
= 890000 + 200 * (arfcn
- 1024);
77 *downlink
= *uplink
+ 45000;
79 else if( arfcn
>= 512 && arfcn
<= 885 && dcs1800_gsm
) {
81 *uplink
= 1710200 + 200 * (arfcn
- 512);
82 *downlink
= *uplink
+ 95000;
84 else if( arfcn
>= 512 && arfcn
<= 810 && !dcs1800_gsm
) {
86 *uplink
= 1850200 + 200 * (arfcn
- 512);
87 *downlink
= *uplink
+ 80000;
89 else if( arfcn
>= 259 && arfcn
<= 293 ) {
91 *uplink
= 450600 + 200 * (arfcn
- 259);
92 *downlink
= *uplink
+ 10000;
94 else if( arfcn
>= 306 && arfcn
<= 340 ) {
96 *uplink
= 479000 + 200 * (arfcn
- 306);
97 *downlink
= *uplink
+ 10000;
99 else if( arfcn
>= 128 && arfcn
<= 251 ) {
101 *uplink
= 824200 + 200 * (arfcn
- 128);
102 *downlink
= *uplink
+ 45000;
106 *uplink
= *downlink
= 0;
112 dissect_gsm_um(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
114 proto_tree
*gsm_um_tree
= NULL
;
117 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "GSM Um");
119 if (pinfo
->pseudo_header
->gsm_um
.uplink
) {
120 col_set_str(pinfo
->cinfo
, COL_RES_DL_DST
, "BTS");
121 col_set_str(pinfo
->cinfo
, COL_RES_DL_SRC
, "MS");
124 switch (pinfo
->pseudo_header
->gsm_um
.channel
) {
125 case GSM_UM_CHANNEL_BCCH
:
126 case GSM_UM_CHANNEL_CCCH
:
127 case GSM_UM_CHANNEL_PCH
:
128 case GSM_UM_CHANNEL_AGCH
:
129 col_set_str(pinfo
->cinfo
, COL_RES_DL_DST
, "Broadcast");
132 col_set_str(pinfo
->cinfo
, COL_RES_DL_DST
, "MS");
135 col_set_str(pinfo
->cinfo
, COL_RES_DL_SRC
, "BTS");
141 ti
= proto_tree_add_item(tree
, proto_gsm_um
, tvb
, 0, 0, ENC_NA
);
142 gsm_um_tree
= proto_item_add_subtree(ti
, ett_gsm_um
);
144 switch( pinfo
->pseudo_header
->gsm_um
.channel
) {
145 case GSM_UM_CHANNEL_BCCH
: channel
= "BCCH"; break;
146 case GSM_UM_CHANNEL_CCCH
: channel
= "CCCH"; break;
147 case GSM_UM_CHANNEL_PCH
: channel
= "PCH"; break;
148 case GSM_UM_CHANNEL_AGCH
: channel
= "AGCH"; break;
149 case GSM_UM_CHANNEL_SACCH
: channel
= "SACCH"; break;
150 case GSM_UM_CHANNEL_FACCH
: channel
= "FACCH"; break;
151 case GSM_UM_CHANNEL_SDCCH
: channel
= "SDCCH"; break;
152 default: channel
= "Unknown"; break;
155 if( pinfo
->pseudo_header
->gsm_um
.uplink
) {
156 proto_tree_add_string(gsm_um_tree
, hf_gsm_um_direction
, tvb
, 0, 0, "Uplink");
159 proto_tree_add_string(gsm_um_tree
, hf_gsm_um_direction
, tvb
, 0, 0, "Downlink");
162 proto_tree_add_string(gsm_um_tree
, hf_gsm_um_channel
, tvb
, 0, 0, channel
);
164 /* Show the other fields, if we have them (ie. downlink, BTS->MS) */
165 if( !pinfo
->pseudo_header
->gsm_um
.uplink
) {
167 guint downlink
, uplink
;
169 decode_arfcn(pinfo
->pseudo_header
->gsm_um
.arfcn
, &band
, &uplink
, &downlink
);
171 proto_tree_add_uint(gsm_um_tree
, hf_gsm_um_arfcn
, tvb
, 0, 0,
172 pinfo
->pseudo_header
->gsm_um
.arfcn
);
173 proto_tree_add_text(gsm_um_tree
, tvb
, 0, 0,
174 "Band: %s, Frequency: %u.%03uMHz", band
,
175 downlink
/ 1000, downlink
% 1000);
176 proto_tree_add_uint(gsm_um_tree
, hf_gsm_um_bsic
, tvb
, 0, 0,
177 pinfo
->pseudo_header
->gsm_um
.bsic
);
178 proto_tree_add_uint(gsm_um_tree
, hf_gsm_um_frame
, tvb
, 0, 0,
179 pinfo
->pseudo_header
->gsm_um
.tdma_frame
);
180 proto_tree_add_uint(gsm_um_tree
, hf_gsm_um_error
, tvb
, 0, 0,
181 pinfo
->pseudo_header
->gsm_um
.error
);
182 proto_tree_add_uint(gsm_um_tree
, hf_gsm_um_timeshift
, tvb
, 0, 0,
183 pinfo
->pseudo_header
->gsm_um
.timeshift
);
187 /* TODO: If CCCH downlink could work out of PCH or AGCH by peeking at next bytes, uplink is RACH */
189 switch( pinfo
->pseudo_header
->gsm_um
.channel
) {
190 case GSM_UM_CHANNEL_BCCH
:
191 case GSM_UM_CHANNEL_CCCH
:
192 case GSM_UM_CHANNEL_PCH
:
193 case GSM_UM_CHANNEL_AGCH
:
194 if( !pinfo
->pseudo_header
->gsm_um
.uplink
) {
196 guint8 pseudo_len
, len_left
, len_byte
;
198 len_left
= tvb_length(tvb
);
199 len_byte
= tvb_get_guint8(tvb
, 0);
200 pseudo_len
= len_byte
>> 2;
201 next_tvb
= tvb_new_subset(tvb
, 1, MIN(len_left
, pseudo_len
), -1);
204 proto_tree_add_uint(gsm_um_tree
, hf_gsm_um_l2_pseudo_len
, tvb
, 0, 1,
208 /* Only dissect non-empty frames */
209 if( tvb_length(next_tvb
) ) {
210 call_dissector(dtap_handle
, next_tvb
, pinfo
, tree
);
214 /* Either RACH, or something invalid */
215 call_dissector(data_handle
, tvb
, pinfo
, tree
);
218 case GSM_UM_CHANNEL_SACCH
:
219 case GSM_UM_CHANNEL_FACCH
:
220 case GSM_UM_CHANNEL_SDCCH
:
221 call_dissector(lapdm_handle
, tvb
, pinfo
, tree
);
224 call_dissector(data_handle
, tvb
, pinfo
, tree
);
230 proto_register_gsm_um(void)
232 static hf_register_info hf
[] = {
233 { &hf_gsm_um_direction
,
234 { "Direction", "gsm_um.direction", FT_STRINGZ
, BASE_NONE
,
235 NULL
, 0x0, NULL
, HFILL
}},
237 { &hf_gsm_um_channel
,
238 { "Channel", "gsm_um.channel", FT_STRINGZ
, BASE_NONE
,
239 NULL
, 0x0, NULL
, HFILL
}},
242 { "BSIC", "gsm_um.bsic", FT_UINT8
, BASE_DEC
,
243 NULL
, 0x0, "Base station identity code", HFILL
}},
246 { "ARFCN", "gsm_um.arfcn", FT_UINT16
, BASE_DEC
,
247 NULL
, 0x0, "Absolute radio frequency channel number", HFILL
}},
250 { "TDMA Frame", "gsm_um.frame", FT_UINT32
, BASE_DEC
,
251 NULL
, 0x0, NULL
, HFILL
}},
254 { "Error", "gsm_um.error", FT_UINT8
, BASE_DEC
,
255 NULL
, 0x0, NULL
, HFILL
}},
257 { &hf_gsm_um_timeshift
,
258 { "Timeshift", "gsm_um.timeshift", FT_UINT16
, BASE_DEC
,
259 NULL
, 0x0, NULL
, HFILL
}},
261 { &hf_gsm_um_l2_pseudo_len
,
262 { "L2 Pseudo Length", "gsm_um.l2_pseudo_len", FT_UINT8
, BASE_DEC
,
263 NULL
, GSM_UM_L2_PSEUDO_LEN
, NULL
, HFILL
}}
266 static gint
*ett
[] = {
269 module_t
*gsm_um_module
;
271 proto_gsm_um
= proto_register_protocol("GSM Um Interface", "GSM Um", "gsm_um");
272 proto_register_field_array(proto_gsm_um
, hf
, array_length(hf
));
273 proto_register_subtree_array(ett
, array_length(ett
));
275 gsm_um_module
= prefs_register_protocol(proto_gsm_um
, NULL
);
276 prefs_register_bool_preference(gsm_um_module
, "dcs1800",
277 "Treat ARFCN 512-810 as DCS 1800 rather than PCS 1900",
278 "Treat ARFCN 512-810 as DCS 1800 rather than PCS 1900",
284 proto_reg_handoff_gsm_um(void)
286 dissector_handle_t gsm_um_handle
;
288 lapdm_handle
= find_dissector("lapdm");
289 dtap_handle
= find_dissector("gsm_a_dtap");
290 data_handle
= find_dissector("data");
292 gsm_um_handle
= create_dissector_handle(dissect_gsm_um
, proto_gsm_um
);
294 dissector_add_uint("wtap_encap", WTAP_ENCAP_GSM_UM
, gsm_um_handle
);