Coverage Report

Created: 2026-07-12 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-indigocare-icall.c
Line
Count
Source
1
/* packet-indigocare-icall.c
2
 * Dissector routines for the IndigoCare iCall protocol
3
 * By Erik de Jong <erikdejong@gmail.com>
4
 * Copyright 2016 Erik de Jong
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 <range.h>
16
#include <epan/packet.h>
17
#include <epan/expert.h>
18
19
0
#define INDIGOCARE_ICALL_SOH      0x01
20
0
#define INDIGOCARE_ICALL_STX      0x02
21
0
#define INDIGOCARE_ICALL_ETX      0x03
22
0
#define INDIGOCARE_ICALL_EOT      0x04
23
#define INDIGOCARE_ICALL_ACK      0x06
24
0
#define INDIGOCARE_ICALL_US     0x1F
25
0
#define INDIGOCARE_ICALL_RS     0x1E
26
27
0
#define INDIGOCARE_ICALL_CALL     0x0A
28
29
0
#define INDIGOCARE_ICALL_CALL_ROOM    0x01
30
0
#define INDIGOCARE_ICALL_CALL_TYPE    0x02
31
0
#define INDIGOCARE_ICALL_CALL_ADDITION    0x03
32
0
#define INDIGOCARE_ICALL_CALL_ID    0x04
33
0
#define INDIGOCARE_ICALL_CALL_TASK    0x05
34
0
#define INDIGOCARE_ICALL_CALL_LOCATION    0x06
35
0
#define INDIGOCARE_ICALL_CALL_NAME1   0x07
36
0
#define INDIGOCARE_ICALL_CALL_NAME2   0x08
37
0
#define INDIGOCARE_ICALL_CALL_TYPE_NUMERICAL  0x09
38
0
#define INDIGOCARE_ICALL_CALL_NURSE   0x0A
39
40
void proto_reg_handoff_icall(void);
41
void proto_register_icall(void);
42
43
static dissector_handle_t icall_handle;
44
45
static expert_field ei_icall_unexpected_header;
46
static expert_field ei_icall_unexpected_record;
47
static expert_field ei_icall_unexpected_end;
48
49
static int proto_icall;
50
static int hf_icall_header_type;
51
52
static int hf_icall_call_room_type;
53
static int hf_icall_call_type_type;
54
static int hf_icall_call_addition_type;
55
static int hf_icall_call_id_type;
56
static int hf_icall_call_task_type;
57
static int hf_icall_call_location_type;
58
static int hf_icall_call_name1_type;
59
static int hf_icall_call_name2_type;
60
static int hf_icall_call_numerical_type;
61
static int hf_icall_call_nurse_type;
62
63
static int hf_icall_padding_type;
64
65
static int ett_icall;
66
static int ett_icall_call;
67
static int ett_icall_unknown;
68
69
static const value_string icall_headertypenames[] = {
70
  { INDIGOCARE_ICALL_CALL,    "Call Info" },
71
  { 0, NULL }
72
};
73
74
static int
75
dissect_icall(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void *data _U_)
76
0
{
77
0
  proto_item *ti;
78
0
  proto_item *header_item;
79
0
  proto_tree *icall_tree;
80
0
  proto_tree *icall_header_tree;
81
0
  uint32_t current_offset = 0, header_offset, identifier_start, identifier_offset, data_start, data_offset, ett;
82
0
  int32_t header;
83
0
  int32_t record_identifier;
84
0
  const uint8_t * record_data;
85
86
  /* Starts with SOH */
87
0
  if ( tvb_get_uint8(tvb, 0) != INDIGOCARE_ICALL_SOH )
88
0
    return 0;
89
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "iCall");
90
0
  col_clear(pinfo->cinfo,COL_INFO);
91
0
  ti = proto_tree_add_item(tree, proto_icall, tvb, 0, -1, ENC_NA);
92
0
  icall_tree = proto_item_add_subtree(ti, ett_icall);
93
0
  current_offset++;
