Coverage Report

Created: 2025-08-04 07:15

/src/wireshark/epan/dissectors/packet-xot.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-xot.c
2
 * Routines for X.25 over TCP dissection (RFC 1613)
3
 *
4
 * Copyright 2000, Paul Ionescu <paul@acorp.ro>
5
 *
6
 * Wireshark - Network traffic analyzer
7
 * By Gerald Combs <gerald@wireshark.org>
8
 * Copyright 1998 Gerald Combs
9
 *
10
 * SPDX-License-Identifier: GPL-2.0-or-later
11
 */
12
13
#include "config.h"
14
15
#include <epan/packet.h>
16
#include <epan/prefs.h>
17
#include <epan/conversation.h>
18
19
#include "packet-tcp.h"
20
21
14
#define TCP_PORT_XOT 1998
22
1.45k
#define XOT_HEADER_LENGTH 4
23
25
#define XOT_VERSION 0
24
85
#define XOT_PVC_SETUP 0xF5
25
26
/* Some X25 macros from packet-x25.c - some adapted code as well below */
27
283
#define X25_MIN_HEADER_LENGTH 3
28
#define X25_MIN_M128_HEADER_LENGTH 4
29
0
#define X25_NONDATA_BIT                 0x01
30
0
#define PACKET_IS_DATA(type)            (!(type & X25_NONDATA_BIT))
31
0
#define X25_MBIT_MOD8                   0x10
32
0
#define X25_MBIT_MOD128                 0x01
33
34
void proto_register_xot(void);
35
void proto_reg_handoff_xot(void);
36
37
static const value_string vals_x25_type[] = {
38
   { XOT_PVC_SETUP, "PVC Setup" },
39
   { 0,   NULL}
40
};
41
42
static const value_string xot_pvc_status_vals[] = {
43
   { 0x00, "Waiting to connect" },
44
45
   { 0x08, "Destination disconnected" },
46
   { 0x09, "PVC/TCP connection refused" },
47
   { 0x0A, "PVC/TCP routing error" },
48
   { 0x0B, "PVC/TCP connect timed out" },
49
50
   { 0x10, "Trying to connect via TCP" },
51
   { 0x11, "Awaiting PVC-SETUP reply" },
52
   { 0x12, "Connected" },
53
   { 0x13, "No such destination interface" },
54
   { 0x14, "Destination interface is not up" },
55
   { 0x15, "Non-X.25 destination interface" },
56
   { 0x16, "No such destination PVC" },
57
   { 0x17, "Destination PVC configuration mismatch" },
58
   { 0x18, "Mismatched flow control values" },
59
   { 0x19, "Can't support flow control values" },
60
   { 0x1A, "PVC setup protocol error" },
61
62
   { 0,   NULL}
63
};
64
65
static int proto_xot;
66
static int ett_xot;
67
static int hf_xot_version;
68
static int hf_xot_length;
69
70
static int hf_x25_gfi;
71
static int hf_x25_lcn;
72
static int hf_x25_type;
73
74
static int hf_xot_pvc_version;
75
static int hf_xot_pvc_status;
76
static int hf_xot_pvc_init_itf_name_len;
77
static int hf_xot_pvc_init_lcn;
78
static int hf_xot_pvc_resp_itf_name_len;
79
static int hf_xot_pvc_resp_lcn;
80
static int hf_xot_pvc_send_inc_window;
81
static int hf_xot_pvc_send_out_window;
82
static int hf_xot_pvc_send_inc_pkt_size;
83
static int hf_xot_pvc_send_out_pkt_size;
84
static int hf_xot_pvc_init_itf_name;
85
static int hf_xot_pvc_resp_itf_name;
86
87
static dissector_handle_t xot_handle;
88
static dissector_handle_t xot_tcp_handle;
89
90
static dissector_handle_t x25_handle;
91
92
/* desegmentation of X.25 over multiple TCP */
93
static bool xot_desegment = true;
94
/* desegmentation of X.25 packet sequences */
95
static bool x25_desegment;
96
97
static unsigned get_xot_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb,
98
                             int offset, void *data _U_)
99
285
{
100
285
   uint16_t plen;
101
285
   int remain = tvb_captured_length_remaining(tvb, offset);
102
285
   if ( remain < XOT_HEADER_LENGTH){
103
      /* We did not get the data we asked for, use up what we can */
104
2
      return remain;
105
2
   }
106
107
   /*
108
    * Get the length of the X.25-over-TCP packet.
109
    */
110
283
   plen = tvb_get_ntohs(tvb, offset + 2);
111
283
   return XOT_HEADER_LENGTH + plen;
112
285
}
113
114
static unsigned get_xot_pdu_len_mult(packet_info *pinfo _U_, tvbuff_t *tvb,
115
                                  int offset, void *data _U_)
