Coverage Report

Created: 2025-02-15 06:25

/src/wireshark/epan/dissectors/packet-uts.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-uts.c
2
 * Routines for UTS WAN protocol dissection
3
 * Copyright 2007, Fulko Hew, SITA INC Canada, Inc.
4
 *
5
 * Copied from packet-ipars.c
6
 *
7
 * Wireshark - Network traffic analyzer
8
 * By Gerald Combs <gerald@wireshark.org>
9
 * Copyright 1998 Gerald Combs
10
 *
11
 * SPDX-License-Identifier: GPL-2.0-or-later
12
 */
13
14
/* Use tabstops = 4 */
15
16
#include "config.h"
17
18
#include <epan/packet.h>
19
#include <wiretap/wtap.h>
20
#include <wsutil/str_util.h>
21
22
0
#define SOH (0x01)
23
0
#define STX (0x02)
24
0
#define ETX (0x03)
25
0
#define EOT (0x04)
26
0
#define ENQ (0x05)
27
0
#define BEL (0x07)
28
0
#define NAK (0x15)
29
0
#define DLE (0x10)
30
31
0
#define GRID  (0x20)
32
0
#define GSID  (0x50)
33
0
#define GDID  (0x70)
34
35
#define MAX_POLL_TYPE_MSG_SIZE  (50)
36
37
void proto_register_uts(void);
38
39
static int  proto_uts;
40
static int  ett_uts;
41
static int  ett_header_uts;
42
static int  ett_trailer_uts;
43
static int  hf_rid;
44
static int  hf_sid;
45
static int  hf_did;
46
static int  hf_retxrequest;
47
static int  hf_ack;
48
static int  hf_replyrequest;
49
static int  hf_busy;
50
static int  hf_notbusy;
51
static int  hf_msgwaiting;
52
static int  hf_function;
53
static int  hf_data;
54
55
0
#define MATCH (1)
56
0
#define FETCH (2)
57
58
0
#define SRC (1)
59
0
#define DST (2)
60
61
static int testchar(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, int op, char match, char *storage)
62
0
{
63
0
  char temp;
64
65
0
  if (tvb_bytes_exist(tvb, offset, 1)) {
66
0
    temp = tvb_get_uint8(tvb, offset) & 0x7f;
67
0
    if (op == FETCH || (op == MATCH && temp == match)) {
68
0
      if (storage != NULL)
69
0
        *storage = temp;
70
0
      return 1;
71
0
    } else {
72
0
      return 0;
73
0
    }
74
0
  } else {
75
0
    col_set_str(pinfo->cinfo, COL_INFO, "Unknown Message Format");
76
0
    return 0;
77
0
  }
78
0
}
79
80
static void
81
set_addr(packet_info *pinfo _U_ , int field, char rid, char sid, char did)
82
0
{
83
0
  if (field == SRC) {
84
0
    col_append_fstr(pinfo->cinfo, COL_DEF_SRC, " %2.2X:%2.2X:%2.2X", rid, sid, did);
85
0
  } else {
86
0
    col_append_fstr(pinfo->cinfo, COL_DEF_DST, " %2.2X:%2.2X:%2.2X", rid, sid, did);
87
0
  }
88
0
}
89
90
static int
91
dissect_uts(tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree, void* data _U_)
92
0
{
93
0
  proto_tree  *uts_tree   = NULL;
94
0
  proto_tree  *uts_header_tree  = NULL;
95
0
  proto_tree  *uts_trailer_tree = NULL;
96
0
  proto_item  *ti;
97
0
  int   length;
98
0
  char    rid = 0, sid = 0, did = 0;
99
0
  int   offset      = 0;
100
0
  int   header_length   = -1;
101
0
  int   ack_start   = 0;
102
0
  int   busy_start    = 0;
103
0
  int   notbusy_start   = 0;
104
0
  int   replyrequest_start  = 0;
105
0
  int   function_start    = 0;
106
0
  int   msgwaiting_start  = 0;
107
0
  int   nak_start   = 0;
108
0
  int   etx_start   = 0;
109
0
  int   bcc_start   = 0;
110
0
  int   stx_start   = 0;
111
0
  char    function_code;
112
0
  uint8_t   *data_ptr;
113
114
0
  enum  { NOTRAFFIC, OTHER }  msg_type = OTHER;
115
116
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "UTS");
117
118
0
  if (testchar(tvb, pinfo, 0, MATCH, EOT, NULL)   &&
119
0
    testchar(tvb, pinfo, 1, MATCH, EOT, NULL) &&
120
0
    testchar(tvb, pinfo, 2, MATCH, ETX, NULL)) {
121
0
    msg_type = NOTRAFFIC;
122
0
    col_set_str(pinfo->cinfo, COL_INFO, "No Traffic");
123
0
  } else {
124
0
    if (testchar(tvb, pinfo, 0, MATCH, SOH, NULL)   &&
125
0
        testchar(tvb, pinfo, 1, FETCH, 0, (char *)&rid)  &&
126
0
        testchar(tvb, pinfo, 2, FETCH, 0, (char *)&sid)  &&
127
0
        testchar(tvb, pinfo, 3, FETCH, 0, (char *)&did)) {
128
0
      offset = 4;
129
0
      if (testchar(tvb, pinfo, offset, MATCH, ETX, NULL)) {
130
0
        col_set_str(pinfo->cinfo, COL_INFO, "General Poll");
131
0
        set_addr(pinfo, DST, rid, sid, did);
132
0
      } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) &&
133
0
           testchar(tvb, pinfo, offset+1, MATCH, '1', NULL)  &&
134
0
           testchar(tvb, pinfo, offset+2, MATCH, ETX, NULL)) {
135
0
        ack_start = offset;
136
0
        if (sid == GSID && did == GDID) {
137
0
          col_set_str(pinfo->cinfo, COL_INFO, "General Poll + ACK");
138
0
          set_addr(pinfo, DST, rid, sid, did);
139
0
        } else if (sid != GSID && did == GDID) {
140
0
          col_set_str(pinfo->cinfo, COL_INFO, "Specific Poll + ACK");
141
0
          set_addr(pinfo, DST, rid, sid, did);
142
0
        } else if (sid != GSID && did != GDID) {
143
0
          col_set_str(pinfo->cinfo, COL_INFO, "No Traffic + ACK");
144
0
          set_addr(pinfo, SRC, rid, sid, did);
145
0
        } else {
146
0
          col_set_str(pinfo->cinfo, COL_INFO, "Unknown Message Format");
147
0
          if ((pinfo->pseudo_header->sita.sita_flags & SITA_FRAME_DIR) == SITA_FRAME_DIR_TXED) {
148
0
            set_addr(pinfo, DST, rid, sid, did); /* if the ACN sent it, the address is of the destination... the terminal */
149
0
          } else {
150
0
            set_addr(pinfo, SRC, rid, sid, did); /* if the ACN received it, the address if of the source... the terminal */
151
0
          }
152
0
        }
153
0
      } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) &&