94
95
  /* Read header */
96
0
  tvb_find_uint8_remaining(tvb, current_offset, INDIGOCARE_ICALL_STX, &header_offset);
97
0
  tvb_get_string_int(tvb, current_offset, header_offset - current_offset, ENC_STR_DEC, &header, NULL);
98
0
  col_add_fstr(pinfo->cinfo, COL_INFO, "%s:", val_to_str(pinfo->pool, header, icall_headertypenames, "Unknown (%d)"));
99
0
  switch(header) {
100
0
    case INDIGOCARE_ICALL_CALL:
101
0
      ett = ett_icall_call;
102
0
    break;
103
0
    default:
104
0
      proto_tree_add_expert_format(icall_tree, pinfo, &ei_icall_unexpected_header, tvb, current_offset, header_offset -  current_offset, "Unexpected header %d", header);
105
0
      return 0;
106
0
    break;
107
0
  }
108
0
  header_item = proto_tree_add_uint_format(icall_tree, hf_icall_header_type, tvb, current_offset, header_offset - current_offset, header, "%s", val_to_str(pinfo->pool, header, icall_headertypenames, "Unknown (%d)"));
109
0
  icall_header_tree = proto_item_add_subtree(header_item, ett);
110
0
  current_offset = header_offset + 1;
111
112
  /* Read records */
113
0
  while (tvb_get_uint8(tvb, current_offset) != INDIGOCARE_ICALL_ETX) {
114
0
    identifier_start = current_offset;
115
0
    tvb_find_uint8_remaining(tvb, current_offset, INDIGOCARE_ICALL_US, &identifier_offset);
116
0
    tvb_get_string_int(tvb, current_offset, identifier_offset - current_offset, ENC_STR_DEC, &record_identifier, NULL);
117
0
    current_offset = identifier_offset + 1;
118
119
0
    data_start = current_offset;
120
0
    tvb_find_uint8_remaining(tvb, data_start, INDIGOCARE_ICALL_RS, &data_offset);
121
0
    record_data = tvb_get_string_enc(pinfo->pool, tvb, current_offset, data_offset - data_start, ENC_ASCII|ENC_NA);
122
123
0
    current_offset = data_offset + 1;
124
125
0
    switch (header) {
126
0
      case INDIGOCARE_ICALL_CALL:
127
0
        switch (record_identifier) {
128
0
          case INDIGOCARE_ICALL_CALL_ROOM:
129
0
            proto_tree_add_item_ret_string(icall_header_tree, hf_icall_call_room_type, tvb, data_start, data_offset - data_start, ENC_ASCII|ENC_NA, pinfo->pool, &record_data);
130
0
            col_append_fstr(pinfo->cinfo, COL_INFO, " Room=%s", record_data);
131
0
          break;
132
0
          case INDIGOCARE_ICALL_CALL_TYPE:
133
0
            proto_tree_add_item_ret_string(icall_header_tree, hf_icall_call_type_type, tvb, data_start, data_offset - data_start, ENC_ASCII|ENC_NA, pinfo->pool, &record_data);
134
0
            col_append_fstr(pinfo->cinfo, COL_INFO, " Type=%s", record_data);
135
0
          break;
136
0
          case INDIGOCARE_ICALL_CALL_ADDITION:
137
0
            proto_tree_add_item(icall_header_tree, hf_icall_call_addition_type, tvb, data_start, data_offset - data_start, ENC_ASCII);
138
0
          break;
139
0
          case INDIGOCARE_ICALL_CALL_ID:
140
0
            proto_tree_add_item(icall_header_tree, hf_icall_call_id_type, tvb, data_start, data_offset - data_start, ENC_ASCII);
141
0
          break;
142
0
          case INDIGOCARE_ICALL_CALL_TASK:
143
0
            proto_tree_add_item(icall_header_tree, hf_icall_call_task_type, tvb, data_start, data_offset - data_start, ENC_ASCII);
144
0
          break;
145
0
          case INDIGOCARE_ICALL_CALL_LOCATION:
146
0
            proto_tree_add_item_ret_string(icall_header_tree, hf_icall_call_location_type, tvb, data_start, data_offset - data_start, ENC_ASCII|ENC_NA, pinfo->pool, &record_data);
147
0
            col_append_fstr(pinfo->cinfo, COL_INFO, " Location=%s", record_data);
148
0
          break;
149
0
          case INDIGOCARE_ICALL_CALL_NAME1:
150
0
            proto_tree_add_item_ret_string(icall_header_tree, hf_icall_call_name1_type, tvb, data_start, data_offset - data_start, ENC_ASCII|ENC_NA, pinfo->pool, &record_data);
151
0
            col_append_fstr(pinfo->cinfo, COL_INFO, " Name 1=%s", record_data);
152
0
          break;
153
0
          case INDIGOCARE_ICALL_CALL_NAME2:
154
0
            proto_tree_add_item_ret_string(icall_header_tree, hf_icall_call_name2_type, tvb, data_start, data_offset - data_start, ENC_ASCII|ENC_NA, pinfo->pool, &record_data);
155
0
            col_append_fstr(pinfo->cinfo, COL_INFO, " Name 2=%s", record_data);
156
0
          break;
157
0
          case INDIGOCARE_ICALL_CALL_TYPE_NUMERICAL:
158
0
            proto_tree_add_item(icall_header_tree, hf_icall_call_numerical_type, tvb, data_start, data_offset - data_start, ENC_ASCII);
159
0
          break;
160
0
          case INDIGOCARE_ICALL_CALL_NURSE:
161
0
            proto_tree_add_item(icall_header_tree, hf_icall_call_nurse_type, tvb, data_start, data_offset - data_start, ENC_ASCII);
162
0
          break;
163
0
          default:
164
0
            proto_tree_add_expert_format(icall_header_tree, pinfo, &ei_icall_unexpected_record, tvb, identifier_start, data_offset - identifier_start, "Unexpected record %d with value %s", record_identifier, record_data);
165
0
          break;
166
0
        }
167
0
      break;
168
0
    }
169
0
  }
