Coverage Report

Created: 2025-12-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-roofnet.c
Line
Count
Source
1
/* packet-roofnet.c
2
 * Routines for roofnet dissection
3
 * Copyright 2006, Sebastien Tandel (sebastien@tandel.be)
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
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/addr_resolv.h>
16
#include <epan/expert.h>
17
#include <epan/ptvcursor.h>
18
19
20
/* roofnet packet type constants */
21
#define ROOFNET_PT_QUERY 0x01
22
#define ROOFNET_PT_REPLY 0x02
23
#define ROOFNET_PT_DATA 0x04
24
#define ROOFNET_PT_GATEWAY 0x08
25
static const value_string roofnet_pt_vals[] = {
26
  { ROOFNET_PT_QUERY, "Query" },
27
  { ROOFNET_PT_REPLY, "Reply" },
28
  { ROOFNET_PT_DATA, "Data" },
29
  { ROOFNET_PT_GATEWAY, "Gateway" },
30
  { 0, NULL }
31
};
32
33
/* roofnet flag bit masks */
34
14
#define ROOFNET_FLAG_ERROR (1<<0)
35
14
#define ROOFNET_FLAG_UPDATE (1<<1)
36
23
#define ROOFNET_FLAG_LAYER2 (1<<9)
37
14
#define ROOFNET_FLAG_RESERVED 0xFDFC
38
#define ROOFNET_FLAG_MASK (ROOFNET_FLAG_ERROR | ROOFNET_FLAG_UPDATE | ROOFNET_FLAG_LAYER2)
39
40
/* header length */
41
27
#define ROOFNET_HEADER_LENGTH 160
42
/* roofnet max length */
43
/* may change with time */
44
27
#define ROOFNET_MAX_LENGTH 400
45
/* Roofnet Link Description Length
46
 * which is 6 fields of 4 bytes */
47
55
#define ROOFNET_LINK_DESCRIPTION_LENGTH 6*4
48
49
/* offset constants */
50
27
#define ROOFNET_OFFSET_TYPE 1
51
27
#define ROOFNET_OFFSET_NLINKS 2
52
11
#define ROOFNET_OFFSET_DATA_LENGTH 10
53
54
/* offset relative to a link section of roofnet */
55
44
#define ROOFNET_LINK_OFFSET_SRC 0
56
44
#define ROOFNET_LINK_OFFSET_DST 20
57
/* roofnet link fields length */
58
44
#define ROOFNET_LINK_LEN 24
59
60
/* forward reference */
61
void proto_register_roofnet(void);
62
void proto_reg_handoff_roofnet(void);
63
64
static dissector_handle_t roofnet_handle;
65
static dissector_handle_t ip_handle;
66
static dissector_handle_t eth_withoutfcs_handle;
67
static int proto_roofnet;
68
69
/* hf fields for the header of roofnet */
70
static int hf_roofnet_version;
71
static int hf_roofnet_type;
72
static int hf_roofnet_nlinks;
73
static int hf_roofnet_next;
74
static int hf_roofnet_ttl;
75
static int hf_roofnet_cksum;
76
static int hf_roofnet_flags;
77
static int hf_roofnet_flags_error;
78
static int hf_roofnet_flags_update;
79
static int hf_roofnet_flags_layer2;
80
static int hf_roofnet_flags_reserved;
81
static int hf_roofnet_data_length;
82
static int hf_roofnet_query_dst;
83
static int hf_roofnet_seq;
84
/* static int hf_roofnet_links; */
85
static int hf_roofnet_link_src;
86
static int hf_roofnet_link_forward;
87
static int hf_roofnet_link_rev;
88
static int hf_roofnet_link_seq;
89
static int hf_roofnet_link_age;
90
static int hf_roofnet_link_dst;
91
92
static int * const flag_list[] = {
93
    &hf_roofnet_flags_error,
94
    &hf_roofnet_flags_update,
95
    &hf_roofnet_flags_layer2,
96
    &hf_roofnet_flags_reserved,
97
    NULL
98
};
99
100
101
static int ett_roofnet;
102
static int ett_roofnet_flags;
103
static int ett_roofnet_link;
104
105
static expert_field ei_roofnet_too_many_links;
106
static expert_field ei_roofnet_too_much_data;
107
108
/*
109
 * dissect the header of roofnet
110
 */
