Coverage Report

Created: 2025-08-04 07:15

/src/wireshark/epan/dissectors/packet-v120.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-v120.c
2
 * Routines for v120 frame disassembly
3
 * Bert Driehuis <driehuis@playbeing.org>
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998
8
 *
9
 * SPDX-License-Identifier: GPL-2.0-or-later
10
 */
11
12
#include "config.h"
13
14
#include <epan/packet.h>
15
#include <epan/xdlc.h>
16
#include <epan/tfs.h>
17
#include <wsutil/array.h>
18
19
void proto_register_v120(void);
20
21
static int proto_v120;
22
static int hf_v120_address;
23
static int hf_v120_rc;
24
static int hf_v120_lli;
25
static int hf_v120_ea0;
26
static int hf_v120_ea1;
27
static int hf_v120_control;
28
static int hf_v120_n_r;
29
static int hf_v120_n_s;
30
static int hf_v120_p;
31
static int hf_v120_p_ext;
32
static int hf_v120_f;
33
static int hf_v120_f_ext;
34
static int hf_v120_s_ftype;
35
static int hf_v120_u_modifier_cmd;
36
static int hf_v120_u_modifier_resp;
37
static int hf_v120_ftype_i;
38
static int hf_v120_ftype_s_u;
39
static int hf_v120_ftype_s_u_ext;
40
static int hf_v120_header8;
41
static int hf_v120_header_ext8;
42
static int hf_v120_header_break8;
43
static int hf_v120_header_error_control8;
44
static int hf_v120_header_segb8;
45
static int hf_v120_header_segf8;
46
static int hf_v120_header16;
47
static int hf_v120_header_ext16;
48
static int hf_v120_header_break16;
49
static int hf_v120_header_error_control16;
50
static int hf_v120_header_segb16;
51
static int hf_v120_header_segf16;
52
static int hf_v120_header_e;
53
static int hf_v120_header_dr;
54
static int hf_v120_header_sr;
55
static int hf_v120_header_rr;
56
57
static int ett_v120;
58
static int ett_v120_address;
59
static int ett_v120_control;
60
static int ett_v120_header;
61
62
static int dissect_v120_header(tvbuff_t *tvb, int offset, proto_tree *tree);
63
64
/* Used only for U frames */
65
static const xdlc_cf_items v120_cf_items = {
66
  NULL,
67
  NULL,
68
  &hf_v120_p,
69
  &hf_v120_f,
70
  NULL,
71
  &hf_v120_u_modifier_cmd,
72
  &hf_v120_u_modifier_resp,
73
  NULL,
74
  &hf_v120_ftype_s_u
75
};
76
77
/* Used only for I and S frames */
78
static const xdlc_cf_items v120_cf_items_ext = {
79
  &hf_v120_n_r,
80
  &hf_v120_n_s,
81
  &hf_v120_p_ext,
82
  &hf_v120_f_ext,
83
  &hf_v120_s_ftype,
84
  NULL,
85
  NULL,
86
  &hf_v120_ftype_i,
87
  &hf_v120_ftype_s_u_ext
88
};
89
90
static int
91
dissect_v120(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
92
4
{
93
4
  proto_tree *v120_tree, *address_tree;
94
4
  proto_item *ti, *tc;
95
4
  int     is_response;
96
4
  int     v120len;
97
4
  uint8_t     byte0, byte1;
98
4
  uint16_t    control;
99
4
  tvbuff_t   *next_tvb;
100
101
4
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "V.120");
102
4
  col_clear(pinfo->cinfo, COL_INFO);
103
104
4
  byte0 = tvb_get_uint8(tvb, 0);
105
106
4
  col_add_fstr(pinfo->cinfo, COL_RES_DL_SRC, "0x%02X", byte0);
107
108
4
  byte1 = tvb_get_uint8(tvb, 1);
109
110
4
  if ( ((byte0 & 0x01) != 0x00) && ((byte1 & 0x01) != 0x01) )
111
0
  {
112
0
    col_set_str(pinfo->cinfo, COL_INFO, "Invalid V.120 frame");
113
0
    if (tree)
114
0
      proto_tree_add_protocol_format(tree, proto_v120, tvb, 0, -1,
115
0
                  "Invalid V.120 frame");
116
0
    return 2;
117
0
  }
118
119
4
  if (pinfo->p2p_dir == P2P_DIR_SENT) {
120
1
    is_response = (byte0 & 0x02) ? false: true;
121
1
    col_set_str(pinfo->cinfo, COL_RES_DL_DST, "DCE");
122
1
    col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "DTE");
123
3
  } else {
124
    /* XXX - what if the direction is unknown? */
125
3
    is_response = (byte0 & 0x02) ? true : false;
126
3
    col_set_str(pinfo->cinfo, COL_RES_DL_DST, "DTE");
127
3
    col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "DCE");