116
0
{
117
0
   int offset_before = offset; /* offset where we start this test */
118
0
   int offset_next = offset + XOT_HEADER_LENGTH + X25_MIN_HEADER_LENGTH;
119
0
   int tvb_len;
120
121
0
   while ((tvb_len = tvb_captured_length_remaining(tvb, offset)) > 0){
122
0
      uint16_t plen = 0;
123
0
      int modulo;
124
0
      uint16_t bytes0_1;
125
0
      uint8_t pkt_type;
126
0
      bool m_bit_set;
127
0
      int offset_x25 = offset + XOT_HEADER_LENGTH;
128
129
      /* Minimum where next starts */
130
0
      offset_next = offset_x25 + X25_MIN_HEADER_LENGTH;
131
132
0
      if (tvb_len < XOT_HEADER_LENGTH) {
133
0
         return offset_next-offset_before;
134
0
      }
135
136
      /*
137
       * Get the length of the current X.25-over-TCP packet.
138
       */
139
0
      plen = get_xot_pdu_len(pinfo, tvb, offset, NULL);
140
0
      offset_next = offset + plen;
141
142
      /* Make sure we have enough data */
143
0
      if (tvb_len < plen){
144
0
         return offset_next-offset_before;
145
0
      }
146
147
      /*Some minor code copied from packet-x25.c */
148
0
      bytes0_1 = tvb_get_ntohs(tvb,  offset_x25+0);
149
0
      pkt_type = tvb_get_uint8(tvb, offset_x25+2);
150
151
      /* If this is the first packet and it is not data, no sequence needed */
152
0
      if (offset == offset_before && !PACKET_IS_DATA(pkt_type)) {
153
0
          return offset_next-offset_before;
154
0
      }
155
156
      /* Check for data, there can be X25 control packets in the X25 data */
157
0
      if (PACKET_IS_DATA(pkt_type)){
158
0
         modulo = ((bytes0_1 & 0x2000) ? 128 : 8);
159
0
         if (modulo == 8) {
160
0
            m_bit_set = pkt_type & X25_MBIT_MOD8;
161
0
         } else {
162
0
            m_bit_set = tvb_get_uint8(tvb, offset_x25+3) & X25_MBIT_MOD128;
163
0
         }
164
165
0
         if (!m_bit_set){
166
            /* We are done with this sequence when the mbit is no longer set */
167
0
            return offset_next-offset_before;
168
0
         }
169
0
      }
170
0
      offset = offset_next;
171
0
      offset_next += XOT_HEADER_LENGTH + X25_MIN_HEADER_LENGTH;
172
0
  }
173
174
  /* not enough data */
175
0
  pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
176
0
  return offset_next - offset_before;
177
0
}
178
179
static int dissect_xot_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
180
283
{
181
283
   int offset = 0;
182
283
   uint16_t version;
183
283
   uint16_t plen;
184
283
   uint8_t pkt_type;
185
283
   proto_item *ti = NULL;
186
283
   proto_tree *xot_tree = NULL;
187
283
   tvbuff_t   *next_tvb;
188
189
   /*
190
    * Dissect the X.25-over-TCP packet.
191
    */
192
283
   col_set_str(pinfo->cinfo, COL_PROTOCOL, "XOT");
193
283
   version = tvb_get_ntohs(tvb, offset + 0);
194
283
   plen = tvb_get_ntohs(tvb, offset + 2);
195
283
   col_add_fstr(pinfo->cinfo, COL_INFO, "XOT Version = %u, size = %u",
196
283
                version, plen);
197
283
   if (offset == 0 &&
198
283
       tvb_reported_length_remaining(tvb, offset) > XOT_HEADER_LENGTH + plen )
199
0
      col_append_fstr(pinfo->cinfo, COL_INFO, " TotX25: %d",
200
0
                      tvb_reported_length_remaining(tvb, offset));
201
202
283
   if (tree) {
203
283
      ti = proto_tree_add_protocol_format(tree, proto_xot, tvb, offset, XOT_HEADER_LENGTH,
204
283
                                          "X.25 over TCP");
205
283
      xot_tree = proto_item_add_subtree(ti, ett_xot);
206
207
283
      proto_tree_add_uint(xot_tree, hf_xot_version, tvb, offset, 2, version);
208
283
      proto_tree_add_uint(xot_tree, hf_xot_length, tvb, offset + 2, 2, plen);
209
283
   }
210
211
283
   offset += XOT_HEADER_LENGTH;
212
   /*
213
    * Construct a tvbuff containing the amount of the payload we have
214
    * available.  Make its reported length the amount of data in the
215
    * X.25-over-TCP packet.
216
    */
217
283
   if (plen >= X25_MIN_HEADER_LENGTH) {
218
85
      pkt_type = tvb_get_uint8(tvb, offset + 2);
219
85
      if (pkt_type == XOT_PVC_SETUP) {
220
0
         unsigned init_itf_name_len, resp_itf_name_len, pkt_size;
221
0
         int hdr_offset = offset;
222
223
0
         col_set_str(pinfo->cinfo, COL_INFO, "XOT PVC Setup");
224
0
         proto_item_set_len(ti, XOT_HEADER_LENGTH + plen);
225
226
         /* These fields are in overlay with packet-x25.c */
227
0
         proto_tree_add_item(xot_tree, hf_x25_gfi, tvb, hdr_offset, 2, ENC_BIG_ENDIAN);
228
0
         proto_tree_add_item(xot_tree, hf_x25_lcn, tvb, hdr_offset, 2, ENC_BIG_ENDIAN);
229
0
         hdr_offset += 2;
230
0
         proto_tree_add_item(xot_tree, hf_x25_type, tvb, hdr_offset, 1, ENC_BIG_ENDIAN);
231
0
         hdr_offset += 1;
232
233
0
         proto_tree_add_item(xot_tree, hf_xot_pvc_version, tvb, hdr_offset, 1, ENC_BIG_ENDIAN);
234
0
         hdr_offset += 1;
235
0
         proto_tree_add_item(xot_tree, hf_xot_pvc_status, tvb, hdr_offset, 1, ENC_BIG_ENDIAN);
236
0
         hdr_offset += 1;
237
0
         proto_tree_add_item(xot_tree, hf_xot_pvc_init_itf_name_len, tvb, hdr_offset, 1, ENC_BIG_ENDIAN);
238
0
         init_itf_name_len = tvb_get_uint8(tvb, hdr_offset);
239
0
         hdr_offset += 1;
240
0
         proto_tree_add_item(xot_tree, hf_xot_pvc_init_lcn, tvb, hdr_offset, 2, ENC_BIG_ENDIAN);
241
0
         hdr_offset += 2;
242
0
         proto_tree_add_item(xot_tree, hf_xot_pvc_resp_itf_name_len, tvb, hdr_offset, 1, ENC_BIG_ENDIAN);
243
0
         resp_itf_name_len = tvb_get_uint8(tvb, hdr_offset);
244
0
         hdr_offset += 1;
245
0
         proto_tree_add_item(xot_tree, hf_xot_pvc_resp_lcn, tvb, hdr_offset, 2, ENC_BIG_ENDIAN);
246
0
         hdr_offset += 2;
247
0
         proto_tree_add_item(xot_tree, hf_xot_pvc_send_inc_window, tvb, hdr_offset, 1, ENC_BIG_ENDIAN);
248
0
         hdr_offset += 1;
249
0
         proto_tree_add_item(xot_tree, hf_xot_pvc_send_out_window, tvb, hdr_offset, 1, ENC_BIG_ENDIAN);
250
0
         hdr_offset += 1;
251
0
         pkt_size = tvb_get_uint8(tvb, hdr_offset);
252
0
         proto_tree_add_uint_format_value(xot_tree, hf_xot_pvc_send_inc_pkt_size, tvb, hdr_offset, 1, pkt_size, "2^%u", pkt_size);
253
0
         hdr_offset += 1;
254
0
         pkt_size = tvb_get_uint8(tvb, hdr_offset);
255
0
         proto_tree_add_uint_format_value(xot_tree, hf_xot_pvc_send_out_pkt_size, tvb, hdr_offset, 1, pkt_size, "2^%u", pkt_size);
256
0
         hdr_offset += 1;
257
0
         proto_tree_add_item(xot_tree, hf_xot_pvc_init_itf_name, tvb, hdr_offset, init_itf_name_len, ENC_ASCII);
258
0
         hdr_offset += init_itf_name_len;
259
0
         proto_tree_add_item(xot_tree, hf_xot_pvc_resp_itf_name, tvb, hdr_offset, resp_itf_name_len, ENC_ASCII);
260
85
      } else {
261
85
         next_tvb = tvb_new_subset_length(tvb, offset, plen);
262
85
         call_dissector(x25_handle, next_tvb, pinfo, tree);
263
85
      }
264
85
   }
265
266
283
   return tvb_captured_length(tvb);
267
283
}
268
269
static int dissect_xot_mult(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
270
0
{
271
0
   int offset = 0;
272
0
   int len = get_xot_pdu_len_mult(pinfo, tvb, offset, NULL);
273
0
   tvbuff_t   *next_tvb;
274
0
   int offset_max = offset+MIN(len,tvb_captured_length_remaining(tvb, offset));
275
0
   proto_item *ti;
276
0
   proto_tree *xot_tree;
277
278
0
   if (tree) {
279
      /* Special header to show segments */
280
0
      ti = proto_tree_add_protocol_format(tree, proto_xot, tvb, offset, offset_max-offset,
281
0
                                          "X.25 over TCP - X.25 Sequence");
282
0
      xot_tree = proto_item_add_subtree(ti, ett_xot);
283
0
      proto_tree_add_uint(xot_tree, hf_xot_length, tvb, offset, offset_max, len);
284
0
   }
285
286
0
   while (offset <= offset_max - XOT_HEADER_LENGTH){
287
0
      int plen = get_xot_pdu_len(pinfo, tvb, offset, NULL);
288
0
      next_tvb = tvb_new_subset_length(tvb, offset, plen);
289
290
0
      dissect_xot_pdu(next_tvb, pinfo, tree, data);
291
0
      offset += plen;
292
0
   }
293
0
   return tvb_captured_length(tvb);
294
0
}
295
296
static int
297
dissect_xot_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
298
38
{
299
38
   if (!x25_desegment || !xot_desegment){
300
38
      tcp_dissect_pdus(tvb, pinfo, tree, xot_desegment,
301
38
                       XOT_HEADER_LENGTH,
302
38
                       get_xot_pdu_len,
303
38
                       dissect_xot_pdu, data);
304
38
   } else {
305
      /* Use length version that "peeks" into X25, possibly several XOT packets */
306
0
      tcp_dissect_pdus(tvb, pinfo, tree, xot_desegment,
307
0
                       XOT_HEADER_LENGTH,
308
0
                       get_xot_pdu_len_mult,
309
0
                       dissect_xot_mult, data);
310
0
   }
311
38
   return tvb_reported_length(tvb);
312
38
}
313
314
static int dissect_xot_tcp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
315
25
{
316
25
   int tvb_len = tvb_captured_length(tvb);
317
25
   conversation_t *conversation;
318
319
25
   if (tvb_len < 2 || tvb_get_ntohs(tvb, 0) != XOT_VERSION) {
320
4
      return 0;
321
4
   }
322
323
21
   conversation = find_or_create_conversation(pinfo);
324
21
   conversation_set_dissector(conversation, xot_tcp_handle);
325
326
21
   return dissect_xot_tcp(tvb, pinfo, tree, data);
327
25
}
328
329
/* Register the protocol with Wireshark */
330
void
331
proto_register_xot(void)
332
14
{
333
14
   static hf_register_info hf[] = {
334
14
      { &hf_xot_version,
335
14
        { "Version", "xot.version", FT_UINT16, BASE_DEC,
336
14
          NULL, 0, "Version of X.25 over TCP protocol", HFILL }},
337
338
14
      { &hf_xot_length,
339
14
        { "Length", "xot.length", FT_UINT16, BASE_DEC,
340
14
          NULL, 0, "Length of X.25 over TCP packet", HFILL }},
341
      /* These fields are in overlay with packet-x25.c */
342
14
      { &hf_x25_gfi,
343
14
        { "GFI", "x25.gfi", FT_UINT16, BASE_DEC,
344
14
          NULL, 0xF000, "General Format Identifier", HFILL }},
345
346
14
      { &hf_x25_lcn,
347
14
        { "Logical Channel", "x25.lcn", FT_UINT16, BASE_DEC,
348
14
          NULL, 0x0FFF, "Logical Channel Number", HFILL }},
349
350
14
      { &hf_x25_type,
351
14
        { "Packet Type", "x25.type", FT_UINT8, BASE_HEX,
352
14
          VALS(vals_x25_type), 0x0, NULL, HFILL }},
353
354
14
      { &hf_xot_pvc_version,
355
14
        { "Version", "xot.pvc.version", FT_UINT8, BASE_HEX,
356
14
          NULL, 0, NULL, HFILL }},
357
358
14
      { &hf_xot_pvc_status,
359
14
        { "Status", "xot.pvc.status", FT_UINT8, BASE_HEX,
360
14
          VALS(xot_pvc_status_vals), 0, NULL, HFILL }},
361
362
14
      { &hf_xot_pvc_init_itf_name_len,
363
14
        { "Initiator interface name length", "xot.pvc.init_itf_name_len", FT_UINT8, BASE_DEC,
364
14
          NULL, 0, NULL, HFILL }},
365
366
14
      { &hf_xot_pvc_init_lcn,
367
14
        { "Initiator LCN", "xot.pvc.init_lcn", FT_UINT16, BASE_DEC,
368
14
          NULL, 0, "Initiator Logical Channel Number", HFILL }},
369
370
14
      { &hf_xot_pvc_resp_itf_name_len,
371
14
        { "Responder interface name length", "xot.pvc.resp_itf_name_len", FT_UINT8, BASE_DEC,
372
14
          NULL, 0, NULL, HFILL }},
373
374
14
      { &hf_xot_pvc_resp_lcn,
375
14
        { "Responder LCN", "xot.pvc.resp_lcn", FT_UINT16, BASE_DEC,
376
14
          NULL, 0, "Responder Logical Channel Number", HFILL }},
377
378
14
      { &hf_xot_pvc_send_inc_window,
379
14
        { "Sender incoming window", "xot.pvc.send_inc_window", FT_UINT8, BASE_DEC,
380
14
          NULL, 0, NULL, HFILL }},
381
382
14
      { &hf_xot_pvc_send_out_window,
383
14
        { "Sender outgoing window", "xot.pvc.send_out_window", FT_UINT8, BASE_DEC,
384
14
          NULL, 0, NULL, HFILL }},
385
386
14
      { &hf_xot_pvc_send_inc_pkt_size,
387
14
        { "Sender incoming packet size", "xot.pvc.send_inc_pkt_size", FT_UINT8, BASE_DEC,
388
14
          NULL, 0, NULL, HFILL }},
389
390
14
      { &hf_xot_pvc_send_out_pkt_size,
391
14
        { "Sender outgoing packet size", "xot.pvc.send_out_pkt_size", FT_UINT8, BASE_DEC,
392
14
          NULL, 0, NULL, HFILL }},
393
394
14
      { &hf_xot_pvc_init_itf_name,
395
14
        { "Initiator interface name", "xot.pvc.init_itf_name", FT_STRING, BASE_NONE,
396
14
          NULL, 0, NULL, HFILL }},
397
398
14
      { &hf_xot_pvc_resp_itf_name,
399
14
        { "Responder interface name", "xot.pvc.resp_itf_name", FT_STRING, BASE_NONE,
400
14
          NULL, 0, NULL, HFILL }}
401
14
   };
402
403
14
   static int *ett[] = {
404
14
      &ett_xot
405
14
   };
406
14
   module_t *xot_module;
407
408
14
   proto_xot = proto_register_protocol("X.25 over TCP", "XOT", "xot");
409
14
   proto_register_field_array(proto_xot, hf, array_length(hf));
410
14
   proto_register_subtree_array(ett, array_length(ett));
411
14
   xot_handle = register_dissector("xot", dissect_xot_tcp_heur, proto_xot);
412
14
   xot_tcp_handle = create_dissector_handle(dissect_xot_tcp, proto_xot);
413
14
   xot_module = prefs_register_protocol(proto_xot, NULL);
414
415
14
   prefs_register_bool_preference(xot_module, "desegment",
416
14
      "Reassemble X.25-over-TCP messages spanning multiple TCP segments",
417
14
      "Whether the X.25-over-TCP dissector should reassemble messages spanning multiple TCP segments. "
418
14
      "To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings",
419
14
      &xot_desegment);
420
14
   prefs_register_bool_preference(xot_module, "x25_desegment",
421
14
      "Reassemble X.25 packets with More flag to enable safe X.25 reassembly",
422
14
      "Whether the X.25-over-TCP dissector should reassemble all X.25 packets before calling the X25 dissector. "
423
14
      "If the TCP packets arrive out-of-order, the X.25 reassembly can otherwise fail. "
424
14
      "To use this option, you should also enable \"Reassemble X.25-over-TCP messages spanning multiple TCP segments\", \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings and \"Reassemble fragmented X.25 packets\" in the X.25 protocol settings.",
425
14
      &x25_desegment);
426
427
14
}
428
429
void
430
proto_reg_handoff_xot(void)
431
14
{
432
14
   dissector_add_uint_with_preference("tcp.port", TCP_PORT_XOT, xot_handle);
433
434
14
   x25_handle = find_dissector_add_dependency("x.25", proto_xot);
435
14
}
436
437
/*
438
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
439
 *
440
 * Local Variables:
441
 * c-basic-offset: 3
442
 * tab-width: 8
443
 * indent-tabs-mode: nil
444
 * End:
445
 *
446
 * ex: set shiftwidth=3 tabstop=8 expandtab:
447
 * :indentSize=3:tabSize=8:noTabs=true:
448
 */