154
0
           testchar(tvb, pinfo, offset+1, MATCH, NAK, NULL) &&
155
0
           testchar(tvb, pinfo, offset+2, MATCH, ETX, NULL) &&
156
0
           sid != GSID && did == GDID) {
157
0
        nak_start = offset;
158
0
        col_set_str(pinfo->cinfo, COL_INFO, "Retransmit Request");
159
0
        set_addr(pinfo, DST, rid, sid, did);
160
0
      } else if (testchar(tvb, pinfo, offset, MATCH, BEL, NULL) &&
161
0
           testchar(tvb, pinfo, offset+1, MATCH, STX, NULL) &&
162
0
           testchar(tvb, pinfo, offset+2, MATCH, ETX, NULL)) {
163
0
        header_length = offset+2;
164
0
        msgwaiting_start = offset;
165
0
        col_set_str(pinfo->cinfo, COL_INFO, "Message Waiting");
166
0
        set_addr(pinfo, DST, rid, sid, did);
167
0
      } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) &&
168
0
           testchar(tvb, pinfo, offset+1, MATCH, '1', NULL)  &&
169
0
           testchar(tvb, pinfo, offset+2, MATCH, STX, NULL)) {
170
0
        ack_start = offset;
171
0
        header_length = offset+3;
172
0
        stx_start = offset+2;
173
0
        col_set_str(pinfo->cinfo, COL_INFO, "Text + ACK");
174
0
        set_addr(pinfo, SRC, rid, sid, did);
175
0
      } else if (testchar(tvb, pinfo, offset, MATCH, STX, NULL)) {
176
0
        header_length = offset+1;
177
0
        stx_start = offset;
178
0
        col_set_str(pinfo->cinfo, COL_INFO, "Text");
179
0
        if ((pinfo->pseudo_header->sita.sita_flags & SITA_FRAME_DIR) == SITA_FRAME_DIR_TXED) {
180
0
          set_addr(pinfo, DST, rid, sid, did);   /* if the ACN sent it, the address is of the destination... the terminal */
181
0
        } else {
182
0
          set_addr(pinfo, SRC, rid, sid, did);   /* if the ACN received it, the address if of the source... the terminal */
183
0
        }
184
0
      } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) &&
