2 * Routines for packet dissection of Ericsson HDLC as used in A-bis over IP
3 * Copyright 2010-2012, 2016 by Harald Welte <laforge@gnumonks.org>
5 * This code is based on pure educational guesses while looking at protocol
6 * traces, as there is no publicly available protocol description by Ericsson.
7 * Even the name is a guess, since it looks quite a bit like HDLC and is used
8 * by Ericsson, I called it EHDLC.
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
14 * SPDX-License-Identifier: GPL-2.0-or-later
19 #include <epan/packet.h>
20 #include <epan/xdlc.h>
23 void proto_register_ehdlc(void);
24 void proto_reg_handoff_ehdlc(void);
26 /* Initialize the protocol and registered fields */
27 static int proto_ehdlc
;
29 static int hf_ehdlc_data_len
;
30 static int hf_ehdlc_csapi
;
31 static int hf_ehdlc_ctei
;
33 static int hf_ehdlc_sapi
;
34 static int hf_ehdlc_tei
;
35 static int hf_ehdlc_c_r
;
37 static int hf_ehdlc_xid_payload
;
38 static int hf_ehdlc_xid_win_tx
;
39 static int hf_ehdlc_xid_win_rx
;
40 static int hf_ehdlc_xid_ack_tmr_ms
;
41 static int hf_ehdlc_xid_format_id
;
42 static int hf_ehdlc_xid_group_id
;
43 static int hf_ehdlc_xid_len
;
44 static int hf_ehdlc_control
;
46 static int hf_ehdlc_p
;
47 static int hf_ehdlc_f
;
48 static int hf_ehdlc_u_modifier_cmd
;
49 static int hf_ehdlc_u_modifier_resp
;
50 static int hf_ehdlc_ftype_s_u
;
52 static int hf_ehdlc_n_r
;
53 static int hf_ehdlc_n_s
;
54 static int hf_ehdlc_p_ext
;
55 static int hf_ehdlc_f_ext
;
56 static int hf_ehdlc_s_ftype
;
57 static int hf_ehdlc_ftype_i
;
58 static int hf_ehdlc_ftype_s_u_ext
;
60 static dissector_handle_t ehdlc_handle
;
62 /* Used only for U frames */
63 static const xdlc_cf_items ehdlc_cf_items
= {
69 &hf_ehdlc_u_modifier_cmd
,
70 &hf_ehdlc_u_modifier_resp
,
75 /* Used only for I and S frames */
76 static const xdlc_cf_items ehdlc_cf_items_ext
= {
85 &hf_ehdlc_ftype_s_u_ext
,
88 /* Initialize the subtree pointers */
90 static int ett_ehdlc_xid
;
91 static int ett_ehdlc_control
;
103 /* Determine TEI from Compressed TEI */
104 static uint8_t tei_from_ctei(uint8_t ctei
)
109 return 60 + (ctei
- 12);
112 static uint8_t c_r_from_csapi(uint8_t csapi
)
123 static uint8_t sapi_from_csapi(uint8_t csapi
)
145 static dissector_handle_t sub_handles
[SUB_MAX
];
148 dissect_ehdlc_xid(proto_tree
*tree
, tvbuff_t
*tvb
, unsigned base_offset
, unsigned len
)
150 unsigned offset
= base_offset
;
152 proto_tree
*xid_tree
;
154 /* XID is formatted like ISO 8885, typically we see
156 * 82 format identifier
157 * 80 group identifier
159 * 07 01 05 Window Size Tx
160 * 09 01 04 Ack Timer (msec)
161 * 08 01 05 Window Size Rx */
162 ti
= proto_tree_add_item(tree
, hf_ehdlc_xid_payload
,
163 tvb
, offset
, len
, ENC_NA
);
164 xid_tree
= proto_item_add_subtree(ti
, ett_ehdlc_xid
);
166 proto_tree_add_item(xid_tree
, hf_ehdlc_xid_format_id
, tvb
, offset
++, 1, ENC_NA
);
167 proto_tree_add_item(xid_tree
, hf_ehdlc_xid_group_id
, tvb
, offset
++, 1, ENC_NA
);
168 proto_tree_add_item(xid_tree
, hf_ehdlc_xid_len
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
171 while (tvb_reported_length_remaining(tvb
, offset
) >= 2) {
172 uint8_t iei
= tvb_get_uint8(tvb
, offset
++);
173 uint8_t ie_len
= tvb_get_uint8(tvb
, offset
++);
177 proto_tree_add_item(xid_tree
, hf_ehdlc_xid_win_tx
, tvb
,
178 offset
, ie_len
, ENC_NA
);
181 proto_tree_add_item(xid_tree
, hf_ehdlc_xid_win_rx
, tvb
,
182 offset
, ie_len
, ENC_NA
);
185 proto_tree_add_item(xid_tree
, hf_ehdlc_xid_ack_tmr_ms
, tvb
,
186 offset
, ie_len
, ENC_NA
);
192 return offset
- base_offset
;
195 /* Code to actually dissect the packets */
197 dissect_ehdlc(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
201 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "EHDLC");
202 col_clear(pinfo
->cinfo
, COL_INFO
);
204 while (tvb_reported_length_remaining(tvb
, offset
) > 0) {
205 proto_item
*ti
= NULL
;
206 proto_tree
*ehdlc_tree
= NULL
;
208 uint8_t csapi
, ctei
, sapi
, tei
, c_r
;
211 bool is_response
= false, is_extended
= true;
212 int header_length
= 2; /* Address + Length field */
214 hdr2
= tvb_get_uint16(tvb
, offset
, ENC_BIG_ENDIAN
);
217 sapi
= sapi_from_csapi(csapi
);
218 c_r
= c_r_from_csapi(csapi
);
219 ctei
= (hdr2
>> 9) & 0xF;
220 tei
= tei_from_ctei(ctei
);
222 /* Add TEI to INFO column */
223 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " | TEI:%02u | ", tei
);
224 col_set_fence(pinfo
->cinfo
, COL_INFO
);
227 /* Use MIN(...,...) in the following to prevent a premature */
228 /* exception before we try to dissect whatever is available. */
229 ti
= proto_tree_add_protocol_format(tree
, proto_ehdlc
,
230 tvb
, offset
, MIN(len
, tvb_captured_length_remaining(tvb
,offset
)),
231 "Ericsson HDLC protocol");
232 ehdlc_tree
= proto_item_add_subtree(ti
, ett_ehdlc
);
234 proto_tree_add_item(ehdlc_tree
, hf_ehdlc_csapi
,
235 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
236 proto_tree_add_item(ehdlc_tree
, hf_ehdlc_ctei
,
237 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
238 ti
= proto_tree_add_uint(ehdlc_tree
, hf_ehdlc_c_r
,
239 tvb
, offset
, 1, c_r
);
240 proto_item_set_generated(ti
);
241 ti
= proto_tree_add_uint(ehdlc_tree
, hf_ehdlc_sapi
,
242 tvb
, offset
, 1, sapi
);
243 proto_item_set_generated(ti
);
244 ti
= proto_tree_add_uint(ehdlc_tree
, hf_ehdlc_tei
,
245 tvb
, offset
, 1, tei
);
246 proto_item_set_generated(ti
);
247 proto_tree_add_item(ehdlc_tree
, hf_ehdlc_data_len
,
248 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
251 if (sapi
== 10 || sapi
== 11) {
253 next_tvb
= tvb_new_subset_length(tvb
, offset
+2, len
-2);
254 call_dissector(sub_handles
[SUB_TFP
], next_tvb
, pinfo
, tree
);
257 } else if (sapi
== 12) {
259 next_tvb
= tvb_new_subset_length(tvb
, offset
+2, len
-2);
260 call_dissector(sub_handles
[SUB_PGSL
], next_tvb
, pinfo
, tree
);
265 control
= dissect_xdlc_control(tvb
, offset
+2, pinfo
, ehdlc_tree
, hf_ehdlc_control
,
266 ett_ehdlc_control
, &ehdlc_cf_items
, &ehdlc_cf_items_ext
,
267 NULL
, NULL
, is_response
, is_extended
, false);
268 header_length
+= XDLC_CONTROL_LEN(control
, is_extended
);
270 if (XDLC_IS_INFORMATION(control
)) {
271 next_tvb
= tvb_new_subset_length(tvb
, offset
+header_length
,
276 /* len == 4 seems to be some kind of ACK */
279 call_dissector(sub_handles
[SUB_RSL
], next_tvb
, pinfo
, tree
);
282 /* len == 4 seems to be some kind of ACK */
285 call_dissector(sub_handles
[SUB_OML
], next_tvb
, pinfo
, tree
);
288 call_dissector(sub_handles
[SUB_DATA
], next_tvb
, pinfo
, tree
);
291 } else if (control
== (XDLC_U
| XDLC_XID
)) {
292 dissect_ehdlc_xid(ehdlc_tree
, tvb
, offset
+header_length
,
300 return tvb_captured_length(tvb
);
304 proto_register_ehdlc(void)
306 static hf_register_info hf
[] = {
307 { &hf_ehdlc_data_len
,
308 { "DataLen", "ehdlc.data_len",
309 FT_UINT16
, BASE_DEC
, NULL
, 0x01FF,
310 "The length of the data (in bytes)", HFILL
}
313 { "Compressed SAPI", "ehdlc.csapi",
314 FT_UINT8
, BASE_DEC
, NULL
, 0xE0,
318 { "Compressed TEI", "ehdlc.ctei",
319 FT_UINT8
, BASE_DEC
, NULL
, 0x1E,
323 { "SAPI", "ehdlc.sapi",
324 FT_UINT8
, BASE_DEC
, NULL
, 0,
328 { "TEI", "ehdlc.tei",
329 FT_UINT8
, BASE_DEC
, NULL
, 0,
333 { "C/R", "ehdlc.c_r",
334 FT_UINT8
, BASE_DEC
, NULL
, 0,
338 { &hf_ehdlc_xid_payload
,
339 { "XID Payload", "ehdlc.xid_payload",
340 FT_BYTES
, BASE_NONE
, NULL
, 0,
343 { &hf_ehdlc_xid_win_tx
,
344 { "Transmit Window", "ehdlc.xid.win_tx",
345 FT_UINT8
, BASE_DEC
, NULL
, 0,
348 { &hf_ehdlc_xid_win_rx
,
349 { "Receive Window", "ehdlc.xid.win_rx",
350 FT_UINT8
, BASE_DEC
, NULL
, 0,
353 { &hf_ehdlc_xid_ack_tmr_ms
,
354 { "Timer (ms)", "ehdlc.xid.ack_tmr_ms",
355 FT_UINT8
, BASE_DEC
, NULL
, 0,
358 { &hf_ehdlc_xid_format_id
,
359 { "Format Identifier", "ehdlc.xid.format_id",
360 FT_UINT8
, BASE_HEX
, NULL
, 0,
363 { &hf_ehdlc_xid_group_id
,
364 { "Group Identifier", "ehdlc.xid.group_id",
365 FT_UINT8
, BASE_HEX
, NULL
, 0,
369 { "XID Length", "ehdlc.xid.len",
370 FT_UINT16
, BASE_DEC
, NULL
, 0,
374 { "Control Field", "ehdlc.control",
375 FT_UINT16
, BASE_HEX
, NULL
, 0,
379 { "N(R)", "ehdlc.control.n_r",
380 FT_UINT16
, BASE_DEC
, NULL
, XDLC_N_R_EXT_MASK
,
384 { "N(S)", "ehdlc.control.n_s",
385 FT_UINT16
, BASE_DEC
, NULL
, XDLC_N_S_EXT_MASK
,
389 { "Poll", "ehdlc.control.p",
390 FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), XDLC_P_F
,
394 { "Poll", "ehdlc.control.p",
395 FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), XDLC_P_F_EXT
,
399 { "Final", "ehdlc.control.f",
400 FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), XDLC_P_F
,
404 { "Final", "ehdlc.control.f",
405 FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), XDLC_P_F_EXT
,
409 { "Supervisory frame type", "ehdlc.control.s_ftype",
410 FT_UINT16
, BASE_HEX
, VALS(stype_vals
), XDLC_S_FTYPE_MASK
,
413 { &hf_ehdlc_u_modifier_cmd
,
414 { "Command", "ehdlc.control.u_modifier_cmd",
415 FT_UINT8
, BASE_HEX
, VALS(modifier_vals_cmd
), XDLC_U_MODIFIER_MASK
,
418 { &hf_ehdlc_u_modifier_resp
,
419 { "Response", "ehdlc.control.u_modifier_resp",
420 FT_UINT8
, BASE_HEX
, VALS(modifier_vals_resp
), XDLC_U_MODIFIER_MASK
,
424 { "Frame Type", "ehdlc.control.ftype",
425 FT_UINT16
, BASE_HEX
, VALS(ftype_vals
), XDLC_I_MASK
,
428 { &hf_ehdlc_ftype_s_u
,
429 { "Frame Type", "ehdlc.control.ftype",
430 FT_UINT8
, BASE_HEX
, VALS(ftype_vals
), XDLC_S_U_MASK
,
433 { &hf_ehdlc_ftype_s_u_ext
,
434 { "Frame Type", "ehdlc.control.ftype",
435 FT_UINT16
, BASE_HEX
, VALS(ftype_vals
), XDLC_S_U_MASK
,
440 static int *ett
[] = {
447 proto_register_protocol("Ericsson HDLC",
448 "Ericsson HDLC as used in A-bis over IP", "ehdlc");
450 proto_register_field_array(proto_ehdlc
, hf
, array_length(hf
));
451 proto_register_subtree_array(ett
, array_length(ett
));
453 ehdlc_handle
= register_dissector("ehdlc", dissect_ehdlc
, proto_ehdlc
);
457 proto_reg_handoff_ehdlc(void)
459 sub_handles
[SUB_RSL
] = find_dissector_add_dependency("gsm_abis_rsl", proto_ehdlc
);
460 sub_handles
[SUB_OML
] = find_dissector_add_dependency("gsm_abis_oml", proto_ehdlc
);
461 sub_handles
[SUB_TFP
] = find_dissector_add_dependency("gsm_abis_tfp", proto_ehdlc
);
462 sub_handles
[SUB_PGSL
] = find_dissector_add_dependency("gsm_abis_pgsl", proto_ehdlc
);
463 sub_handles
[SUB_DATA
] = find_dissector("data");
465 dissector_add_for_decode_as("l2tp.pw_type", ehdlc_handle
);
469 * Editor modelines - https://www.wireshark.org/tools/modelines.html
474 * indent-tabs-mode: t
477 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
478 * :indentSize=8:tabSize=8:noTabs=false: