epan/dissectors/pidl/samr/samr.cnf cnf_dissect_lsa_BinaryString => lsarpc_dissect_str...
[wireshark-sm.git] / epan / dissectors / packet-ehdlc.c
blob1eb8a485fcf3498ab92371266bce8b8d68dd92ba
1 /* packet-ehdlc.c
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
17 #include "config.h"
19 #include <epan/packet.h>
20 #include <epan/xdlc.h>
21 #include <epan/tfs.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 = {
64 NULL,
65 NULL,
66 &hf_ehdlc_p,
67 &hf_ehdlc_f,
68 NULL,
69 &hf_ehdlc_u_modifier_cmd,
70 &hf_ehdlc_u_modifier_resp,
71 NULL,
72 &hf_ehdlc_ftype_s_u
75 /* Used only for I and S frames */
76 static const xdlc_cf_items ehdlc_cf_items_ext = {
77 &hf_ehdlc_n_r,
78 &hf_ehdlc_n_s,
79 &hf_ehdlc_p_ext,
80 &hf_ehdlc_f_ext,
81 &hf_ehdlc_s_ftype,
82 NULL,
83 NULL,
84 &hf_ehdlc_ftype_i,
85 &hf_ehdlc_ftype_s_u_ext,
88 /* Initialize the subtree pointers */
89 static int ett_ehdlc;
90 static int ett_ehdlc_xid;
91 static int ett_ehdlc_control;
93 enum {
94 SUB_RSL,
95 SUB_OML,
96 SUB_TFP,
97 SUB_PGSL,
98 SUB_DATA,
100 SUB_MAX
103 /* Determine TEI from Compressed TEI */
104 static uint8_t tei_from_ctei(uint8_t ctei)
106 if (ctei < 12)
107 return ctei;
108 else
109 return 60 + (ctei - 12);
112 static uint8_t c_r_from_csapi(uint8_t csapi)
114 switch (csapi) {
115 case 1:
116 case 6:
117 return 1;
118 default:
119 return 0;
123 static uint8_t sapi_from_csapi(uint8_t csapi)
125 switch (csapi) {
126 case 0:
127 case 1: /* RSL */
128 return 0;
129 case 2: /* TFP */
130 return 10;
131 case 3: /* TFP */
132 return 11;
133 case 4: /* P-GSL */
134 return 12;
135 case 5:
136 case 6: /* OML */
137 return 62;
138 case 7:
139 default:
140 /* error! */
141 return 0;
145 static dissector_handle_t sub_handles[SUB_MAX];
147 static int
148 dissect_ehdlc_xid(proto_tree *tree, tvbuff_t *tvb, unsigned base_offset, unsigned len)
150 unsigned offset = base_offset;
151 proto_item *ti;
152 proto_tree *xid_tree;
154 /* XID is formatted like ISO 8885, typically we see
155 * something like
156 * 82 format identifier
157 * 80 group identifier
158 * 00 09 length
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);
169 offset += 2;
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++);
175 switch (iei) {
176 case 0x07:
177 proto_tree_add_item(xid_tree, hf_ehdlc_xid_win_tx, tvb,
178 offset, ie_len, ENC_NA);
179 break;
180 case 0x08:
181 proto_tree_add_item(xid_tree, hf_ehdlc_xid_win_rx, tvb,
182 offset, ie_len, ENC_NA);
183 break;
184 case 0x09:
185 proto_tree_add_item(xid_tree, hf_ehdlc_xid_ack_tmr_ms, tvb,
186 offset, ie_len, ENC_NA);
187 break;
189 offset += ie_len;
192 return offset - base_offset;
195 /* Code to actually dissect the packets */
196 static int
197 dissect_ehdlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
199 int offset = 4;
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;
207 uint16_t len, hdr2;
208 uint8_t csapi, ctei, sapi, tei, c_r;
209 tvbuff_t *next_tvb;
210 uint16_t control;
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);
215 len = hdr2 & 0x1FF;
216 csapi = hdr2 >> 13;
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);
226 if (tree) {
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) {
252 /* Voice TRAU */
253 next_tvb = tvb_new_subset_length(tvb, offset+2, len-2);
254 call_dissector(sub_handles[SUB_TFP], next_tvb, pinfo, tree);
255 offset += len;
256 continue;
257 } else if (sapi == 12) {
258 /* GPRS TRAU */
259 next_tvb = tvb_new_subset_length(tvb, offset+2, len-2);
260 call_dissector(sub_handles[SUB_PGSL], next_tvb, pinfo, tree);
261 offset += len;
262 continue;
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,
272 len-header_length);
274 switch (sapi) {
275 case 0:
276 /* len == 4 seems to be some kind of ACK */
277 if (len <= 4)
278 break;
279 call_dissector(sub_handles[SUB_RSL], next_tvb, pinfo, tree);
280 break;
281 case 62:
282 /* len == 4 seems to be some kind of ACK */
283 if (len <= 4)
284 break;
285 call_dissector(sub_handles[SUB_OML], next_tvb, pinfo, tree);
286 break;
287 default:
288 call_dissector(sub_handles[SUB_DATA], next_tvb, pinfo, tree);
289 break;
291 } else if (control == (XDLC_U | XDLC_XID)) {
292 dissect_ehdlc_xid(ehdlc_tree, tvb, offset+header_length,
293 len-header_length);
296 if (len == 0)
297 len = 1;
298 offset += len;
300 return tvb_captured_length(tvb);
303 void
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 }
312 { &hf_ehdlc_csapi,
313 { "Compressed SAPI", "ehdlc.csapi",
314 FT_UINT8, BASE_DEC, NULL, 0xE0,
315 NULL, HFILL}
317 { &hf_ehdlc_ctei,
318 { "Compressed TEI", "ehdlc.ctei",
319 FT_UINT8, BASE_DEC, NULL, 0x1E,
320 NULL, HFILL}
322 { &hf_ehdlc_sapi,
323 { "SAPI", "ehdlc.sapi",
324 FT_UINT8, BASE_DEC, NULL, 0,
325 NULL, HFILL }
327 { &hf_ehdlc_tei,
328 { "TEI", "ehdlc.tei",
329 FT_UINT8, BASE_DEC, NULL, 0,
330 NULL, HFILL }
332 { &hf_ehdlc_c_r,
333 { "C/R", "ehdlc.c_r",
334 FT_UINT8, BASE_DEC, NULL, 0,
335 NULL, HFILL }
338 { &hf_ehdlc_xid_payload,
339 { "XID Payload", "ehdlc.xid_payload",
340 FT_BYTES, BASE_NONE, NULL, 0,
341 NULL, HFILL }
343 { &hf_ehdlc_xid_win_tx,
344 { "Transmit Window", "ehdlc.xid.win_tx",
345 FT_UINT8, BASE_DEC, NULL, 0,
346 NULL, HFILL }
348 { &hf_ehdlc_xid_win_rx,
349 { "Receive Window", "ehdlc.xid.win_rx",
350 FT_UINT8, BASE_DEC, NULL, 0,
351 NULL, HFILL }
353 { &hf_ehdlc_xid_ack_tmr_ms,
354 { "Timer (ms)", "ehdlc.xid.ack_tmr_ms",
355 FT_UINT8, BASE_DEC, NULL, 0,
356 NULL, HFILL }
358 { &hf_ehdlc_xid_format_id,
359 { "Format Identifier", "ehdlc.xid.format_id",
360 FT_UINT8, BASE_HEX, NULL, 0,
361 NULL, HFILL }
363 { &hf_ehdlc_xid_group_id,
364 { "Group Identifier", "ehdlc.xid.group_id",
365 FT_UINT8, BASE_HEX, NULL, 0,
366 NULL, HFILL }
368 { &hf_ehdlc_xid_len,
369 { "XID Length", "ehdlc.xid.len",
370 FT_UINT16, BASE_DEC, NULL, 0,
371 NULL, HFILL }
373 { &hf_ehdlc_control,
374 { "Control Field", "ehdlc.control",
375 FT_UINT16, BASE_HEX, NULL, 0,
376 NULL, HFILL }
378 { &hf_ehdlc_n_r,
379 { "N(R)", "ehdlc.control.n_r",
380 FT_UINT16, BASE_DEC, NULL, XDLC_N_R_EXT_MASK,
381 NULL, HFILL }
383 { &hf_ehdlc_n_s,
384 { "N(S)", "ehdlc.control.n_s",
385 FT_UINT16, BASE_DEC, NULL, XDLC_N_S_EXT_MASK,
386 NULL, HFILL }
388 { &hf_ehdlc_p,
389 { "Poll", "ehdlc.control.p",
390 FT_BOOLEAN, 8, TFS(&tfs_set_notset), XDLC_P_F,
391 NULL, HFILL }
393 { &hf_ehdlc_p_ext,
394 { "Poll", "ehdlc.control.p",
395 FT_BOOLEAN, 16, TFS(&tfs_set_notset), XDLC_P_F_EXT,
396 NULL, HFILL }
398 { &hf_ehdlc_f,
399 { "Final", "ehdlc.control.f",
400 FT_BOOLEAN, 8, TFS(&tfs_set_notset), XDLC_P_F,
401 NULL, HFILL }
403 { &hf_ehdlc_f_ext,
404 { "Final", "ehdlc.control.f",
405 FT_BOOLEAN, 16, TFS(&tfs_set_notset), XDLC_P_F_EXT,
406 NULL, HFILL }
408 { &hf_ehdlc_s_ftype,
409 { "Supervisory frame type", "ehdlc.control.s_ftype",
410 FT_UINT16, BASE_HEX, VALS(stype_vals), XDLC_S_FTYPE_MASK,
411 NULL, HFILL }
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,
416 NULL, HFILL }
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,
421 NULL, HFILL }
423 { &hf_ehdlc_ftype_i,
424 { "Frame Type", "ehdlc.control.ftype",
425 FT_UINT16, BASE_HEX, VALS(ftype_vals), XDLC_I_MASK,
426 NULL, HFILL }
428 { &hf_ehdlc_ftype_s_u,
429 { "Frame Type", "ehdlc.control.ftype",
430 FT_UINT8, BASE_HEX, VALS(ftype_vals), XDLC_S_U_MASK,
431 NULL, HFILL }
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,
436 NULL, HFILL }
440 static int *ett[] = {
441 &ett_ehdlc,
442 &ett_ehdlc_xid,
443 &ett_ehdlc_control,
446 proto_ehdlc =
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);
456 void
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
471 * Local variables:
472 * c-basic-offset: 8
473 * tab-width: 8
474 * indent-tabs-mode: t
475 * End:
477 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
478 * :indentSize=8:tabSize=8:noTabs=false: