Coverage Report

Created: 2025-08-04 07:15

/src/wireshark/epan/dissectors/packet-xip-serval.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-xip-serval.c
2
 * Routines for XIP Serval dissection
3
 *
4
 * Wireshark - Network traffic analyzer
5
 * By Gerald Combs <gerald@wireshark.org>
6
 * Copyright 1998 Gerald Combs
7
 *
8
 * SPDX-License-Identifier: GPL-2.0-or-later
9
 *
10
 * Serval is a service-centric architecture that has been ported to XIA to
11
 * allow applications to communicate using service names.
12
 */
13
14
#include "config.h"
15
#include <epan/packet.h>
16
#include <epan/expert.h>
17
#include <epan/in_cksum.h>
18
#include <epan/tfs.h>
19
#include <epan/unit_strings.h>
20
21
#include <wsutil/array.h>
22
#include <ipproto.h>
23
24
void proto_register_xip_serval(void);
25
void proto_reg_handoff_xip_serval(void);
26
27
static dissector_handle_t tcp_handle;
28
static dissector_handle_t udp_handle;
29
30
static int proto_xip_serval;
31
32
/* XIP Serval header. */
33
static int hf_xip_serval_hl;
34
static int hf_xip_serval_proto;
35
static int hf_xip_serval_check;
36
static int hf_xip_serval_check_status;
37
38
/* XIP Serval general extension header. */
39
static int hf_xip_serval_ext_type;
40
static int hf_xip_serval_ext_length;
41
42
/* XIP Serval control extension header. */
43
static int hf_xip_serval_cext;
44
static int hf_xip_serval_cext_flags;
45
static int hf_xip_serval_cext_syn;
46
static int hf_xip_serval_cext_rsyn;
47
static int hf_xip_serval_cext_ack;
48
static int hf_xip_serval_cext_nack;
49
static int hf_xip_serval_cext_rst;
50
static int hf_xip_serval_cext_fin;
51
static int hf_xip_serval_cext_verno;
52
static int hf_xip_serval_cext_ackno;
53
static int hf_xip_serval_cext_nonce;
54
55
static int ett_xip_serval_tree;
56
static int ett_xip_serval_cext;
57
static int ett_xip_serval_cext_flags;
58
59
static expert_field ei_xip_serval_bad_len;
60
static expert_field ei_xip_serval_bad_proto;
61
static expert_field ei_xip_serval_bad_checksum;
62
static expert_field ei_xip_serval_bad_ext;
63
64
1
#define XIP_SERVAL_PROTO_DATA   0
65
static const value_string xip_serval_proto_vals[] = {
66
  { XIP_SERVAL_PROTO_DATA,  "Data" },
67
  { IP_PROTO_TCP,     "TCP" },
68
  { IP_PROTO_UDP,     "UDP" },
69
  { 0,        NULL },
70
};
71
72
static int * const xip_serval_cext_flags[] = {
73
  &hf_xip_serval_cext_syn,
74
  &hf_xip_serval_cext_rsyn,
75
  &hf_xip_serval_cext_ack,
76
  &hf_xip_serval_cext_nack,
77
  &hf_xip_serval_cext_rst,
78
  &hf_xip_serval_cext_fin,
79
  NULL
80
};
81
82
13
#define XIP_SERVAL_MIN_LEN    4
83
84
39
#define XIP_SERVAL_EXT_MIN_LEN    2
85
32
#define XIP_SERVAL_EXT_TYPE_MASK  0xF0
86
25
#define XIP_SERVAL_EXT_TYPE_CONTROL 0
87
88
#define XIP_SERVAL_CEXT_FLAGS_WIDTH 8
89
#define XIP_SERVAL_CEXT_NONCE_SIZE  8
90
25
#define XIP_SERVAL_CEXT_LEN   20
91
92
26
#define XSRVL_LEN     0
93
26
#define XSRVL_PRO     1
94
13
#define XSRVL_CHK     2
95
13
#define XSRVL_EXT     4
96
97
static uint8_t
98
display_xip_serval_control_ext(tvbuff_t *tvb, proto_tree *xip_serval_tree,
99
  int offset, uint8_t type, uint8_t length)