111
static uint16_t dissect_roofnet_header(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, unsigned *offset)
112
27
{
113
27
  uint16_t flags;
114
27
  ptvcursor_t *cursor = ptvcursor_new(pinfo->pool, tree, tvb, *offset);
115
116
27
  ptvcursor_add(cursor, hf_roofnet_version, 1, ENC_BIG_ENDIAN);
117
27
  ptvcursor_add(cursor, hf_roofnet_type, 1, ENC_BIG_ENDIAN);
118
27
  ptvcursor_add(cursor, hf_roofnet_nlinks, 1, ENC_BIG_ENDIAN);
119
27
  ptvcursor_add(cursor, hf_roofnet_next, 1, ENC_BIG_ENDIAN);
120
27
  ptvcursor_add(cursor, hf_roofnet_ttl, 2, ENC_BIG_ENDIAN);
121
27
  proto_tree_add_checksum(ptvcursor_tree(cursor), ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor),
122
27
                          hf_roofnet_cksum, -1, NULL, NULL, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
123
27
  ptvcursor_advance(cursor, 2);
124
27
  flags = tvb_get_ntohs(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));
125
27
  proto_tree_add_bitmask(ptvcursor_tree(cursor), ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor),
126
27
                          hf_roofnet_flags, ett_roofnet_flags, flag_list, ENC_BIG_ENDIAN);
127
27
  ptvcursor_advance(cursor, 2);
128
27
  ptvcursor_add(cursor, hf_roofnet_data_length, 2, ENC_BIG_ENDIAN);
129
27
  ptvcursor_add(cursor, hf_roofnet_query_dst, 4, ENC_BIG_ENDIAN);
130
27
  ptvcursor_add(cursor, hf_roofnet_seq, 4, ENC_BIG_ENDIAN);
131
132
27
  *offset = ptvcursor_current_offset(cursor);
133
27
  ptvcursor_free(cursor);
134
135
27
  return flags;
136
27
}
137
138
/*
139
 * dissect the description of link in roofnet
140
 */
141
static void dissect_roofnet_link(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, unsigned *offset, unsigned link)
142
44
{
143
44
  proto_tree *subtree = NULL;
144
145
44
  ptvcursor_t *cursor = NULL;
146
147
44
  uint32_t addr_src = 0;
148
44
  uint32_t addr_dst = 0;
149
150
44
  addr_src = tvb_get_ipv4(tvb, *offset + ROOFNET_LINK_OFFSET_SRC);
151
44
  addr_dst = tvb_get_ipv4(tvb, *offset + ROOFNET_LINK_OFFSET_DST);
152
153
44
  subtree = proto_tree_add_subtree_format(tree, tvb, *offset, ROOFNET_LINK_LEN,
154
44
                                          ett_roofnet_link, NULL, "link: %u, src: %s, dst: %s",
155
44
                                          link,
156
44
                                          get_hostname(addr_src),
157
44
                                          get_hostname(addr_dst));
158
159
44
  proto_tree_add_ipv4(subtree, hf_roofnet_link_src, tvb, *offset, 4, addr_src);
160
44
  *offset += 4;
161
162
44
  cursor = ptvcursor_new(pinfo->pool, subtree, tvb, *offset);
163
164
44
  ptvcursor_add(cursor, hf_roofnet_link_forward, 4, ENC_BIG_ENDIAN);
165
44
  ptvcursor_add(cursor, hf_roofnet_link_rev, 4, ENC_BIG_ENDIAN);
166
44
  ptvcursor_add(cursor, hf_roofnet_link_seq, 4, ENC_BIG_ENDIAN);
167
44
  ptvcursor_add(cursor, hf_roofnet_link_age, 4, ENC_BIG_ENDIAN);
168
169
44
  *offset = ptvcursor_current_offset(cursor);
170
44
  ptvcursor_free(cursor);
171
172
44
  proto_tree_add_ipv4(subtree, hf_roofnet_link_dst, tvb, *offset, 4, addr_dst);
173
  /* don't increment offset here because the dst of this link is the src of the next one */
174
44
}
175
176
/*
177
 * dissect the data in roofnet
178
 */
