Coverage Report

Created: 2026-06-30 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-stcsig.c
Line
Count
Source
1
/* packet-stcsig.c
2
 * Routines for dissecting Spirent Test Center Signatures
3
 * Copyright 2018 Joerg Mayer (see AUTHORS file)
4
 * Based on disassembly of Spirent's modified version of Wireshark 1.10.3
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
/* The logic is based on the disassembly of libwireshark.dll which was
14
 * part of wireshark-win64-1.10.3-spirent-2.exe, distributed by Spirent
15
 * to customers of their Spirent Test Center.
16
 * As the installer displays the normal GPLv2+ license the choice was
17
 * made to go with disassembly instead of finding out who to ask for
18
 * the source code.
19
 *
20
 * Please report errors or missing features when compared to the original.
21
 */
22
23
/* TODO:
24
 * - Find out the meaning of the unknown trailer (perhaps some fcs or
25
 *   some prbseq related stuff?)
26
 * - Find out meaning of prbseq
27
 * - Is there a (fixed) structure in the csp field?
28
 * - Find out what the TSLR really stands for - currently just a guess
29
 */
30
#include "config.h"
31
32
#include <epan/packet.h>
33
#include <tfs.h>
34
35
void proto_register_stcsig(void);
36
void proto_reg_handoff_stcsig(void);
37
38
static int proto_stcsig;
39
40
static int hf_stcsig_csp;
41
static int hf_stcsig_iv;
42
static int hf_stcsig_prbseq;
43
static int hf_stcsig_rawdata;
44
static int hf_stcsig_seqnum_complement;
45
static int hf_stcsig_seqnum_edm;
46
static int hf_stcsig_seqnum_sm;
47
static int hf_stcsig_streamid;
48
static int hf_stcsig_streamindex;
49
static int hf_stcsig_streamtype;
50
static int hf_stcsig_timestamp;
51
static int hf_stcsig_tslr;
52
static int hf_stcsig_unknown;
53
54
static int ett_stcsig;
55
static int ett_stcsig_streamid;
56
57
static const true_false_string tfs_end_start = { "EndOfFrame", "StartOfFrame" };
58
59
static const true_false_string tfs_hard_soft = { "Hard", "Soft" };
60
61
/*
62
 * For the last 20 bytes of the data section to be a Spirent Signature
63
 * the first byte (offset 0) plus the 11th byte (offset 10) of the decoded
64
 * signature must add up to 255
65
 */