128
3
  }
129
130
4
  ti = proto_tree_add_protocol_format(tree, proto_v120, tvb, 0, -1, "V.120");
131
4
  v120_tree = proto_item_add_subtree(ti, ett_v120);
132
4
  tc = proto_tree_add_item(v120_tree, hf_v120_address, tvb, 0, 2, ENC_BIG_ENDIAN);
133
4
  proto_item_append_text(tc, "LLI: %d C/R: %s",
134
4
      ((byte0 & 0xfc) << 5) | ((byte1 & 0xfe) >> 1),
135
4
      byte0 & 0x02 ? "R" : "C");
136
4
  address_tree = proto_item_add_subtree(tc, ett_v120_address);
137
138
4
  proto_tree_add_item(address_tree, hf_v120_rc, tvb, 0, 2, ENC_BIG_ENDIAN);
139
4
  proto_tree_add_item(address_tree, hf_v120_lli, tvb, 0, 2, ENC_BIG_ENDIAN);
140
4
  proto_tree_add_item(address_tree, hf_v120_ea0, tvb, 0, 2, ENC_BIG_ENDIAN);
141
4
  proto_tree_add_item(address_tree, hf_v120_ea1, tvb, 0, 2, ENC_BIG_ENDIAN);
142
143
4
  control = dissect_xdlc_control(tvb, 2, pinfo, v120_tree, hf_v120_control,
144
4
    ett_v120_control, &v120_cf_items, &v120_cf_items_ext,
145
4
    NULL, NULL, is_response, true, false);
146
147
4
  v120len = 2 + XDLC_CONTROL_LEN(control, true);
148
149
4
  if (tvb_bytes_exist(tvb, v120len, 1))
150
3
    v120len += dissect_v120_header(tvb, v120len, v120_tree);
151
4
  proto_item_set_len(ti, v120len);
152
4
  next_tvb = tvb_new_subset_remaining(tvb, v120len);
153
4
  call_data_dissector(next_tvb, pinfo, v120_tree);
154
155
4
  return tvb_captured_length(tvb);
