Coverage Report

Created: 2025-04-03 08:45

/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
 */