170
0
  current_offset++;
171
0
  if (tvb_get_uint8(tvb, current_offset) != INDIGOCARE_ICALL_EOT) {
172
    /* Malformed packet terminator */
173
0
    proto_tree_add_expert(icall_header_tree, pinfo, &ei_icall_unexpected_end, tvb, current_offset, 1);
174
0
    return tvb_captured_length(tvb);
175
0
  }
176
0
  current_offset++;
177
0
  if (tvb_captured_length_remaining(tvb, current_offset)) {
178
    /* Padding */
179
0
    proto_tree_add_item(icall_header_tree, hf_icall_padding_type, tvb, current_offset, tvb_captured_length_remaining(tvb, current_offset), ENC_NA);
180
0
  }
181
0
  return tvb_captured_length(tvb);
182
0
}
183
184
void
185
proto_reg_handoff_icall(void)
186
15
{
187
15
  dissector_add_for_decode_as("udp.port", icall_handle);
188
15
  dissector_add_for_decode_as("tcp.port", icall_handle);
189
15
}
190
191
void
192
proto_register_icall(void)
193
15
{
194
15
  static hf_register_info hf[] = {
195
15
  { &hf_icall_header_type,
196
15
    { "Header Type", "icall.header",
197
15
    FT_UINT32, BASE_DEC,
198
15
    VALS(icall_headertypenames), 0x0,
199
15
    NULL, HFILL }
200
15
  },
201
15
  { &hf_icall_call_room_type,
202
15
    { "Room", "icall.call.room",
203
15
    FT_STRING, BASE_NONE,
204
15
    NULL, 0x0,
205
15
    NULL, HFILL }
206
15
  },
207
15
  { &hf_icall_call_type_type,
208
15
    { "Type", "icall.call.type",
209
15
    FT_STRING, BASE_NONE,
210
15
    NULL, 0x0,
211
15
    NULL, HFILL }
212
15
  },
213
15
  { &hf_icall_call_addition_type,
214
15
    { "Addition", "icall.call.addition",
215
15
    FT_STRING, BASE_NONE,
216
15
    NULL, 0x0,
217
15
    NULL, HFILL }
218
15
  },
219
15
  { &hf_icall_call_id_type,
220
15
    { "ID", "icall.call.id",
221
15
    FT_STRING, BASE_NONE,
222
15
    NULL, 0x0,
223
15
    NULL, HFILL }
224
15
  },
225
15
  { &hf_icall_call_task_type,
226
15
    { "Task", "icall.call.task",
227
15
    FT_STRING, BASE_NONE,
228
15
    NULL, 0x0,
229
15
    NULL, HFILL }
230
15
  },
231
15
  { &hf_icall_call_location_type,
232
15
    { "Location", "icall.call.location",
233
15
    FT_STRING, BASE_NONE,
234
15
    NULL, 0x0,
235
15
    NULL, HFILL }
236
15
  },
237
15
  { &hf_icall_call_name1_type,
238
15
    { "Name 1", "icall.call.name1",
239
15
    FT_STRING, BASE_NONE,
240
15
    NULL, 0x0,
241
15
    NULL, HFILL }
242
15
  },
243
15
  { &hf_icall_call_name2_type,
244
15
    { "Name 2", "icall.call.name2",
245
15
    FT_STRING, BASE_NONE,
246
15
    NULL, 0x0,
247
15
    NULL, HFILL }
248
15
  },
249
15
  { &hf_icall_call_numerical_type,
250
15
    { "Type Numerical", "icall.call.type_numerical",
251
15
    FT_STRING, BASE_NONE,
252
15
    NULL, 0x0,
253
15
    NULL, HFILL }
254
15
  },
255
15
  { &hf_icall_call_nurse_type,
256
15
    { "Nurse", "icall.call.nurse",
257
15
    FT_STRING, BASE_NONE,
258
15
    NULL, 0x0,
259
15
    NULL, HFILL }
260
15
  },
261
15
  { &hf_icall_padding_type,
262
15
    { "Padding", "icall.padding",
263
15
    FT_BYTES, BASE_NONE,
264
15
    NULL, 0x0,
265
15
    NULL, HFILL }
266
15
  }
267
15
  };
268
269
15
  static ei_register_info ei[] = {
270
15
    { &ei_icall_unexpected_header, { "icall.unexpected.header", PI_MALFORMED, PI_WARN, "Unexpected header", EXPFILL }},
271
15
    { &ei_icall_unexpected_record, { "icall.unexpected.record", PI_MALFORMED, PI_WARN, "Unexpected record", EXPFILL }},
272
15
    { &ei_icall_unexpected_end, { "icall.unexpected.end", PI_MALFORMED, PI_WARN, "Unexpected end of packet", EXPFILL }}
273
15
  };
274
275
15
  expert_module_t* expert_icall;
276
277
  /* Setup protocol subtree array */
278
15
  static int *ett[] = {
279
15
    &ett_icall,
280
15
    &ett_icall_call,
281
15
    &ett_icall_unknown
282
15
  };
283
284
15
  proto_icall = proto_register_protocol ("iCall Communication Protocol", "iCall", "icall");
285
286
15
  proto_register_field_array(proto_icall, hf, array_length(hf));
287
15
  proto_register_subtree_array(ett, array_length(ett));
288
289
15
  expert_icall = expert_register_protocol(proto_icall);
290
15
  expert_register_field_array(expert_icall, ei, array_length(ei));
291
292
15
  icall_handle = register_dissector("icall", dissect_icall, proto_icall);
293
15
}
294
295
/*
296
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
297
 *
298
 * Local variables:
299
 * c-basic-offset: 8
300
 * tab-width: 8
301
 * indent-tabs-mode: t
302
 * End:
303
 *
304
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
305
 * :indentSize=8:tabSize=8:noTabs=false:
306
 */