185
0
           testchar(tvb, pinfo, offset+1, MATCH, ENQ, NULL) &&
186
0
           testchar(tvb, pinfo, offset+2, MATCH, ETX, NULL)) {
187
0
        replyrequest_start = offset;
188
0
        col_set_str(pinfo->cinfo, COL_INFO, "Reply Request");
189
0
        set_addr(pinfo, SRC, rid, sid, did);
190
0
      } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) &&
191
0
           testchar(tvb, pinfo, offset+1, MATCH, '?', NULL)  &&
192
0
           testchar(tvb, pinfo, offset+2, MATCH, ETX, NULL)) {
193
0
        busy_start = offset;
194
0
        col_set_str(pinfo->cinfo, COL_INFO, "Busy");
195
0
        set_addr(pinfo, SRC, rid, sid, did);
196
0
      } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) &&
197
0
           testchar(tvb, pinfo, offset+1, MATCH, ';', NULL)  &&
198
0
           testchar(tvb, pinfo, offset+2, MATCH, ETX, NULL)) {
199
0
        notbusy_start = offset;
200
0
        col_set_str(pinfo->cinfo, COL_INFO, "Not Busy");
201
0
        set_addr(pinfo, SRC, rid, sid, did);
202
0
      } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL) &&
203
0
           testchar(tvb, pinfo, offset+1, MATCH, '1', NULL)  &&
204
0
           testchar(tvb, pinfo, offset+2, MATCH, DLE, NULL) &&
205
0
           testchar(tvb, pinfo, offset+3, MATCH, ';', NULL)  &&
206
0
           testchar(tvb, pinfo, offset+4, MATCH, ETX, NULL)) {
207
0
        notbusy_start = offset+2;
208
0
        ack_start = offset;
209
0
        col_set_str(pinfo->cinfo, COL_INFO, "Not Busy + ACK");
210
0
        set_addr(pinfo, SRC, rid, sid, did);
211
0
      } else if (testchar(tvb, pinfo, offset, MATCH, DLE, NULL)   &&
212
0
           testchar(tvb, pinfo, offset+1, MATCH, '1', NULL)    &&
213
0
           testchar(tvb, pinfo, offset+2, FETCH, 0, &function_code)  &&
214
0
           testchar(tvb, pinfo, offset+3, MATCH, ETX, NULL)) {
215
0
        ack_start = offset;
216
0
        function_start = offset + 2;
217
0
        col_add_fstr(pinfo->cinfo, COL_INFO, "Function Message '%c' + ACK", function_code);
218
0
        set_addr(pinfo, SRC, rid, sid, did);
219
0
      } else if (testchar(tvb, pinfo, offset, FETCH, 0, &function_code)  &&
220
0
           testchar(tvb, pinfo, offset+1, MATCH, ETX, NULL)) {
221
0
        function_start = offset;
222
0
        col_add_fstr(pinfo->cinfo, COL_INFO, "Function Message '%c'", function_code);
223
0
        set_addr(pinfo, SRC, rid, sid, did);
224
0
      }
225
0
    }
226
0
  }
227
228
0
  while (tvb_reported_length_remaining(tvb, offset) > 0) {         /* now look for the ETX */
229
0
    if ((tvb_get_uint8(tvb, offset) & 0x7f) == ETX) {
230
0
      if (header_length == -1)
231
0
        header_length = offset; /* the header ends at an STX, or if not found, the ETX */
232
0
      etx_start = offset;
233
0
      offset++;
234
0
      break;
235
0
    }
236
0
    offset++;
237
0
  }