179
static void dissect_roofnet_data(proto_tree *tree, tvbuff_t *tvb, packet_info * pinfo, int offset, uint16_t flags)
180
11
{
181
11
  uint16_t roofnet_datalen = 0;
182
11
  uint16_t remaining_datalen = 0;
183
184
11
  roofnet_datalen = tvb_get_ntohs(tvb, ROOFNET_OFFSET_DATA_LENGTH);
185
11
  remaining_datalen = tvb_reported_length_remaining(tvb, offset);
186
187
188
  /* dissect on remaining_datalen */
189
11
   if (roofnet_datalen < remaining_datalen)
190
4
     proto_tree_add_expert_format(tree, pinfo, &ei_roofnet_too_much_data, tvb, offset, roofnet_datalen,
191
4
                                  "[More payload data (%u) than told by Roofnet (%u)]",
192
4
                                  remaining_datalen, roofnet_datalen);
193
194
11
  if (roofnet_datalen == 0)
195
2
    return;
196
197
  /* dissect payload */
198
9
  if (flags & ROOFNET_FLAG_LAYER2) {
199
    /* ethernet frame is padded with 2 bytes at the start */
200
5
    call_dissector(eth_withoutfcs_handle, tvb_new_subset_remaining(tvb, offset+2), pinfo, tree);
201
5
  } else {
202
4
    call_dissector(ip_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree);
203
4
  }
204
205
9
}
206
207
/*
208
 * entry point of the roofnet dissector
209
 */
210
static int dissect_roofnet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
211
27
{
212
27
  proto_item * it;
213
27
  proto_tree * roofnet_tree;
214
27
  unsigned offset = 0;
215
216
27
  uint8_t roofnet_msg_type = 0;
217
27
  uint8_t roofnet_nlinks = 0;
218
27
  uint8_t nlink = 1;
219
27
  uint16_t flags;
220
221
27
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "Roofnet");
222
223
27
  roofnet_msg_type = tvb_get_uint8(tvb, ROOFNET_OFFSET_TYPE);
224
  /* Clear out stuff in the info column */
225
27
  col_add_fstr(pinfo->cinfo, COL_INFO, "Message Type: %s",
226
27
               val_to_str(pinfo->pool, roofnet_msg_type, roofnet_pt_vals, "Unknown (%d)"));
227
228
27
  it = proto_tree_add_item(tree, proto_roofnet, tvb, offset, -1, ENC_NA);
229
27
  roofnet_tree = proto_item_add_subtree(it, ett_roofnet);
230
231
27
  flags = dissect_roofnet_header(roofnet_tree, pinfo, tvb, &offset);
232
233
27
  roofnet_nlinks = tvb_get_uint8(tvb, ROOFNET_OFFSET_NLINKS);
234
  /* Check that we do not have a malformed roofnet packet */
235
27
  if ((roofnet_nlinks*6*4)+ROOFNET_HEADER_LENGTH > ROOFNET_MAX_LENGTH) {
236
2
    expert_add_info_format(pinfo, it, &ei_roofnet_too_many_links, "Too many links (%u)", roofnet_nlinks);
237
2
    return tvb_captured_length(tvb);
238
2
  }
239
240
69
  for (; roofnet_nlinks > 0; roofnet_nlinks--) {
241
    /* Do we have enough buffer to decode the next link ? */
242
55
    if (tvb_reported_length_remaining(tvb, offset) < ROOFNET_LINK_DESCRIPTION_LENGTH)
243
11
      return offset;
244
44
    dissect_roofnet_link(roofnet_tree, pinfo, tvb, &offset, nlink++);
245
44
  }