156
4
}
157
158
static int
159
dissect_v120_header(tvbuff_t *tvb, int offset, proto_tree *tree)
160
3
{
161
3
  int         header_len;
162
3
  uint8_t     byte0;
163
3
  proto_tree *h_tree;
164
3
  proto_item *tc;
165
166
3
  byte0 = tvb_get_uint8(tvb, offset);
167
3
  if (byte0 & 0x80) {
168
1
    header_len = 1;
169
1
    tc = proto_tree_add_item(tree, hf_v120_header8, tvb, 0, 1, ENC_BIG_ENDIAN);
170
171
1
    h_tree = proto_item_add_subtree(tc, ett_v120_header);
172
1
    proto_tree_add_item(h_tree, hf_v120_header_ext8, tvb, 0, 1, ENC_NA);
173
1
    proto_tree_add_item(h_tree, hf_v120_header_break8, tvb, 0, 1, ENC_NA);
174
1
    proto_tree_add_item(h_tree, hf_v120_header_error_control8, tvb, 0, 1, ENC_BIG_ENDIAN);
175
1
    proto_tree_add_item(h_tree, hf_v120_header_segb8, tvb, 0, 1, ENC_NA);
176
1
    proto_tree_add_item(h_tree, hf_v120_header_segf8, tvb, 0, 1, ENC_NA);
177
2
  } else {
178
2
    header_len = 2;
179
2
    tc = proto_tree_add_item(tree, hf_v120_header16, tvb, 0, 2, ENC_BIG_ENDIAN);
180
2
    h_tree = proto_item_add_subtree(tc, ett_v120_header);
181
2
    proto_tree_add_item(h_tree, hf_v120_header_ext16, tvb, 0, 2, ENC_BIG_ENDIAN);
182
2
    proto_tree_add_item(h_tree, hf_v120_header_break16, tvb, 0, 2, ENC_BIG_ENDIAN);
183
2
    proto_tree_add_item(h_tree, hf_v120_header_error_control16, tvb, 0, 2, ENC_BIG_ENDIAN);
184
2
    proto_tree_add_item(h_tree, hf_v120_header_segb16, tvb, 0, 2, ENC_BIG_ENDIAN);
185
2
    proto_tree_add_item(h_tree, hf_v120_header_segf16, tvb, 0, 2, ENC_BIG_ENDIAN);
186
2
    proto_tree_add_item(h_tree, hf_v120_header_e, tvb, 0, 2, ENC_BIG_ENDIAN);
187
2
    proto_tree_add_item(h_tree, hf_v120_header_dr, tvb, 0, 2, ENC_BIG_ENDIAN);
188
2
    proto_tree_add_item(h_tree, hf_v120_header_sr, tvb, 0, 2, ENC_BIG_ENDIAN);
189
2
    proto_tree_add_item(h_tree, hf_v120_header_rr, tvb, 0, 2, ENC_BIG_ENDIAN);
190
2
  }
191
192
3
  proto_item_append_text(tc, " B: %d F: %d",
193
3
             byte0 & 0x02 ? 1:0, byte0 & 0x01 ? 1:0);
194
195
3
  return header_len;
196
3
}
197
198
void
199
proto_register_v120(void)
200
14
{
201
14
  static hf_register_info hf[] = {
202
14
    { &hf_v120_address,
203
14
      { "Link Address", "v120.address", FT_UINT16, BASE_HEX, NULL,
204
14
        0x0, NULL, HFILL }},
205
14
    { &hf_v120_rc,
206
14
      { "R/C", "v120.rc", FT_BOOLEAN, 16, TFS(&tfs_response_command),
207
14
        0x0002, NULL, HFILL }},
208
14
    { &hf_v120_lli,
209
14
      { "LLI", "v120.lli", FT_UINT16, BASE_HEX, NULL,
210
14
        0xfefc, NULL, HFILL }},
211
14
    { &hf_v120_ea0,
212
14
      { "EA0", "v120.ea0", FT_BOOLEAN, 16, TFS(&tfs_error_ok),
213
14
        0x0001, NULL, HFILL }},
214
14
    { &hf_v120_ea1,
215
14
      { "EA1", "v120.ea1", FT_BOOLEAN, 16, TFS(&tfs_ok_error),
216
14
        0x0100, NULL, HFILL }},
217
14
    { &hf_v120_control,
218
14
      { "Control Field", "v120.control", FT_UINT16, BASE_HEX, NULL, 0x0,
219
14
        NULL, HFILL }},
220
14
    { &hf_v120_n_r,
221
14
      { "N(R)", "v120.control.n_r", FT_UINT16, BASE_DEC,
222
14
        NULL, XDLC_N_R_EXT_MASK, NULL, HFILL }},
223
14
    { &hf_v120_n_s,
224
14
      { "N(S)", "v120.control.n_s", FT_UINT16, BASE_DEC,
225
14
        NULL, XDLC_N_S_EXT_MASK, NULL, HFILL }},
226
14
    { &hf_v120_p,
227
14
      { "Poll", "v120.control.p", FT_BOOLEAN, 8,
228
14
        TFS(&tfs_set_notset), XDLC_P_F, NULL, HFILL }},
229
14
    { &hf_v120_p_ext,
230
14
      { "Poll", "v120.control.p", FT_BOOLEAN, 16,
231
14
        TFS(&tfs_set_notset), XDLC_P_F_EXT, NULL, HFILL }},
232
14
    { &hf_v120_f,
233
14
      { "Final", "v120.control.f", FT_BOOLEAN, 8,
234
14
        TFS(&tfs_set_notset), XDLC_P_F, NULL, HFILL }},
235
14
    { &hf_v120_f_ext,
236
14
      { "Final", "v120.control.f", FT_BOOLEAN, 16,
237
14
        TFS(&tfs_set_notset), XDLC_P_F_EXT, NULL, HFILL }},
238
14
    { &hf_v120_s_ftype,
239
14
      { "Supervisory frame type", "v120.control.s_ftype", FT_UINT16, BASE_HEX,
240
14
        VALS(stype_vals), XDLC_S_FTYPE_MASK, NULL, HFILL }},
241
14
    { &hf_v120_u_modifier_cmd,
242
14
      { "Command", "v120.control.u_modifier_cmd", FT_UINT8, BASE_HEX,
243
14
        VALS(modifier_vals_cmd), XDLC_U_MODIFIER_MASK, NULL, HFILL }},
244
14
    { &hf_v120_u_modifier_resp,
245
14
      { "Response", "v120.control.u_modifier_resp", FT_UINT8, BASE_HEX,
246
14
        VALS(modifier_vals_resp), XDLC_U_MODIFIER_MASK, NULL, HFILL }},
247
14
    { &hf_v120_ftype_i,
248
14
      { "Frame type", "v120.control.ftype", FT_UINT16, BASE_HEX,
249
14
        VALS(ftype_vals), XDLC_I_MASK, NULL, HFILL }},
250
14
    { &hf_v120_ftype_s_u,
251
14
      { "Frame type", "v120.control.ftype", FT_UINT8, BASE_HEX,
252
14
        VALS(ftype_vals), XDLC_S_U_MASK, NULL, HFILL }},
253
14
    { &hf_v120_ftype_s_u_ext,
254
14
      { "Frame type", "v120.control.ftype", FT_UINT16, BASE_HEX,
255
14
        VALS(ftype_vals), XDLC_S_U_MASK, NULL, HFILL }},
256
14
    { &hf_v120_header8,
257
14
      { "Header", "v120.header", FT_UINT8, BASE_HEX, NULL, 0x0,
258
14
        NULL, HFILL }},
259
14
    { &hf_v120_header_ext8,
260
14
      { "Extension octet", "v120.header.ext", FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x80,
261
14
        NULL, HFILL }},
262
14
    { &hf_v120_header_break8,
263
14
      { "Break condition", "v120.header.break", FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x40,
264
14
        NULL, HFILL }},
265
14
    { &hf_v120_header_error_control8,
266
14
      { "Error control C1/C2", "v120.error_control", FT_UINT8, BASE_HEX, NULL, 0x0C,
267
14
        NULL, HFILL }},
268
14
    { &hf_v120_header_segb8,
269
14
      { "Bit B", "v120.header.segb", FT_BOOLEAN, 8, TFS(&tfs_segmentation_no_segmentation), 0x02,
270
14
        NULL, HFILL }},
271
14
    { &hf_v120_header_segf8,
272
14
      { "Bit F", "v120.header.segf", FT_BOOLEAN, 8, TFS(&tfs_segmentation_no_segmentation), 0x01,
273
14
        NULL, HFILL }},
274
14
    { &hf_v120_header16,
275
14
      { "Header", "v120.header", FT_UINT16, BASE_HEX, NULL, 0x0,
276
14
        NULL, HFILL }},
277
14
    { &hf_v120_header_ext16,
278
14
      { "Extension octet", "v120.header.ext", FT_BOOLEAN, 16, TFS(&tfs_yes_no), 0x0080,
279
14
        NULL, HFILL }},
280
14
    { &hf_v120_header_break16,
281
14
      { "Break condition", "v120.header.break", FT_BOOLEAN, 16, TFS(&tfs_yes_no), 0x0040,
282
14
        NULL, HFILL }},
283
14
    { &hf_v120_header_error_control16,
284
14
      { "Error control C1/C2", "v120.error_control", FT_UINT16, BASE_HEX, NULL, 0x0C,
285
14
        NULL, HFILL }},
286
14
    { &hf_v120_header_segb16,
287
14
      { "Bit B", "v120.header.segb", FT_BOOLEAN, 16, TFS(&tfs_segmentation_no_segmentation), 0x0002,
288
14
        NULL, HFILL }},
289
14
    { &hf_v120_header_segf16,
290
14
      { "Bit F", "v120.header.segf", FT_BOOLEAN, 16, TFS(&tfs_segmentation_no_segmentation), 0x0001,
291
14
        NULL, HFILL }},
292
14
    { &hf_v120_header_e,
293
14
      { "E", "v120.header.e", FT_BOOLEAN, 16, TFS(&tfs_yes_no), 0x8000,
294
14
        NULL, HFILL }},
295
14
    { &hf_v120_header_dr,
296
14
      { "DR", "v120.header.dr", FT_BOOLEAN, 16, TFS(&tfs_yes_no), 0x4000,
297
14
        NULL, HFILL }},
298
14
    { &hf_v120_header_sr,
299
14
      { "SR", "v120.header.sr", FT_BOOLEAN, 16, TFS(&tfs_yes_no), 0x2000,
300
14
        NULL, HFILL }},
301
14
    { &hf_v120_header_rr,
302
14
      { "RR", "v120.header.rr", FT_BOOLEAN, 16, TFS(&tfs_yes_no), 0x1000,
303
14
        NULL, HFILL }},
304
14
  };
305
14
  static int *ett[] = {
306
14
    &ett_v120,
307
14
    &ett_v120_address,
308
14
    &ett_v120_control,
309
14
    &ett_v120_header,
310
14
  };
311
312
14
  proto_v120 = proto_register_protocol("Async data over ISDN (V.120)",
313
14
               "V.120", "v120");
314
14
  proto_register_field_array (proto_v120, hf, array_length(hf));
315
14
  proto_register_subtree_array(ett, array_length(ett));
316
317
14
  register_dissector("v120", dissect_v120, proto_v120);
318
14
}
319
320
/*
321
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
322
 *
323
 * Local variables:
324
 * c-basic-offset: 8
325
 * tab-width: 8
326
 * indent-tabs-mode: t
327
 * End:
328
 *
329
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
330
 * :indentSize=8:tabSize=8:noTabs=false:
331
 */