100
25
{
101
25
  proto_tree *cext_tree;
102
25
  proto_item *ti;
103
104
  /* Create Serval Control Extension tree. */
105
25
  ti = proto_tree_add_item(xip_serval_tree, hf_xip_serval_cext, tvb,
106
25
    offset, length, ENC_NA);
107
25
  cext_tree = proto_item_add_subtree(ti, ett_xip_serval_cext);
108
109
  /* Add XIP Serval extension type. */
110
25
  proto_tree_add_uint(cext_tree, hf_xip_serval_ext_type, tvb,
111
25
    offset, 1, type);
112
25
  offset++;
113
114
  /* Add XIP Serval extension length. */
115
25
  proto_tree_add_item(cext_tree, hf_xip_serval_ext_length, tvb,
116
25
    offset, 1, ENC_BIG_ENDIAN);
117
25
  offset++;
118
119
  /* Create XIP Serval Control Extension flags tree. */
120
25
  proto_tree_add_bitmask(cext_tree, tvb, offset,
121
25
    hf_xip_serval_cext_flags, ett_xip_serval_cext_flags,
122
25
    xip_serval_cext_flags, ENC_BIG_ENDIAN);
123
124
  /* Skip two bits for res1. */
125
25
  offset++;
126
127
  /* Skip a byte for res2. */
128
25
  offset++;
129
130
  /* Add verification number. */
131
25
  proto_tree_add_item(cext_tree, hf_xip_serval_cext_verno,
132
25
    tvb, offset, 4, ENC_BIG_ENDIAN);
133
25
  offset += 4;
134
135
  /* Add acknowledgement number. */
136
25
  proto_tree_add_item(cext_tree, hf_xip_serval_cext_ackno,
137
25
    tvb, offset, 4, ENC_BIG_ENDIAN);
138
25
  offset += 4;
139
140
  /* Add nonce. */
141
25
  proto_tree_add_item(cext_tree, hf_xip_serval_cext_nonce,
142
25
    tvb, offset, 8, ENC_NA);
143
144
  /* Displayed XIP_SERVAL_CEXT_LEN bytes. */
145
25
  return XIP_SERVAL_CEXT_LEN;
146
25
}
147
148
static uint8_t
149
display_xip_serval_ext(tvbuff_t *tvb, packet_info *pinfo, proto_item *ti,
150
  proto_tree *xip_serval_tree, int offset)