246
247
14
  dissect_roofnet_data(tree, tvb, pinfo, offset+4, flags);
248
14
  return tvb_captured_length(tvb);
249
25
}
250
251
void proto_register_roofnet(void)
252
14
{
253
14
  static hf_register_info hf[] = {
254
    /* Roofnet Header */
255
14
    { &hf_roofnet_version,
256
14
      { "Version", "roofnet.version",
257
14
      FT_UINT8, BASE_DEC, NULL, 0x0, "Roofnet Version", HFILL }
258
14
    },
259
260
14
    { &hf_roofnet_type,
261
14
      { "Type", "roofnet.type",
262
14
        FT_UINT8, BASE_DEC, VALS(roofnet_pt_vals), 0x0, "Roofnet Message Type", HFILL }
263
14
    },
264
265
14
    { &hf_roofnet_nlinks,
266
14
      { "Number of Links", "roofnet.nlinks",
267
14
        FT_UINT8, BASE_DEC, NULL, 0x0, "Roofnet Number of Links", HFILL }
268
14
    },
269
270
14
    { &hf_roofnet_next,
271
14
      { "Next Link", "roofnet.next",
272
14
        FT_UINT8, BASE_DEC, NULL, 0x0, "Roofnet Next Link to Use", HFILL }
273
14
    },
274
275
14
    { &hf_roofnet_ttl,
276
14
      { "Time To Live", "roofnet.ttl",
277
14
        FT_UINT16, BASE_DEC, NULL, 0x0, "Roofnet Time to Live", HFILL }
278
14
    },
279
280
14
    { &hf_roofnet_cksum,
281
14
      { "Checksum", "roofnet.cksum",
282
14
        FT_UINT16, BASE_DEC, NULL, 0x0, "Roofnet Header Checksum", HFILL }
283
14
    },
284
285
14
    { &hf_roofnet_flags,
286
14
      { "Flags", "roofnet.flags",
287
14
        FT_UINT16, BASE_HEX, NULL, 0x0, "Roofnet flags", HFILL }
288
14
    },
289
290
14
    { &hf_roofnet_flags_error,
291
14
      { "Roofnet Error", "roofnet.flags.error",
292
14
        FT_BOOLEAN, 16, NULL, ROOFNET_FLAG_ERROR, NULL, HFILL }
293
14
    },
294
295
14
    { &hf_roofnet_flags_update,
296
14
      { "Roofnet Update", "roofnet.flags.update",
297
14
        FT_BOOLEAN, 16, NULL, ROOFNET_FLAG_UPDATE, NULL, HFILL }
298
14
    },
299
300
14
    { &hf_roofnet_flags_layer2,
301
14
      { "Roofnet Layer 2", "roofnet.flags.layer2",
302
14
        FT_BOOLEAN, 16, NULL, ROOFNET_FLAG_LAYER2, NULL, HFILL }
303
14
    },
304
305
14
    { &hf_roofnet_flags_reserved,
306
14
      { "Roofnet Reserved", "roofnet.flags.reserved",
307
14
        FT_BOOLEAN, 16, NULL, ROOFNET_FLAG_RESERVED, NULL, HFILL }
308
14
    },
309
310
14
    { &hf_roofnet_data_length,
311
14
      { "Data Length", "roofnet.datalength",
312
14
        FT_UINT16, BASE_DEC, NULL, 0x0, "Data Payload Length", HFILL }
313
14
    },
314
315
14
    { &hf_roofnet_query_dst,
316
14
      { "Query Dst", "roofnet.querydst",
317
14
        FT_IPv4, BASE_NONE, NULL, 0x0, "Roofnet Query Destination", HFILL }
318
14
    },
319
320
14
    { &hf_roofnet_seq,
321
14
      { "Seq", "roofnet.seq",
322
14
        FT_UINT32, BASE_DEC, NULL, 0x0, "Roofnet Sequential Number", HFILL }
323
14
    },
324
325
#if 0
326
    { &hf_roofnet_links,
327
      { "Links", "roofnet.links",
328
      FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }
329
    },
330
#endif
331
332
14
    { &hf_roofnet_link_src,
333
14
      { "Source IP", "roofnet.link.src",
334
14
      FT_IPv4, BASE_NONE, NULL, 0x0, "Roofnet Message Source", HFILL }
335
14
    },
336
337
14
    { &hf_roofnet_link_forward,
338
14
      { "Forward", "roofnet.link.forward",
339
14
        FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
340
14
    },
341
342
14
    { &hf_roofnet_link_rev,
343
14
      { "Rev", "roofnet.link.rev",
344
14
        FT_UINT32, BASE_DEC, NULL, 0x0, "Revision Number", HFILL }
345
14
    },
346
347
14
    { &hf_roofnet_link_seq,
348
14
      { "Seq", "roofnet.link.seq",
349
14
        FT_UINT32, BASE_DEC, NULL, 0x0, "Link Sequential Number", HFILL }
350
14
    },
351
352
14
    { &hf_roofnet_link_age,
353
14
      { "Age", "roofnet.link.age",
354
14
        FT_UINT32, BASE_DEC, NULL, 0x0, "Information Age", HFILL }
355
14
    },
356
357
14
    { &hf_roofnet_link_dst,
358
14
      { "Dst IP", "roofnet.link.dst",
359
14
        FT_IPv4, BASE_NONE, NULL, 0x0, "Roofnet Message Destination", HFILL }
360
14
    }
361
14
  };
362
363
  /* setup protocol subtree array */
364
14
  static int *ett[] = {
365
14
    &ett_roofnet,
366
14
    &ett_roofnet_flags,
367
14
    &ett_roofnet_link
368
14
  };
369
370
14
  static ei_register_info ei[] = {
371
14
     { &ei_roofnet_too_many_links, { "roofnet.too_many_links", PI_MALFORMED, PI_ERROR, "Too many links", EXPFILL }},
372
14
     { &ei_roofnet_too_much_data, { "roofnet.too_much_data", PI_MALFORMED, PI_ERROR, "More payload data than told by Roofnet", EXPFILL }},
373
14
  };
374
375
14
  expert_module_t* expert_roofnet;
376
377
14
  proto_roofnet = proto_register_protocol("Roofnet Protocol", "Roofnet", "roofnet");
378
379
14
  proto_register_field_array(proto_roofnet, hf, array_length(hf));
380
14
  proto_register_subtree_array(ett, array_length(ett));
381
14
  expert_roofnet = expert_register_protocol(proto_roofnet);
382
14
  expert_register_field_array(expert_roofnet, ei, array_length(ei));
383
384
14
  roofnet_handle = register_dissector("roofnet", dissect_roofnet, proto_roofnet);
385
14
}
386
387
388
void proto_reg_handoff_roofnet(void)
389
14
{
390
  /* Until now there is no other option than having an IPv4 payload (maybe
391
   * extended one day to IPv6 or other?) */
392
14
  ip_handle = find_dissector_add_dependency("ip", proto_roofnet);
393
14
  eth_withoutfcs_handle = find_dissector_add_dependency("eth_withoutfcs", proto_roofnet);
394
  /* I did not put the type numbers in the ethertypes.h as they only are
395
   * experimental and not official */
396
14
  dissector_add_uint("ethertype", 0x0641, roofnet_handle);
397
14
  dissector_add_uint("ethertype", 0x0643, roofnet_handle);
398
14
  dissector_add_uint("ethertype", 0x0644, roofnet_handle);
399
14
  dissector_add_uint("ethertype", 0x0645, roofnet_handle);
400
14
}
401
402
/*
403
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
404
 *
405
 * Local Variables:
406
 * c-basic-offset: 2
407
 * tab-width: 8
408
 * indent-tabs-mode: nil
409
 * End:
410
 *
411
 * ex: set shiftwidth=2 tabstop=8 expandtab:
412
 * :indentSize=2:tabSize=8:noTabs=true:
413
 */