238
0
  if (tvb_reported_length_remaining(tvb, offset))           /* if there is anything left, it could be the BCC and pads */
239
0
    bcc_start = offset;
240
241
0
  if (tree) {
242
0
    ti = proto_tree_add_protocol_format(tree, proto_uts, tvb, 0, -1, "UTS");
243
0
    uts_tree = proto_item_add_subtree(ti, ett_uts);
244
245
0
    if (msg_type == NOTRAFFIC) {
246
0
      proto_tree_add_protocol_format(uts_tree, proto_uts, tvb, 0, 2, "No Traffic");
247
0
      proto_tree_add_protocol_format(uts_tree, proto_uts, tvb, 2, -1, "ETX + padding");
248
0
    } else {
249
0
      uts_header_tree = proto_tree_add_subtree(uts_tree, tvb, 0, header_length, ett_header_uts, NULL, "Header");
250
251
0
      proto_tree_add_protocol_format(uts_header_tree, proto_uts, tvb, 0, 1, "SOH");
252
253
0
      if (rid == GRID)
254
0
        proto_tree_add_uint_format(uts_header_tree, hf_rid, tvb, 1, 1, rid, "RID (%02X) (General)", rid);
255
0
      else
256
0
        proto_tree_add_uint_format(uts_header_tree, hf_rid, tvb, 1, 1, rid, "RID (%02X)", rid);
257
258
0
      if (sid == GSID)
259
0
        proto_tree_add_uint_format(uts_header_tree, hf_sid, tvb, 2, 1, sid, "SID (%02X) (General)", sid);
260
0
      else
261
0
        proto_tree_add_uint_format(uts_header_tree, hf_sid, tvb, 2, 1, sid, "SID (%02X)", sid);
262
263
0
      if (did == GDID)
264
0
        proto_tree_add_uint_format(uts_header_tree, hf_did, tvb, 3, 1, did, "DID (%02X) (General)", did);
265
0
      else
266
0
        proto_tree_add_uint_format(uts_header_tree, hf_did, tvb, 3, 1, did, "DID (%02X)", did);
267
268
0
      if (nak_start)
269
0
        proto_tree_add_boolean_format(uts_header_tree, hf_retxrequest,  tvb, nak_start, 2, 1, "Re-transmit Request");
270
0
      if (ack_start)
271
0
        proto_tree_add_boolean_format(uts_header_tree, hf_ack, tvb, ack_start, 2, 1, "Ack");
272
273
0
      if (replyrequest_start)
274
0
        proto_tree_add_boolean_format(uts_header_tree, hf_replyrequest, tvb, replyrequest_start, 2, 1, "Reply Request");
275
0
      if (busy_start)
276
0
        proto_tree_add_boolean_format(uts_header_tree, hf_busy, tvb, busy_start, 2, 1, "Busy");
277
278
0
      if (notbusy_start)
279
0
        proto_tree_add_boolean_format(uts_header_tree, hf_notbusy, tvb, notbusy_start, 2, 1, "Not Busy");
280
281
0
      if (msgwaiting_start)
282
0
        proto_tree_add_boolean_format(uts_header_tree, hf_msgwaiting, tvb, msgwaiting_start, 1, 1, "Message Waiting");
283
284
0
      if (function_start)
285
0
        proto_tree_add_uint_format(uts_header_tree, hf_function, tvb, function_start, 1, function_code, "Function '%c'", function_code  );
286
287
0
      if (stx_start) {
288
0
        proto_tree_add_protocol_format(uts_header_tree, proto_uts, tvb, stx_start, 1, "Start of Text");
289
0
        length = tvb_captured_length_remaining(tvb, stx_start+1);    /* find out how much message remains      */
290
0
        if (etx_start)
291
0
          length = (etx_start - stx_start - 1);       /* and the data part is the rest...       */
292
                        /* whatever precedes the ETX if it exists */
293
0
        data_ptr = tvb_get_string_enc(pinfo->pool, tvb, stx_start+1, length, ENC_ASCII);  /* copy the string for dissecting */
294
0
        proto_tree_add_string_format(uts_tree, hf_data, tvb, stx_start + 1, length, data_ptr,
295
0
                   "Text (%d byte%s)", length, plurality(length, "", "s"));
296
0
      }
297
298
0
      if (etx_start) {
299
0
        uts_trailer_tree = proto_tree_add_subtree(uts_tree, tvb, etx_start, -1, ett_trailer_uts, NULL, "Trailer");
300
301
0
        if (etx_start)
302
0
          proto_tree_add_protocol_format(uts_trailer_tree, proto_uts, tvb, etx_start, 1, "ETX");
303
0
        if (bcc_start)
304
0
          proto_tree_add_protocol_format(uts_trailer_tree, proto_uts, tvb, bcc_start, -1, "CCC + padding");
305
0
      }
306
0
    }
307
0
  }