66
static bool
67
is_signature(tvbuff_t *tvb, int sigoffset)
68
0
{
69
  /*
70
   * How to generate the table below:
71
   *
72
   * static uint8_t runit = 1;
73
   * for(int k=0; k<256; k++) {
74
   *  obfuscation_value = k;
75
   *  for(int i=1; i<=10; i++) {
76
   *    obfuscation_value = deobfuscate_this[obfuscation_value];
77
   *  }
78
   *  printf("0x%02x, ", obfuscation_value);
79
   *  if (k%8 == 7) printf("\n");
80
   * }
81
   */
82
83
0
  static const uint8_t deobfuscate_offset_10[256] = {
84
0
    0x00, 0x86, 0x0d, 0x8b, 0x9d, 0x1b, 0x90, 0x16,
85
0
    0xbc, 0x3a, 0xb1, 0x37, 0x21, 0xa7, 0x2c, 0xaa,
86
0
    0x78, 0xfe, 0x75, 0xf3, 0xe5, 0x63, 0xe8, 0x6e,
87
0
    0xc4, 0x42, 0xc9, 0x4f, 0x59, 0xdf, 0x54, 0xd2,
88
0
    0xf1, 0x77, 0xfc, 0x7a, 0x6c, 0xea, 0x61, 0xe7,
89
0
    0x4d, 0xcb, 0x40, 0xc6, 0xd0, 0x56, 0xdd, 0x5b,
90
0
    0x89, 0x0f, 0x84, 0x02, 0x14, 0x92, 0x19, 0x9f,
91
0
    0x35, 0xb3, 0x38, 0xbe, 0xa8, 0x2e, 0xa5, 0x23,
92
0
    0xe2, 0x64, 0xef, 0x69, 0x7f, 0xf9, 0x72, 0xf4,
93
0
    0x5e, 0xd8, 0x53, 0xd5, 0xc3, 0x45, 0xce, 0x48,
94
0
    0x9a, 0x1c, 0x97, 0x11, 0x07, 0x81, 0x0a, 0x8c,
95
0
    0x26, 0xa0, 0x2b, 0xad, 0xbb, 0x3d, 0xb6, 0x30,
96
0
    0x13, 0x95, 0x1e, 0x98, 0x8e, 0x08, 0x83, 0x05,
97
0
    0xaf, 0x29, 0xa2, 0x24, 0x32, 0xb4, 0x3f, 0xb9,
98
0
    0x6b, 0xed, 0x66, 0xe0, 0xf6, 0x70, 0xfb, 0x7d,
99
0
    0xd7, 0x51, 0xda, 0x5c, 0x4a, 0xcc, 0x47, 0xc1,
100
0
    0x43, 0xc5, 0x4e, 0xc8, 0xde, 0x58, 0xd3, 0x55,
101
0
    0xff, 0x79, 0xf2, 0x74, 0x62, 0xe4, 0x6f, 0xe9,
102
0
    0x3b, 0xbd, 0x36, 0xb0, 0xa6, 0x20, 0xab, 0x2d,
103
0
    0x87, 0x01, 0x8a, 0x0c, 0x1a, 0x9c, 0x17, 0x91,
104
0
    0xb2, 0x34, 0xbf, 0x39, 0x2f, 0xa9, 0x22, 0xa4,
105
0
    0x0e, 0x88, 0x03, 0x85, 0x93, 0x15, 0x9e, 0x18,
106
0
    0xca, 0x4c, 0xc7, 0x41, 0x57, 0xd1, 0x5a, 0xdc,
107
0
    0x76, 0xf0, 0x7b, 0xfd, 0xeb, 0x6d, 0xe6, 0x60,
108
0
    0xa1, 0x27, 0xac, 0x2a, 0x3c, 0xba, 0x31, 0xb7,
109
0
    0x1d, 0x9b, 0x10, 0x96, 0x80, 0x06, 0x8d, 0x0b,
110
0
    0xd9, 0x5f, 0xd4, 0x52, 0x44, 0xc2, 0x49, 0xcf,
111
0
    0x65, 0xe3, 0x68, 0xee, 0xf8, 0x7e, 0xf5, 0x73,
112
0
    0x50, 0xd6, 0x5d, 0xdb, 0xcd, 0x4b, 0xc0, 0x46,
113
0
    0xec, 0x6a, 0xe1, 0x67, 0x71, 0xf7, 0x7c, 0xfa,
114
0
    0x28, 0xae, 0x25, 0xa3, 0xb5, 0x33, 0xb8, 0x3e,
115
0
    0x94, 0x12, 0x99, 0x1f, 0x09, 0x8f, 0x04, 0x82
116
0
  };
117
0
  uint8_t byte0;
118
0
  uint8_t byte10;
119
120
  /* Byte 0 also is the initialization vector for the obfuscation of offsets 1 - 15 */
121
0
  byte0 = tvb_get_uint8(tvb, sigoffset);
122
0
  byte10 = tvb_get_uint8(tvb, sigoffset + 10);
123
124
0
  if (byte0 + (byte10 ^ deobfuscate_offset_10[byte0]) == 255) {
125
0
    return true;
126
0
  } else {
127
0
    return false;
128
0
  }
129
0
}
130
131
static void
132
decode_signature(uint8_t* decode_buffer)
133
0
{
134
0
  static const uint8_t deobfuscate_this[256] = {
135
0
    0x00, 0x71, 0xe3, 0x92, 0xb6, 0xc7, 0x55, 0x24,
136
0
    0x1c, 0x6d, 0xff, 0x8e, 0xaa, 0xdb, 0x49, 0x38,
137
0
    0x39, 0x48, 0xda, 0xab, 0x8f, 0xfe, 0x6c, 0x1d,
138
0
    0x25, 0x54, 0xc6, 0xb7, 0x93, 0xe2, 0x70, 0x01,
139
0
    0x72, 0x03, 0x91, 0xe0, 0xc4, 0xb5, 0x27, 0x56,
140
0
    0x6e, 0x1f, 0x8d, 0xfc, 0xd8, 0xa9, 0x3b, 0x4a,
141
0
    0x4b, 0x3a, 0xa8, 0xd9, 0xfd, 0x8c, 0x1e, 0x6f,
142
0
    0x57, 0x26, 0xb4, 0xc5, 0xe1, 0x90, 0x02, 0x73,
143
0
    0xe4, 0x95, 0x07, 0x76, 0x52, 0x23, 0xb1, 0xc0,
144
0
    0xf8, 0x89, 0x1b, 0x6a, 0x4e, 0x3f, 0xad, 0xdc,
145
0
    0xdd, 0xac, 0x3e, 0x4f, 0x6b, 0x1a, 0x88, 0xf9,
146
0
    0xc1, 0xb0, 0x22, 0x53, 0x77, 0x06, 0x94, 0xe5,
147
0
    0x96, 0xe7, 0x75, 0x04, 0x20, 0x51, 0xc3, 0xb2,
148
0
    0x8a, 0xfb, 0x69, 0x18, 0x3c, 0x4d, 0xdf, 0xae,
149
0
    0xaf, 0xde, 0x4c, 0x3d, 0x19, 0x68, 0xfa, 0x8b,
150
0
    0xb3, 0xc2, 0x50, 0x21, 0x05, 0x74, 0xe6, 0x97,
151
0
    0xb8, 0xc9, 0x5b, 0x2a, 0x0e, 0x7f, 0xed, 0x9c,
152
0
    0xa4, 0xd5, 0x47, 0x36, 0x12, 0x63, 0xf1, 0x80,
153
0
    0x81, 0xf0, 0x62, 0x13, 0x37, 0x46, 0xd4, 0xa5,
154
0
    0x9d, 0xec, 0x7e, 0x0f, 0x2b, 0x5a, 0xc8, 0xb9,
155
0
    0xca, 0xbb, 0x29, 0x58, 0x7c, 0x0d, 0x9f, 0xee,
156
0
    0xd6, 0xa7, 0x35, 0x44, 0x60, 0x11, 0x83, 0xf2,
157
0
    0xf3, 0x82, 0x10, 0x61, 0x45, 0x34, 0xa6, 0xd7,
158
0
    0xef, 0x9e, 0x0c, 0x7d, 0x59, 0x28, 0xba, 0xcb,
159
0
    0x5c, 0x2d, 0xbf, 0xce, 0xea, 0x9b, 0x09, 0x78,
160
0
    0x40, 0x31, 0xa3, 0xd2, 0xf6, 0x87, 0x15, 0x64,
161
0
    0x65, 0x14, 0x86, 0xf7, 0xd3, 0xa2, 0x30, 0x41,
162
0
    0x79, 0x08, 0x9a, 0xeb, 0xcf, 0xbe, 0x2c, 0x5d,
163
0
    0x2e, 0x5f, 0xcd, 0xbc, 0x98, 0xe9, 0x7b, 0x0a,
164
0
    0x32, 0x43, 0xd1, 0xa0, 0x84, 0xf5, 0x67, 0x16,
165
0
    0x17, 0x66, 0xf4, 0x85, 0xa1, 0xd0, 0x42, 0x33,
166
0
    0x0b, 0x7a, 0xe8, 0x99, 0xbd, 0xcc, 0x5e, 0x2f
167
0
  };
168
0
  uint8_t obfuscation_value;
169
170
0
  obfuscation_value = decode_buffer[0];
171
172
0
  for(int i=1; i<16; i++) {
173
0
    obfuscation_value = deobfuscate_this[obfuscation_value];
174
0
    decode_buffer[i] ^= obfuscation_value;
175
0
  }
176
  /* decode_buffer[16...19] is unobfuscated */
177
0
}
178
179
static int
180
dissect_stcsig(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
181
0
{
182
0
  int        bytes, length;
183
0
  int        sig_offset;
184
185
0
  tvbuff_t   *stcsig_tvb;
186
0
  proto_item *ti;
187
0
  proto_tree *stcsig_tree;
188
0
  proto_tree *stcsig_streamid_tree;
189
0
  uint8_t    *real_stcsig;
190
191
0
  uint64_t   timestamp_2_5_ns;
192
0
  uint64_t   timestamp_ns;
193
0
  nstime_t   timestamp;
194
195
0
  length = tvb_captured_length(tvb);
196
0
  if (length >= 21 && tvb_get_uint8(tvb, length - 21) == 0 && is_signature(tvb, length - 20)) {
197
0
    bytes = 20;
198
0
  } else if (length >= 25 && tvb_get_uint8(tvb, length - 25) == 0 && is_signature(tvb, length - 24)) {
199
    /* Sigsize + 4 bytes FCS */
200
0
    bytes = 24;
201
0
  } else if (length >= 29 && tvb_get_uint8(tvb, length - 29) == 0 && is_signature(tvb, length - 28)) {
202
    /* Sigsize + 8 bytes FCS, i.e. FibreChannel */
203
0
    bytes = 28;
204
0
  } else if (length >= 20 && is_signature(tvb, length - 20)) {
205
0
    bytes = 20;
206
0
  } else if (length >= 24 && is_signature(tvb, length - 24)) {
207
    /* Sigsize + 4 bytes FCS */
208
0
    bytes = 24;
209
0
  } else if (length >= 28 && is_signature(tvb, length - 28)) {
210
    /* Sigsize + 8 bytes FCS, i.e. FibreChannel */
211
0
    bytes = 28;
212
0
  } else {
213
0
    return 0;
214
0
  }
215
0
  sig_offset = length - bytes;
216
217
#if 0
218
  /* Maybe make this a preference */
219
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "STCSIG");
220
  col_set_str(pinfo->cinfo, COL_INFO, "Spirent Test Center Signature");
221
#endif
222
223
0
  real_stcsig = (uint8_t *)tvb_memdup(pinfo->pool, tvb, sig_offset, 20);
224
0
  decode_signature(real_stcsig);
225
0
  stcsig_tvb = tvb_new_child_real_data(tvb, real_stcsig, 20, 20);
226
0
  add_new_data_source(pinfo, stcsig_tvb, "Spirent Test Center Signature");
227
228
0
  ti = proto_tree_add_item(tree, proto_stcsig, tvb, sig_offset, 20, ENC_NA);
229
0
  stcsig_tree = proto_item_add_subtree(ti, ett_stcsig);
230
231
0
  proto_tree_add_item(stcsig_tree, hf_stcsig_rawdata, tvb, sig_offset, 20, ENC_NA);
232
0
  proto_tree_add_item(stcsig_tree, hf_stcsig_iv, stcsig_tvb, 0, 1, ENC_NA);
233
0
  ti = proto_tree_add_item(stcsig_tree, hf_stcsig_streamid, stcsig_tvb, 1, 4, ENC_BIG_ENDIAN);
234
0
  stcsig_streamid_tree = proto_item_add_subtree(ti, ett_stcsig_streamid);
235
  /* This subtree is mostly an optical hierarchy, auto expand it */
236
0
  tree_expanded_set(ett_stcsig_streamid, true);
237
0
  proto_tree_add_item(stcsig_streamid_tree, hf_stcsig_csp, stcsig_tvb, 1, 2, ENC_BIG_ENDIAN);
238
0
  proto_tree_add_item(stcsig_streamid_tree, hf_stcsig_streamtype, stcsig_tvb, 3, 1, ENC_NA);
239
0
  proto_tree_add_item(stcsig_streamid_tree, hf_stcsig_streamindex, stcsig_tvb, 3, 2, ENC_BIG_ENDIAN);
240
0
  if (tvb_get_ntohs(stcsig_tvb, 5) + tvb_get_ntohs(stcsig_tvb, 7) == 0xffff) {
241
0
    proto_tree_add_item(stcsig_tree, hf_stcsig_seqnum_complement, stcsig_tvb, 5, 2, ENC_BIG_ENDIAN);
242
0
    proto_tree_add_item(stcsig_tree, hf_stcsig_seqnum_edm, stcsig_tvb, 7, 4, ENC_BIG_ENDIAN);
243
0
  } else {
244
0
    proto_tree_add_item(stcsig_tree, hf_stcsig_seqnum_sm, stcsig_tvb, 5, 6, ENC_BIG_ENDIAN);
245
0
  }
246
0
  timestamp_2_5_ns = (uint64_t)(tvb_get_uint8(stcsig_tvb, 15) & 0xfc) << 30;
247
0
  timestamp_2_5_ns |= tvb_get_ntohl(stcsig_tvb, 11);
248
  /* Convert 2.5 ns ticks to nanoseconds */
249
0
  timestamp_ns = timestamp_2_5_ns * 25 / 10;
250
0
  timestamp.secs = (time_t)(timestamp_ns / 1000000000L);
251
0
  timestamp.nsecs = (int)(timestamp_ns % 1000000000L);
252
0
  proto_tree_add_time(stcsig_tree, hf_stcsig_timestamp, stcsig_tvb, 11, 5, &timestamp);
253
0
  proto_tree_add_item(stcsig_tree, hf_stcsig_prbseq, stcsig_tvb, 15, 1, ENC_NA);
254
0
  proto_tree_add_item(stcsig_tree, hf_stcsig_tslr, stcsig_tvb, 15, 1, ENC_NA);
255
0
  proto_tree_add_item(stcsig_tree, hf_stcsig_unknown, stcsig_tvb, 16, 4, ENC_NA);
256
257
  /* Ignored for post-dissectors but required by function type */
258
0
  return length;
259
0
}
260
261
void
262
proto_register_stcsig(void)
263
14
{
264
14
  static hf_register_info hf[] = {
265
14
    { &hf_stcsig_rawdata,
266
14
      { "Raw Data", "stcsig.rawdata",
267
14
        FT_BYTES, BASE_NONE, NULL, 0x0,
268
14
        NULL, HFILL }
269
14
    },
270
14
    { &hf_stcsig_iv,
271
14
      { "IV", "stcsig.iv",
272
14
        FT_UINT8, BASE_HEX, NULL, 0x0,
273
14
        "Deobfuscation Initialization Vector and Complement of Sequence Low Byte", HFILL }
274
14
    },
275
14
    { &hf_stcsig_streamid,
276
14
      { "StreamID", "stcsig.streamid",
277
14
        FT_INT32, BASE_DEC, NULL, 0x0,
278
14
        NULL, HFILL }
279
14
    },
280
14
    { &hf_stcsig_csp,
281
14
      { "ChassisSlotPort", "stcsig.csp",
282
14
        FT_UINT16, BASE_DEC, NULL, 0x0,
283
14
        NULL, HFILL }
284
14
    },
285
14
    { &hf_stcsig_seqnum_complement,
286
14
      { "Complement (EDM)", "stcsig.complement",
287
14
        FT_UINT16, BASE_DEC, NULL, 0x0,
288
14
        "Complement of high bytes of Sequence Number", HFILL }
289
14
    },
290
14
    { &hf_stcsig_seqnum_edm,
291
14
      { "Sequence Number (EDM)", "stcsig.seqnum",
292
14
        FT_UINT32, BASE_DEC, NULL, 0x0,
293
14
        "Sequence Number (Enhanced Detection Mode)", HFILL }
294
14
    },
295
14
    { &hf_stcsig_seqnum_sm,
296
14
      { "Sequence Number (SM)", "stcsig.seqnum.sm",
297
14
        FT_UINT48, BASE_DEC, NULL, 0x0,
298
14
        "Sequence Number (Sequence Mode)", HFILL }
299
14
    },
300
14
    { &hf_stcsig_streamindex,
301
14
      { "Stream Index", "stcsig.streamindex",
302
14
        FT_UINT16, BASE_DEC, NULL, 0x0,
303
14
        NULL, HFILL }
304
14
    },
305
14
    { &hf_stcsig_timestamp,
306
14
      { "Timestamp", "stcsig.timestamp",
307
14
        FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
308
14
        NULL, HFILL }
309
14
    },
310
14
    { &hf_stcsig_prbseq,
311
14
      { "Pseudo-Random Binary Sequence", "stcsig.prbseq",
312
14
        FT_BOOLEAN, 8, NULL, 0x02,
313
14
        NULL, HFILL }
314
14
    },
315
14
    { &hf_stcsig_tslr,
316
14
      { "TSLR", "stcsig.tslr",
317
14
        FT_BOOLEAN, 8, TFS(&tfs_end_start), 0x01,
318
14
        "Time Stamp Location Reference", HFILL }
319
14
    },
320
14
    { &hf_stcsig_streamtype,
321
14
      { "StreamType", "stcsig.streamtype",
322
14
        FT_BOOLEAN, 8, TFS(&tfs_hard_soft), 0x80,
323
14
        NULL, HFILL }
324
14
    },
325
14
    { &hf_stcsig_unknown,
326
14
      { "Unknown", "stcsig.unknown",
327
14
        FT_BYTES, BASE_NONE, NULL, 0x0,
328
14
        "Unknown Trailer (not obfuscated)", HFILL }
329
14
    },
330
14
  };
331
332
14
  static int *ett[] = {
333
14
    &ett_stcsig,
334
14
    &ett_stcsig_streamid
335
14
  };
336
337
14
  dissector_handle_t stcsig_handle;
338
339
14
  proto_stcsig = proto_register_protocol("Spirent Test Center Signature", "STCSIG", "stcsig");
340
341
14
  proto_register_field_array(proto_stcsig, hf, array_length(hf));
342
14
  proto_register_subtree_array(ett, array_length(ett));
343
344
14
  stcsig_handle = register_dissector("stcsig", dissect_stcsig, proto_stcsig);
345
14
  register_postdissector(stcsig_handle);
346
347
  /* STCSIG is a rarely used case, disable it by default for performance reasons. */
348
14
  proto_disable_by_default(proto_stcsig);
349
14
}
350
351
/*
352
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
353
 *
354
 * Local variables:
355
 * c-basic-offset: 8
356
 * tab-width: 8
357
 * indent-tabs-mode: t
358
 * End:
359
 *
360
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
361
 * :indentSize=8:tabSize=8:noTabs=false:
362
 */