/src/wireshark/epan/xdlc.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* xdlc.c |
2 | | * Routines for use by various SDLC-derived protocols, such as HDLC |
3 | | * and its derivatives LAPB, IEEE 802.2 LLC, etc.. |
4 | | * |
5 | | * Wireshark - Network traffic analyzer |
6 | | * By Gerald Combs <gerald@wireshark.org> |
7 | | * Copyright 1998 Gerald Combs |
8 | | * |
9 | | * SPDX-License-Identifier: GPL-2.0-or-later |
10 | | */ |
11 | | |
12 | | #include "config.h" |
13 | | |
14 | | #include <stdio.h> |
15 | | #include <string.h> |
16 | | |
17 | | #include <glib.h> |
18 | | #include <epan/packet.h> |
19 | | #include <epan/xdlc.h> |
20 | | #include <wsutil/pint.h> |
21 | | |
22 | | const value_string ftype_vals[] = { |
23 | | { XDLC_I, "Information frame" }, |
24 | | { XDLC_S, "Supervisory frame" }, |
25 | | { XDLC_U, "Unnumbered frame" }, |
26 | | { 0, NULL } |
27 | | }; |
28 | | |
29 | | const value_string stype_vals[] = { |
30 | | { XDLC_RR>>2, "Receiver ready" }, |
31 | | { XDLC_RNR>>2, "Receiver not ready" }, |
32 | | { XDLC_REJ>>2, "Reject" }, |
33 | | { XDLC_SREJ>>2, "Selective reject" }, |
34 | | { 0, NULL } |
35 | | }; |
36 | | |
37 | | static const value_string modifier_short_vals_cmd[] = { |
38 | | { XDLC_UI, "UI" }, |
39 | | { XDLC_UP, "UP" }, |
40 | | { XDLC_DISC, "DISC" }, |
41 | | { XDLC_UA, "UA" }, |
42 | | { XDLC_SNRM, "SNRM" }, |
43 | | { XDLC_SNRME, "SNRME" }, |
44 | | { XDLC_TEST, "TEST" }, |
45 | | { XDLC_SIM, "SIM" }, |
46 | | { XDLC_FRMR, "FRMR" }, |
47 | | { XDLC_CFGR, "CFGR" }, |
48 | | { XDLC_SARM, "SARM" }, |
49 | | { XDLC_SABM, "SABM" }, |
50 | | { XDLC_SARME, "SARME" }, |
51 | | { XDLC_SABME, "SABME" }, |
52 | | { XDLC_RESET, "RESET" }, |
53 | | { XDLC_XID, "XID" }, |
54 | | { XDLC_SNRME, "SNRME" }, |
55 | | { XDLC_BCN, "BCN" }, |
56 | | { 0, NULL } |
57 | | }; |
58 | | |
59 | | const value_string modifier_vals_cmd[] = { |
60 | | { XDLC_UI>>2, "Unnumbered Information" }, |
61 | | { XDLC_UP>>2, "Unnumbered Poll" }, |
62 | | { XDLC_DISC>>2, "Disconnect" }, |
63 | | { XDLC_UA>>2, "Unnumbered Acknowledge" }, |
64 | | { XDLC_SNRM>>2, "Set Normal Response Mode" }, |
65 | | { XDLC_TEST>>2, "Test" }, |
66 | | { XDLC_SIM>>2, "Set Initialization Mode" }, |
67 | | { XDLC_FRMR>>2, "Frame reject" }, |
68 | | { XDLC_CFGR>>2, "Configure" }, |
69 | | { XDLC_SARM>>2, "Set Asynchronous Response Mode" }, |
70 | | { XDLC_SABM>>2, "Set Asynchronous Balanced Mode" }, |
71 | | { XDLC_SARME>>2, "Set Asynchronous Response Mode Extended" }, |
72 | | { XDLC_SABME>>2, "Set Asynchronous Balanced Mode Extended" }, |
73 | | { XDLC_RESET>>2, "Reset" }, |
74 | | { XDLC_XID>>2, "Exchange identification" }, |
75 | | { XDLC_SNRME>>2, "Set Normal Response Mode Extended" }, |
76 | | { XDLC_BCN>>2, "Beacon" }, |
77 | | { 0, NULL } |
78 | | }; |
79 | | |
80 | | static const value_string modifier_short_vals_resp[] = { |
81 | | { XDLC_UI, "UI" }, |
82 | | { XDLC_UP, "UP" }, |
83 | | { XDLC_RD, "RD" }, |
84 | | { XDLC_UA, "UA" }, |
85 | | { XDLC_SNRM, "SNRM" }, |
86 | | { XDLC_TEST, "TEST" }, |
87 | | { XDLC_RIM, "RIM" }, |
88 | | { XDLC_FRMR, "FRMR" }, |
89 | | { XDLC_CFGR, "CFGR" }, |
90 | | { XDLC_DM, "DM" }, |
91 | | { XDLC_SABM, "SABM" }, |
92 | | { XDLC_SARME, "SARME" }, |
93 | | { XDLC_SABME, "SABME" }, |
94 | | { XDLC_RESET, "RESET" }, |
95 | | { XDLC_XID, "XID" }, |
96 | | { XDLC_SNRME, "SNRME" }, |
97 | | { XDLC_BCN, "BCN" }, |
98 | | { 0, NULL } |
99 | | }; |
100 | | |
101 | | const value_string modifier_vals_resp[] = { |
102 | | { XDLC_UI>>2, "Unnumbered Information" }, |
103 | | { XDLC_UP>>2, "Unnumbered Poll" }, |
104 | | { XDLC_RD>>2, "Request Disconnect" }, |
105 | | { XDLC_UA>>2, "Unnumbered Acknowledge" }, |
106 | | { XDLC_SNRM>>2, "Set Normal Response Mode" }, |
107 | | { XDLC_TEST>>2, "Test" }, |
108 | | { XDLC_RIM>>2, "Request Initialization Mode" }, |
109 | | { XDLC_FRMR>>2, "Frame reject" }, |
110 | | { XDLC_CFGR>>2, "Configure" }, |
111 | | { XDLC_DM>>2, "Disconnected mode" }, |
112 | | { XDLC_SABM>>2, "Set Asynchronous Balanced Mode" }, |
113 | | { XDLC_SARME>>2, "Set Asynchronous Response Mode Extended" }, |
114 | | { XDLC_SABME>>2, "Set Asynchronous Balanced Mode Extended" }, |
115 | | { XDLC_RESET>>2, "Reset" }, |
116 | | { XDLC_XID>>2, "Exchange identification" }, |
117 | | { XDLC_SNRME>>2, "Set Normal Response Mode Extended" }, |
118 | | { XDLC_BCN>>2, "Beacon" }, |
119 | | { 0, NULL } |
120 | | }; |
121 | | |
122 | | int |
123 | | get_xdlc_control(const uint8_t *pd, int offset, bool is_extended) |
124 | 0 | { |
125 | 0 | uint16_t control; |
126 | |
|
127 | 0 | switch (pd[offset] & 0x03) { |
128 | | |
129 | 0 | case XDLC_S: |
130 | 0 | default: |
131 | | /* |
132 | | * Supervisory or Information frame. |
133 | | */ |
134 | 0 | if (is_extended) |
135 | 0 | control = pletoh16(&pd[offset]); |
136 | 0 | else |
137 | 0 | control = pd[offset]; |
138 | 0 | break; |
139 | | |
140 | 0 | case XDLC_U: |
141 | | /* |
142 | | * Unnumbered frame. |
143 | | * |
144 | | * XXX - is this two octets, with a P/F bit, in HDLC extended |
145 | | * operation? It's one octet in LLC, even though the control |
146 | | * field of I and S frames is a 2-byte extended-operation field |
147 | | * in LLC. Given that there are no sequence numbers in the |
148 | | * control field of a U frame, there doesn't appear to be any |
149 | | * need for it to be 2 bytes in extended operation. |
150 | | */ |
151 | 0 | control = pd[offset]; |
152 | 0 | break; |
153 | 0 | } |
154 | 0 | return control; |
155 | 0 | } |
156 | | |
157 | | int |
158 | | dissect_xdlc_control(tvbuff_t *tvb, int offset, packet_info *pinfo, |
159 | | proto_tree *xdlc_tree, int hf_xdlc_control, int ett_xdlc_control, |
160 | | const xdlc_cf_items *cf_items_nonext, const xdlc_cf_items *cf_items_ext, |
161 | | const value_string *u_modifier_short_vals_cmd, |
162 | | const value_string *u_modifier_short_vals_resp, bool is_response, |
163 | | bool is_extended, bool append_info) |
164 | 44.3k | { |
165 | 44.3k | uint16_t control; |
166 | 44.3k | int control_len; |
167 | 44.3k | const xdlc_cf_items *cf_items; |
168 | 44.3k | const char *control_format; |
169 | 44.3k | uint16_t poll_final; |
170 | 44.3k | char *info; |
171 | 44.3k | proto_tree *tc, *control_tree; |
172 | 44.3k | const char *frame_type = NULL; |
173 | 44.3k | const char *modifier; |
174 | | |
175 | 44.3k | info=(char *)wmem_alloc(pinfo->pool, 80); |
176 | 44.3k | switch (tvb_get_uint8(tvb, offset) & 0x03) { |
177 | | |
178 | 2.02k | case XDLC_S: |
179 | | /* |
180 | | * Supervisory frame. |
181 | | */ |
182 | 2.02k | if (is_extended) { |
183 | 1.85k | control = tvb_get_letohs(tvb, offset); |
184 | 1.85k | control_len = 2; |
185 | 1.85k | cf_items = cf_items_ext; |
186 | 1.85k | control_format = "Control field: %s (0x%04X)"; |
187 | 1.85k | } else { |
188 | 168 | control = tvb_get_uint8(tvb, offset); |
189 | 168 | control_len = 1; |
190 | 168 | cf_items = cf_items_nonext; |
191 | 168 | control_format = "Control field: %s (0x%02X)"; |
192 | 168 | } |
193 | 2.02k | switch (control & XDLC_S_FTYPE_MASK) { |
194 | 408 | case XDLC_RR: |
195 | 408 | frame_type = "RR"; |
196 | 408 | break; |
197 | | |
198 | 316 | case XDLC_RNR: |
199 | 316 | frame_type = "RNR"; |
200 | 316 | break; |
201 | | |
202 | 1.01k | case XDLC_REJ: |
203 | 1.01k | frame_type = "REJ"; |
204 | 1.01k | break; |
205 | | |
206 | 260 | case XDLC_SREJ: |
207 | 260 | frame_type = "SREJ"; |
208 | 260 | break; |
209 | 2.02k | } |
210 | 2.00k | if (is_extended) { |
211 | 1.83k | poll_final = (control & XDLC_P_F_EXT); |
212 | 1.83k | snprintf(info, 80, "S%s, func=%s, N(R)=%u", |
213 | 1.83k | (poll_final ? |
214 | 1.83k | (is_response ? " F" : " P") : |
215 | 1.83k | ""), |
216 | 1.83k | frame_type, |
217 | 1.83k | (control & XDLC_N_R_EXT_MASK) >> XDLC_N_R_EXT_SHIFT); |
218 | 1.83k | } else { |
219 | 168 | poll_final = (control & XDLC_P_F); |
220 | 168 | snprintf(info, 80, "S%s, func=%s, N(R)=%u", |
221 | 168 | (poll_final ? |
222 | 168 | (is_response ? " F" : " P") : |
223 | 168 | ""), |
224 | 168 | frame_type, |
225 | 168 | (control & XDLC_N_R_MASK) >> XDLC_N_R_SHIFT); |
226 | 168 | } |
227 | 2.00k | if (append_info) { |
228 | 796 | col_append_str(pinfo->cinfo, COL_INFO, ", "); |
229 | 796 | col_append_str(pinfo->cinfo, COL_INFO, info); |
230 | 1.20k | } else { |
231 | 1.20k | col_add_str(pinfo->cinfo, COL_INFO, info); |
232 | 1.20k | } |
233 | 2.00k | if (xdlc_tree) { |
234 | 2.00k | tc = proto_tree_add_uint_format(xdlc_tree, hf_xdlc_control, tvb, |
235 | 2.00k | offset, control_len, control, control_format, info, control); |
236 | 2.00k | control_tree = proto_item_add_subtree(tc, ett_xdlc_control); |
237 | 2.00k | proto_tree_add_uint(control_tree, *cf_items->hf_xdlc_n_r, |
238 | 2.00k | tvb, offset, control_len, control); |
239 | 2.00k | if (poll_final) { |
240 | 1.39k | proto_tree_add_boolean(control_tree, |
241 | 1.39k | (is_response ? *cf_items->hf_xdlc_f : |
242 | 1.39k | *cf_items->hf_xdlc_p), |
243 | 1.39k | tvb, offset, control_len, control); |
244 | 1.39k | } |
245 | 2.00k | proto_tree_add_uint(control_tree, *cf_items->hf_xdlc_s_ftype, |
246 | 2.00k | tvb, offset, control_len, control); |
247 | | /* This will always say it's a supervisory frame */ |
248 | 2.00k | proto_tree_add_uint(control_tree, *cf_items->hf_xdlc_ftype_s_u, |
249 | 2.00k | tvb, offset, control_len, control); |
250 | 2.00k | } |
251 | 2.00k | break; |
252 | | |
253 | 12.1k | case XDLC_U: |
254 | | /* |
255 | | * Unnumbered frame. |
256 | | * |
257 | | * XXX - is this two octets, with a P/F bit, in HDLC extended |
258 | | * operation? It's one octet in LLC, even though the control |
259 | | * field of I and S frames is a 2-byte extended-operation field |
260 | | * in LLC. Given that there are no sequence numbers in the |
261 | | * control field of a U frame, there doesn't appear to be any |
262 | | * need for it to be 2 bytes in extended operation. |
263 | | */ |
264 | 12.1k | if (u_modifier_short_vals_cmd == NULL) |
265 | 12.1k | u_modifier_short_vals_cmd = modifier_short_vals_cmd; |
266 | 12.1k | if (u_modifier_short_vals_resp == NULL) |
267 | 12.1k | u_modifier_short_vals_resp = modifier_short_vals_resp; |
268 | 12.1k | control = tvb_get_uint8(tvb, offset); |
269 | 12.1k | control_len = 1; |
270 | 12.1k | cf_items = cf_items_nonext; |
271 | 12.1k | control_format = "Control field: %s (0x%02X)"; |
272 | 12.1k | if (is_response) { |
273 | 1.19k | modifier = val_to_str(control & XDLC_U_MODIFIER_MASK, |
274 | 1.19k | u_modifier_short_vals_resp, "Unknown"); |
275 | 10.9k | } else { |
276 | 10.9k | modifier = val_to_str(control & XDLC_U_MODIFIER_MASK, |
277 | 10.9k | u_modifier_short_vals_cmd, "Unknown"); |
278 | 10.9k | } |
279 | 12.1k | poll_final = (control & XDLC_P_F); |
280 | 12.1k | snprintf(info, 80, "U%s, func=%s", |
281 | 12.1k | (poll_final ? |
282 | 12.1k | (is_response ? " F" : " P") : |
283 | 12.1k | ""), |
284 | 12.1k | modifier); |
285 | 12.1k | if (append_info) { |
286 | 116 | col_append_str(pinfo->cinfo, COL_INFO, ", "); |
287 | 116 | col_append_str(pinfo->cinfo, COL_INFO, info); |
288 | 12.0k | } else { |
289 | 12.0k | col_add_str(pinfo->cinfo, COL_INFO, info); |
290 | 12.0k | } |
291 | 12.1k | if (xdlc_tree) { |
292 | 12.1k | tc = proto_tree_add_uint_format(xdlc_tree, hf_xdlc_control, tvb, |
293 | 12.1k | offset, control_len, control, control_format, info, control); |
294 | 12.1k | control_tree = proto_item_add_subtree(tc, ett_xdlc_control); |
295 | 12.1k | if (poll_final) { |
296 | 1.06k | proto_tree_add_boolean(control_tree, |
297 | 1.06k | (is_response ? *cf_items->hf_xdlc_f: |
298 | 1.06k | *cf_items->hf_xdlc_p), |
299 | 1.06k | tvb, offset, control_len, control); |
300 | 1.06k | } |
301 | 12.1k | proto_tree_add_uint(control_tree, |
302 | 12.1k | (is_response ? *cf_items->hf_xdlc_u_modifier_resp : |
303 | 12.1k | *cf_items->hf_xdlc_u_modifier_cmd), |
304 | 12.1k | tvb, offset, control_len, control); |
305 | | /* This will always say it's an unnumbered frame */ |
306 | 12.1k | proto_tree_add_uint(control_tree, *cf_items->hf_xdlc_ftype_s_u, |
307 | 12.1k | tvb, offset, control_len, control); |
308 | 12.1k | } |
309 | 12.1k | break; |
310 | | |
311 | 29.5k | default: |
312 | | /* |
313 | | * Information frame. |
314 | | */ |
315 | 29.5k | if (is_extended) { |
316 | 28.4k | control = tvb_get_letohs(tvb, offset); |
317 | 28.4k | control_len = 2; |
318 | 28.4k | cf_items = cf_items_ext; |
319 | 28.4k | control_format = "Control field: %s (0x%04X)"; |
320 | 28.4k | poll_final = (control & XDLC_P_F_EXT); |
321 | 28.4k | snprintf(info, 80, "I%s, N(R)=%u, N(S)=%u", |
322 | 28.4k | ((control & XDLC_P_F_EXT) ? " P" : ""), |
323 | 28.4k | (control & XDLC_N_R_EXT_MASK) >> XDLC_N_R_EXT_SHIFT, |
324 | 28.4k | (control & XDLC_N_S_EXT_MASK) >> XDLC_N_S_EXT_SHIFT); |
325 | 28.4k | } else { |
326 | 1.08k | control = tvb_get_uint8(tvb, offset); |
327 | 1.08k | control_len = 1; |
328 | 1.08k | cf_items = cf_items_nonext; |
329 | 1.08k | control_format = "Control field: %s (0x%02X)"; |
330 | 1.08k | poll_final = (control & XDLC_P_F); |
331 | 1.08k | snprintf(info, 80, "I%s, N(R)=%u, N(S)=%u", |
332 | 1.08k | ((control & XDLC_P_F) ? " P" : ""), |
333 | 1.08k | (control & XDLC_N_R_MASK) >> XDLC_N_R_SHIFT, |
334 | 1.08k | (control & XDLC_N_S_MASK) >> XDLC_N_S_SHIFT); |
335 | 1.08k | } |
336 | 29.5k | if (append_info) { |
337 | 48 | col_append_str(pinfo->cinfo, COL_INFO, ", "); |
338 | 48 | col_append_str(pinfo->cinfo, COL_INFO, info); |
339 | 29.4k | } else { |
340 | 29.4k | col_add_str(pinfo->cinfo, COL_INFO, info); |
341 | 29.4k | } |
342 | 29.5k | if (xdlc_tree) { |
343 | 29.3k | tc = proto_tree_add_uint_format(xdlc_tree, hf_xdlc_control, tvb, |
344 | 29.3k | offset, control_len, control, control_format, info, control); |
345 | 29.3k | control_tree = proto_item_add_subtree(tc, ett_xdlc_control); |
346 | 29.3k | proto_tree_add_uint(control_tree, *cf_items->hf_xdlc_n_r, |
347 | 29.3k | tvb, offset, control_len, control); |
348 | 29.3k | proto_tree_add_uint(control_tree, *cf_items->hf_xdlc_n_s, |
349 | 29.3k | tvb, offset, control_len, control); |
350 | 29.3k | if (poll_final) { |
351 | 12.3k | proto_tree_add_boolean(control_tree, *cf_items->hf_xdlc_p, |
352 | 12.3k | tvb, offset, control_len, control); |
353 | 12.3k | } |
354 | | /* This will always say it's an information frame */ |
355 | 29.3k | proto_tree_add_uint(control_tree, *cf_items->hf_xdlc_ftype_i, |
356 | 29.3k | tvb, offset, control_len, control); |
357 | 29.3k | } |
358 | 29.5k | break; |
359 | 44.3k | } |
360 | 43.5k | return control; |
361 | 44.3k | } |
362 | | |
363 | | /* |
364 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
365 | | * |
366 | | * Local variables: |
367 | | * c-basic-offset: 4 |
368 | | * tab-width: 8 |
369 | | * indent-tabs-mode: nil |
370 | | * End: |
371 | | * |
372 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
373 | | * :indentSize=4:tabSize=8:noTabs=true: |
374 | | */ |