308
0
  return tvb_captured_length(tvb);
309
0
}
310
311
void
312
proto_register_uts(void)
313
14
{
314
14
  static hf_register_info hf[] = {
315
14
    { &hf_rid,
316
14
      { "RID",     "uts.rid",
317
14
        FT_UINT8, BASE_HEX, NULL, 0, "Remote Identifier address", HFILL }},
318
14
    { &hf_sid,
319
14
      { "SID",     "uts.sid",
320
14
        FT_UINT8, BASE_HEX, NULL, 0, "Site Identifier address", HFILL }},
321
14
    { &hf_did,
322
14
      { "DID",     "uts.did",
323
14
        FT_UINT8, BASE_HEX, NULL, 0, "Device Identifier address", HFILL }},
324
14
    { &hf_retxrequest,
325
14
      { "ReTxRequest",  "uts.retxrequest",
326
14
        FT_BOOLEAN, BASE_NONE,  NULL, 0x0, "true if Re-transmit Request", HFILL }},
327
14
    { &hf_ack,
328
14
      { "Ack",     "uts.ack",
329
14
        FT_BOOLEAN, BASE_NONE,  NULL, 0x0, "true if Ack",   HFILL }},
330
14
    { &hf_replyrequest,
331
14
      { "ReplyRequest", "uts.replyrequest",
332
14
        FT_BOOLEAN, BASE_NONE,  NULL, 0x0, "true if Reply Request", HFILL }},
333
14
    { &hf_busy,
334
14
      { "Busy",    "uts.busy",
335
14
        FT_BOOLEAN, BASE_NONE,  NULL, 0x0, "true if Busy",    HFILL }},
336
14
    { &hf_notbusy,
337
14
      { "NotBusy",     "uts.notbusy",
338
14
        FT_BOOLEAN, BASE_NONE,  NULL, 0x0, "true if Not Busy",    HFILL }},
339
14
    { &hf_msgwaiting,
340
14
      { "MsgWaiting",  "uts.msgwaiting",
341
14
        FT_BOOLEAN, BASE_NONE,  NULL, 0x0, "true if Message Waiting", HFILL }},
342
14
    { &hf_function,
343
14
      { "Function",    "uts.function",
344
14
        FT_UINT8, BASE_HEX, NULL, 0, "Function Code value",   HFILL }},
345
14
    { &hf_data,
346
14
      { "Data",    "uts.data",
347
14
        FT_STRING,  BASE_NONE,  NULL, 0, "User Data Message",   HFILL }},
348
14
  };
349
350
14
  static int *ett[] = {
351
14
    &ett_uts,
352
14
    &ett_header_uts,
353
14
    &ett_trailer_uts,
354
14
  };
355
356
14
  proto_uts = proto_register_protocol("Unisys Transmittal System", "UTS", "uts");   /* name, short name, abbrev */
357
14
  proto_register_field_array(proto_uts, hf, array_length(hf));
358
14
  proto_register_subtree_array(ett, array_length(ett));
359
14
  register_dissector("uts", dissect_uts, proto_uts);
360
14
}
361
362
/*
363
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
364
 *
365
 * Local variables:
366
 * c-basic-offset: 8
367
 * tab-width: 8
368
 * indent-tabs-mode: t
369
 * End:
370
 *
371
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
372
 * :indentSize=8:tabSize=8:noTabs=false:
373
 */