151
32
{
152
32
  uint8_t type = tvb_get_uint8(tvb, offset) & XIP_SERVAL_EXT_TYPE_MASK;
153
32
  uint8_t length = tvb_get_uint8(tvb, offset + 1);
154
155
  /* For now, the only type of extension header in XIP Serval is
156
   * the control extension header.
157
   */
158
32
  switch (type) {
159
25
  case XIP_SERVAL_EXT_TYPE_CONTROL:
160
25
    return display_xip_serval_control_ext(tvb, xip_serval_tree,
161
25
      offset, type, length);
162
6
  default:
163
6
    expert_add_info_format(pinfo, ti, &ei_xip_serval_bad_ext,
164
6
      "Unrecognized Serval extension header type: 0x%02x",
165
6
      type);
166
6
    return 0;
167
32
  }
168
32
}
169
170
static void
171
display_xip_serval(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
172
13
{
173
13
  proto_tree *xip_serval_tree;
174
13
  proto_item *ti, *hl_ti;
175
13
  tvbuff_t *next_tvb;
176
177
13
  vec_t cksum_vec;
178
13
  int offset;
179
13
  uint8_t xsh_len, protocol, bytes_remaining;
180
181
  /* Get XIP Serval header length, stored as number of 32-bit words. */
182
13
  xsh_len = tvb_get_uint8(tvb, XSRVL_LEN) << 2;
183
184
  /* Create XIP Serval header tree. */
185
13
  ti = proto_tree_add_item(tree, proto_xip_serval, tvb,
186
13
    0, xsh_len, ENC_NA);
187
13
  xip_serval_tree = proto_item_add_subtree(ti, ett_xip_serval_tree);
188
189
  /* Add XIP Serval header length. */
190
13
  hl_ti = proto_tree_add_item(xip_serval_tree, hf_xip_serval_hl, tvb,
191
13
    XSRVL_LEN, 1, ENC_BIG_ENDIAN);
192
13
  if (tvb_captured_length(tvb) < xsh_len)
193
2
    expert_add_info_format(pinfo, hl_ti, &ei_xip_serval_bad_len,
194
2
      "Header Length field (%d bytes) cannot be greater than actual number of bytes left in packet (%d bytes)",
195
2
      xsh_len, tvb_captured_length(tvb));
196
197
  /* Add XIP Serval protocol. If it's not data, TCP, or UDP, the
198
   * packet is malformed.
199
   */
200
13
  proto_tree_add_item(xip_serval_tree, hf_xip_serval_proto, tvb,
201
13
    XSRVL_PRO, 1, ENC_BIG_ENDIAN);
202
13
  protocol = tvb_get_uint8(tvb, XSRVL_PRO);
203
13
  if (!try_val_to_str(protocol, xip_serval_proto_vals))
204
7
    expert_add_info_format(pinfo, ti, &ei_xip_serval_bad_proto,
205
7
      "Unrecognized protocol type: %d", protocol);
206
207
  /* Compute checksum. */
208
13
  SET_CKSUM_VEC_TVB(cksum_vec, tvb, 0, xsh_len);
209
210
13
  proto_tree_add_checksum(xip_serval_tree, tvb, XSRVL_CHK, hf_xip_serval_check, hf_xip_serval_check_status, &ei_xip_serval_bad_checksum, pinfo, in_cksum(&cksum_vec, 1),
211
13
              ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY|PROTO_CHECKSUM_IN_CKSUM);
212
13
  offset = XSRVL_EXT;
213
214
  /* If there's still more room, check for extension headers. */
215
13
  bytes_remaining = xsh_len - offset;
216
39
  while (bytes_remaining >= XIP_SERVAL_EXT_MIN_LEN) {
217
32
    int8_t bytes_displayed = display_xip_serval_ext(tvb, pinfo, ti,
218
32
      xip_serval_tree, offset);
219
220
    /* Extension headers are malformed, so we can't say
221
     * what the rest of the packet holds. Stop dissecting.
222
     */
223
32
    if (bytes_displayed <= 0)
224
6
      return;
225
226
26
    offset += bytes_displayed;
227
26
    bytes_remaining -= bytes_displayed;
228
26
  }
229
230
7
  switch (protocol) {
231
1
  case XIP_SERVAL_PROTO_DATA:
232
1
    next_tvb = tvb_new_subset_remaining(tvb, offset);
233
1
    call_data_dissector(next_tvb, pinfo, tree);
234
1
    break;
235
0
  case IP_PROTO_TCP: {
236
    /* Get the Data Offset field of the TCP header, which is
237
     * the high nibble of the 12th octet and represents the
238
     * size of the TCP header of 32-bit words.
239
     */
240
0
    uint8_t tcp_len = hi_nibble(tvb_get_uint8(tvb, offset + 12))*4;
241
0
    next_tvb = tvb_new_subset_length(tvb, offset, tcp_len);
242
0
    call_dissector(tcp_handle, next_tvb, pinfo, tree);
243
0
    break;
244
0
  }
245
0
  case IP_PROTO_UDP:
246
    /* The UDP header is always 8 bytes. */
247
0
    next_tvb = tvb_new_subset_length(tvb, offset, 8);
248
0
    call_dissector(udp_handle, next_tvb, pinfo, tree);
249
0
    break;
250
1
  default:
251
1
    break;
252
7
  }
253
7
}
254
255
static int
256
dissect_xip_serval(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
257
  void *data _U_)
258
13
{
259
13
  if (tvb_reported_length(tvb) < XIP_SERVAL_MIN_LEN)
260
0
    return 0;
261
262
13
  col_append_str(pinfo->cinfo, COL_INFO, " (with Serval)");
263
264
13
  display_xip_serval(tvb, pinfo, tree);
265
13
  return tvb_captured_length(tvb);
266
13
}
267
268
void
269
proto_register_xip_serval(void)
270
14
{
271
14
  static hf_register_info hf[] = {
272
273
    /* Serval Header. */
274
275
14
    { &hf_xip_serval_hl,
276
14
    { "Header Length", "xip_serval.hl", FT_UINT8,
277
14
       BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, NULL, HFILL }},
278
279
14
    { &hf_xip_serval_proto,
280
14
    { "Protocol", "xip_serval.proto", FT_UINT8,
281
14
       BASE_DEC, VALS(xip_serval_proto_vals), 0x0, NULL, HFILL }},
282
283
14
    { &hf_xip_serval_check,
284
14
    { "Checksum", "xip_serval.check", FT_UINT16,
285
14
       BASE_HEX, NULL, 0x0, NULL, HFILL }},
286
287
14
    { &hf_xip_serval_check_status,
288
14
    { "Checksum Status", "xip_serval.check.status", FT_UINT8,
289
14
       BASE_NONE, VALS(proto_checksum_vals), 0x0, NULL, HFILL }},
290
291
    /* Serval Extension Header. */
292
293
14
    { &hf_xip_serval_ext_type,
294
14
    { "Extension Type", "xip_serval.ext_type", FT_UINT8,
295
14
       BASE_DEC, NULL, 0x0, NULL, HFILL }},
296
297
14
    { &hf_xip_serval_ext_length,
298
14
    { "Extension Length", "xip_serval.ext_length", FT_UINT8,
299
14
       BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0, NULL, HFILL }},
300
301
    /* Serval Control Extension Header. */
302
303
14
    { &hf_xip_serval_cext,
304
14
    { "Serval Control Extension", "xip_serval.cext",
305
14
       FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
306
307
14
    { &hf_xip_serval_cext_flags,
308
14
    { "Flags", "xip_serval.cext_flags", FT_UINT8, BASE_HEX,
309
14
      NULL, 0x0, NULL, HFILL }},
310
311
14
    { &hf_xip_serval_cext_syn,
312
14
    { "SYN", "xip_serval.cext_syn", FT_BOOLEAN, 8,
313
14
      TFS(&tfs_set_notset), 0x80, NULL, HFILL }},
314
315
14
    { &hf_xip_serval_cext_rsyn,
316
14
    { "RSYN", "xip_serval.cext_rsyn", FT_BOOLEAN, 8,
317
14
      TFS(&tfs_set_notset), 0x40, NULL, HFILL }},
318
319
14
    { &hf_xip_serval_cext_ack,
320
14
    { "ACK", "xip_serval.cext_ack", FT_BOOLEAN, 8,
321
14
      TFS(&tfs_set_notset), 0x20, NULL, HFILL }},
322
323
14
    { &hf_xip_serval_cext_nack,
324
14
    { "NACK", "xip_serval.cext_nack", FT_BOOLEAN, 8,
325
14
      TFS(&tfs_set_notset), 0x10, NULL, HFILL }},
326
327
14
    { &hf_xip_serval_cext_rst,
328
14
    { "RST", "xip_serval.cext_rst", FT_BOOLEAN, 8,
329
14
      TFS(&tfs_set_notset), 0x08, NULL, HFILL }},
330
331
14
    { &hf_xip_serval_cext_fin,
332
14
    { "FIN", "xip_serval.cext_fin", FT_BOOLEAN, 8,
333
14
      TFS(&tfs_set_notset), 0x04, NULL, HFILL }},
334
335
14
    { &hf_xip_serval_cext_verno,
336
14
    { "Version Number", "xip_serval.cext_verno", FT_UINT32,
337
14
      BASE_DEC, NULL, 0x0, NULL, HFILL }},
338
339
14
    { &hf_xip_serval_cext_ackno,
340
14
    { "Acknowledgement Number", "xip_serval.cext_ackno",
341
14
      FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
342
343
14
    { &hf_xip_serval_cext_nonce,
344
14
    { "Nonce", "xip_serval.cext_nonce", FT_BYTES,
345
14
      SEP_SPACE, NULL, 0x0, NULL, HFILL }}
346
14
  };
347
348
14
  static int *ett[] = {
349
14
    &ett_xip_serval_tree,
350
14
    &ett_xip_serval_cext,
351
14
    &ett_xip_serval_cext_flags
352
14
  };
353
354
14
  static ei_register_info ei[] = {
355
356
14
    { &ei_xip_serval_bad_len,
357
14
    { "xip_serval.bad_len", PI_MALFORMED, PI_ERROR,
358
14
      "Bad header length", EXPFILL }},
359
360
14
    { &ei_xip_serval_bad_ext,
361
14
    { "xip_serval.bad_ext", PI_MALFORMED, PI_ERROR,
362
14
      "Bad extension header type", EXPFILL }},
363
364
14
    { &ei_xip_serval_bad_proto,
365
14
    { "xip_serval.bad_proto", PI_MALFORMED, PI_ERROR,
366
14
      "Bad protocol type", EXPFILL }},
367
368
14
    { &ei_xip_serval_bad_checksum,
369
14
    { "xip_serval.bad_checksum", PI_MALFORMED, PI_ERROR,
370
14
      "Incorrect checksum", EXPFILL }}
371
14
  };
372
373
14
  expert_module_t* expert_xip_serval;
374
375
14
  proto_xip_serval = proto_register_protocol("XIP Serval", "XIP Serval", "xipserval");
376
14
  register_dissector("xipserval", dissect_xip_serval,
377
14
    proto_xip_serval);
378
14
  proto_register_field_array(proto_xip_serval, hf, array_length(hf));
379
14
  proto_register_subtree_array(ett, array_length(ett));
380
381
14
  expert_xip_serval = expert_register_protocol(proto_xip_serval);
382
14
  expert_register_field_array(expert_xip_serval, ei, array_length(ei));
383
14
}
384
385
void
386
proto_reg_handoff_xip_serval(void)
387
14
{
388
14
  tcp_handle = find_dissector_add_dependency("tcp", proto_xip_serval);
389
14
  udp_handle = find_dissector_add_dependency("udp", proto_xip_serval);
390
14
}
391
392
/*
393
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
394
 *
395
 * Local variables:
396
 * c-basic-offset: 8
397
 * tab-width: 8
398
 * indent-tabs-mode: t
399
 * End:
400
 *
401
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
402
 * :indentSize=8:tabSize=8:noTabs=false:
403
 */