Coverage Report

Created: 2026-05-14 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-pw-cesopsn.c
Line
Count
Source
1
/* packet-pw-cesopsn.c
2
 * Routines for CESoPSN PW dissection as per RFC5086.
3
 * Copyright 2009, Dmitry Trebich, Artem Tamazov <artem.tamazov@tellabs.com>
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
 * History:
12
 * ---------------------------------
13
 * 16.03.2009 initial implementation for MPLS
14
 * 14.08.2009 added: support for IP/UDP demultiplexing
15
 * Not supported yet:
16
 * - All PW modes, except Basic NxDS0 mode.
17
 * - <Optional> RTP Headers (RFC3550)
18
 * - Decoding of PW payload
19
 */
20
21
#include "config.h"
22
23
#include <epan/packet.h>
24
#include <epan/expert.h>
25
26
#include "packet-mpls.h"
27
#include "packet-pw-common.h"
28
29
void proto_register_pw_cesopsn(void);
30
void proto_reg_handoff_pw_cesopsn(void);
31
32
static int proto = -1;
33
static int ett_pw_cesopsn;
34
35
static int hf_cw;
36
static int hf_cw_bits03;
37
static int hf_cw_lm;
38
static int hf_cw_r;
39
static int hf_cw_frg;
40
static int hf_cw_len;
41
static int hf_cw_seq;
42
static int hf_payload;
43
static int hf_payload_l;
44
45
static expert_field ei_payload_size_invalid_undecoded;
46
static expert_field ei_cw_frg;
47
static expert_field ei_payload_size_invalid_error;
48
static expert_field ei_cw_bits03;
49
static expert_field ei_pref_cw_len;
50
static expert_field ei_cw_lm;
51
static expert_field ei_packet_size_too_small;
52
53
static dissector_handle_t pw_padding_handle;
54
static dissector_handle_t pw_cesopsn_udp_handle;
55
static dissector_handle_t pw_cesopsn_mpls_handle;
56
57
static const value_string vals_cw_lm[] = {
58
  /* note that bitmask in hs_register_info is 0xb == 1011B */
59
  /* this is why 0x8 comes just after 0x3 */
60
  { 0x0,  "Normal situation - no AC faults" },
61
  /*{ 0x1,  "Reserved combination" },*/
62
  { 0x2,  "AC Fault - RDI condition" },
63
  { 0x3,  "Reserved for CESoPSN signaling" },
64
  { 0x8,  "AC Fault - TDM data is invalid" },
65
  /*{ 0x9,  "Reserved combination" },*/
66
  /*{ 0xa,  "Reserved combination" },*/
67
  /*{ 0xb,  "Reserved combination" },*/
68
  { 0,  NULL }
69
};
70
71
72
static
73
void dissect_pw_cesopsn( tvbuff_t * tvb_original
74
            ,packet_info * pinfo
75
            ,proto_tree * tree
76
            ,pwc_demux_type_t demux)
77
0
{
78
0
  const int encaps_size = 4; /*RTP header in encapsulation is not supported yet*/
79
0
  int       packet_size;
80
0
  int       payload_size;
81
0
  int       padding_size;
82
0
  int properties;
83
84
0
  packet_size = tvb_reported_length_remaining(tvb_original, 0);
85
86
  /*
87
   * FIXME
88
   * "4" below should be replaced by something like "min_packet_size_this_dissector"
89
   * Also call to dissect_try_cw_first_nibble() should be moved before this block
90
   */
91
0
  if (packet_size < 4) /* 4 is smallest size which may be sensible (for PWACH dissector) */
92
0
  {
93
0
    proto_item  *item;
94
0
    item = proto_tree_add_item(tree, proto, tvb_original, 0, -1, ENC_NA);
95
0
    expert_add_info_format(pinfo, item, &ei_packet_size_too_small,
96
0
               "PW packet size (%d) is too small to carry sensible information"
97
0
               ,(int)packet_size);
98
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "CESoPSN basic (no RTP)");
99
0
    col_set_str(pinfo->cinfo, COL_INFO, "Malformed: PW packet is too small");
100
0
    return;
101
0
  }
102
103
0
  switch (demux)
104
0
  {
105
0
  case PWC_DEMUX_MPLS:
106
0
    if (dissect_try_cw_first_nibble(tvb_original, pinfo, tree))
107
0
    {
108
0
      return;
109
0
    }
110
0
    break;
111
0
  case PWC_DEMUX_UDP:
112
0
    break;
113
0
  default:
114
0
    DISSECTOR_ASSERT_NOT_REACHED();
115
0
    return;
116
0
  }
117
118
  /* check how "good" is this packet */
119
  /* also decide payload length from packet size and CW */
120
0
  properties = PWC_PACKET_PROPERTIES_T_INITIALIZER;
121
0
  if (0 != (tvb_get_uint8(tvb_original, 0) & 0xf0 /*bits03*/))
122
0
  {
123
0
    properties |= PWC_CW_BAD_BITS03;
124
0
  }
125
0
  if (0 != (tvb_get_uint8(tvb_original, 1) & 0xc0 /*frag*/))
126
0
  {
127
0
    properties |= PWC_CW_BAD_FRAG;
128
0
  }
129
0
  {
130
    /* RFC5086:
131
     * [LEN (bits (10 to 15) MAY be used to carry the length of the CESoPSN
132
     * packet (defined as the size of the CESoPSN header + the payload size)
133
     * if it is less than 64 bytes, and MUST be set to zero otherwise.
134
     * Note:  If fixed RTP header is used in the encapsulation, it is
135
     * considered part of the CESoPSN header.]
136
     *
137
     * Note that this differs from RFC4385's definition of length:
138
     * [ If the MPLS payload is less than 64 bytes, the length field
139
     * MUST be set to the length of the PW payload...]
140
     *
141
     * We will use RFC5086's definition here.
142
     */
143
0
    int  cw_len;
144
0
    int payload_size_from_packet;
145
146
0
    cw_len = tvb_get_uint8(tvb_original, 1) & 0x3f;
147
0
    payload_size_from_packet = packet_size - encaps_size;
148
0
    if (cw_len != 0)
149
0
    {
150
0
      int payload_size_from_cw;
151
0
      payload_size_from_cw = cw_len - encaps_size;
152
      /*
153
       * Assumptions for error case,
154
       * will be overwritten if no errors found:
155
       */
156
0
      payload_size = payload_size_from_packet;
157
0
      padding_size = 0;
158
159
0
      if (payload_size_from_cw < 0)
160
0
      {
161
0
        properties |= PWC_CW_BAD_PAYLEN_LT_0;
162
0
      }
163
0
      else if (payload_size_from_cw > payload_size_from_packet)
164
0
      {
165
0
        properties |= PWC_CW_BAD_PAYLEN_GT_PACKET;
166
0
      }
167
0
      else if (payload_size_from_packet >= 64)
168
0
      {
169
0
        properties |= PWC_CW_BAD_LEN_MUST_BE_0;
170
0
      }
171
0
      else /* ok */
172
0
      {
173
0
        payload_size = payload_size_from_cw;
174
0
        padding_size = payload_size_from_packet - payload_size_from_cw; /* >=0 */
175
0
      }
176
0
    }
177
0
    else
178
0
    {
179
0
      payload_size = payload_size_from_packet;
180
0
      padding_size = 0;
181
0
    }
182
0
  }
183
184
0
  {
185
0
    uint8_t cw_lm;
186
0
    cw_lm = tvb_get_uint8(tvb_original, 0) & 0x0b /*l+mod*/;
187
0
    if (NULL == try_val_to_str(cw_lm, vals_cw_lm))
188
0
    {
189
0
      properties |= PWC_CW_SUSPECT_LM;
190
0
    }
191
192
0
    {
193
0
      uint8_t l_bit, m_bits;
194
0
      l_bit  = (cw_lm & 0x08) >> 3;
195
0
      m_bits = (cw_lm & 0x03) >> 0;
196
0
      if ((l_bit == 0 && m_bits == 0x0) /*CESoPSN data packet - normal situation*/
197
0
          ||(l_bit == 0 && m_bits == 0x2) /*CESoPSN data packet - RDI on the AC*/ )
198
0
      {
199
0
        if ((payload_size == 0) || ((payload_size % 8) != 0))
200
0
        {
201
0
          properties |= PWC_PAY_SIZE_BAD;
202
0
        }
203
0
      }
204
0
      else if (l_bit == 1 && m_bits == 0x0) /*TDM data is invalid; payload MAY be omitted*/
205
0
      {
206
        /*allow any size of payload*/
207
0
      }
208
0
      else /*reserved combinations*/
209
0
      {
210
        /*allow any size of payload*/
211
0
      }
212
0
    }
213
0
  }
214
215
  /* fill up columns*/
216
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "CESoPSN basic (no RTP)");
217
0
  col_clear(pinfo->cinfo, COL_INFO);
218
0
  if (properties & PWC_ANYOF_CW_BAD)
219
0
  {
220
0
    col_set_str(pinfo->cinfo, COL_INFO, "CW:Bad, ");
221
0
  }
222
0
  else if (properties & PWC_ANYOF_CW_SUSPECT)
223
0
  {
224
0
    col_append_str(pinfo->cinfo, COL_INFO, "CW:Suspect, ");
225
0
  }
226
227
0
  if (properties & PWC_PAY_SIZE_BAD)
228
0
  {
229
0
    col_append_str(pinfo->cinfo, COL_INFO, "Payload size:Bad, ");
230
0
  }
231
232
0
  col_append_fstr(pinfo->cinfo, COL_INFO, "TDM octets:%d", (int)payload_size);
233
234
0
  if (padding_size != 0)
235
0
  {
236
0
    col_append_fstr(pinfo->cinfo, COL_INFO, ", Padding:%d", (int)padding_size);
237
0
  }
238
239
0
  {
240
0
    proto_item* item;
241
0
    item = proto_tree_add_item(tree, proto, tvb_original, 0, -1, ENC_NA);
242
0
    pwc_item_append_cw(item,tvb_get_ntohl(tvb_original, 0),true);
243
0
    pwc_item_append_text_n_items(item,(int)payload_size,"octet");
244
0
    {
245
0
      proto_tree* tree2;
246
0
      tree2 = proto_item_add_subtree(item, ett_pw_cesopsn);
247
0
      {
248
0
        tvbuff_t* tvb;
249
0
        proto_item* item2;
250
0
        tvb = tvb_new_subset_length(tvb_original, 0, PWC_SIZEOF_CW);
251
0
        item2 = proto_tree_add_item(tree2, hf_cw, tvb, 0, -1, ENC_NA);
252
0
        pwc_item_append_cw(item2,tvb_get_ntohl(tvb, 0),false);
253
0
        {
254
0
          proto_tree* tree3;
255
0
          tree3 = proto_item_add_subtree(item, ett_pw_cesopsn);
256
0
          {
257
0
            proto_item* item3;
258
0
            if (properties & PWC_CW_BAD_BITS03) /*display only if value is wrong*/
259
0
            {
260
0
              item3 = proto_tree_add_item(tree3, hf_cw_bits03, tvb, 0, 1, ENC_BIG_ENDIAN);
261
0
              expert_add_info(pinfo, item3, &ei_cw_bits03);
262
0
            }
263
264
0
            item3 = proto_tree_add_item(tree3, hf_cw_lm,  tvb, 0, 1, ENC_BIG_ENDIAN);
265
0
            if (properties & PWC_CW_SUSPECT_LM)
266
0
            {
267
0
              expert_add_info(pinfo, item3, &ei_cw_lm);
268
0
            }
269
270
0
            proto_tree_add_item(tree3, hf_cw_r, tvb, 0, 1, ENC_BIG_ENDIAN);
271
272
0
            item3 = proto_tree_add_item(tree3, hf_cw_frg, tvb, 1, 1, ENC_BIG_ENDIAN);
273
0
            if (properties & PWC_CW_BAD_FRAG)
274
0
            {
275
0
              expert_add_info(pinfo, item3, &ei_cw_frg);
276
0
            }
277
278
0
            item3 = proto_tree_add_item(tree3, hf_cw_len, tvb, 1, 1, ENC_BIG_ENDIAN);
279
0
            if (properties & PWC_CW_BAD_PAYLEN_LT_0)
280
0
            {
281
0
              expert_add_info_format(pinfo, item3, &ei_pref_cw_len,
282
0
                "Bad Length: too small, must be > %d",
283
0
                (int)encaps_size);
284
0
            }
285
0
            if (properties & PWC_CW_BAD_PAYLEN_GT_PACKET)
286
0
            {
287
0
              expert_add_info_format(pinfo, item3, &ei_pref_cw_len,
288
0
                "Bad Length: must be <= than PSN packet size (%d)",
289
0
                (int)packet_size);
290
0
            }
291
0
            if (properties & PWC_CW_BAD_LEN_MUST_BE_0)
292
0
            {
293
0
              expert_add_info_format(pinfo, item3, &ei_pref_cw_len,
294
0
                "Bad Length: must be 0 if CESoPSN packet size (%d) is > 64",
295
0
                (int)packet_size);
296
0
            }
297
298
0
            proto_tree_add_item(tree3, hf_cw_seq, tvb, 2, 2, ENC_BIG_ENDIAN);
299
300
0
          }
301
0
        }
302
0
      }
303
0
    }
304
305
    /* payload */
306
0
    if (payload_size == 0)
307
0
    {
308
0
      if (properties & PWC_PAY_SIZE_BAD)
309
0
      {
310
0
        expert_add_info_format(pinfo, item, &ei_payload_size_invalid_error,
311
0
          "CESoPSN payload: none found. Size of payload must be <> 0");
312
0
      }
313
0
      else
314
0
      {
315
0
        expert_add_info(pinfo, item, &ei_payload_size_invalid_undecoded);
316
0
      }
317
0
    }
318
0
    else
319
0
    {
320
0
      proto_tree* tree2;
321
0
      tree2 = proto_item_add_subtree(item, ett_pw_cesopsn);
322
0
      {
323
0
        proto_item* item2;
324
0
        tvbuff_t* tvb;
325
0
        tvb = tvb_new_subset_length(tvb_original, PWC_SIZEOF_CW, payload_size);
326
0
        item2 = proto_tree_add_item(tree2, hf_payload, tvb, 0, -1, ENC_NA);
327
0
        pwc_item_append_text_n_items(item2,(int)payload_size,"octet");
328
0
        if (properties & PWC_PAY_SIZE_BAD)
329
0
        {
330
0
          expert_add_info_format(pinfo, item2, &ei_payload_size_invalid_error,
331
0
            "CESoPSN packet payload size must be multiple of 8");
332
0
        }
333
0
        tree2 = proto_item_add_subtree(item2, ett_pw_cesopsn);
334
0
        call_data_dissector(tvb, pinfo, tree2);
335
0
        item2 = proto_tree_add_int(tree2, hf_payload_l, tvb, 0, 0
336
0
          ,(int)payload_size); /* allow filtering */
337
0
        proto_item_set_hidden(item2);
338
0
      }
339
0
    }
340
341
    /* padding */
342
0
    if (padding_size > 0)
343
0
    {
344
0
      proto_tree* tree2;
345
0
      tree2 = proto_item_add_subtree(item, ett_pw_cesopsn);
346
0
      {
347
0
        tvbuff_t* tvb;
348
0
        tvb = tvb_new_subset_length(tvb_original, PWC_SIZEOF_CW + payload_size, padding_size);
349
0
        call_dissector(pw_padding_handle, tvb, pinfo, tree2);
350
0
      }
351
0
    }
352
0
  }
353
0
  return;
354
0
}
355
356
357
static
358
int dissect_pw_cesopsn_mpls( tvbuff_t * tvb_original, packet_info * pinfo, proto_tree * tree, void* data _U_)
359
0
{
360
0
  dissect_pw_cesopsn(tvb_original,pinfo,tree,PWC_DEMUX_MPLS);
361
0
  return tvb_captured_length(tvb_original);
362
0
}
363
364
365
static
366
int dissect_pw_cesopsn_udp( tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void* data _U_)
367
0
{
368
0
  dissect_pw_cesopsn(tvb,pinfo,tree,PWC_DEMUX_UDP);
369
0
  return tvb_captured_length(tvb);
370
0
}
371
372
373
void proto_register_pw_cesopsn(void)
374
15
{
375
15
  static hf_register_info hf[] = {
376
15
    { &hf_cw  ,{"Control Word"    ,"pwcesopsn.cw"
377
15
          ,FT_NONE      ,BASE_NONE    ,NULL
378
15
          ,0        ,NULL      ,HFILL }},
379
380
15
    {&hf_cw_bits03,{"Bits 0 to 3"     ,"pwcesopsn.cw.bits03"
381
15
        ,FT_UINT8     ,BASE_DEC   ,NULL
382
15
        ,0xf0       ,NULL      ,HFILL }},
383
384
15
    { &hf_cw_lm,  {"L+M bits"     ,"pwcesopsn.cw.lm"
385
15
         ,FT_UINT8      ,BASE_HEX   ,VALS(vals_cw_lm)
386
15
         ,0x0b          ,NULL      ,HFILL }},
387
388
15
    {&hf_cw_r,  {"R bit: Local CE-bound IWF"  ,"pwcesopsn.cw.rbit"
389
15
         ,FT_UINT8      ,BASE_DEC   ,VALS(pwc_vals_cw_r_bit)
390
15
         ,0x04        ,NULL      ,HFILL }},
391
392
15
    {&hf_cw_frg,  {"Fragmentation"    ,"pwcesopsn.cw.frag"
393
15
         ,FT_UINT8      ,BASE_DEC   ,VALS(pwc_vals_cw_frag)
394
15
         ,0xc0        ,NULL      ,HFILL }},
395
396
15
    {&hf_cw_len,  {"Length"     ,"pwcesopsn.cw.length"
397
15
         ,FT_UINT8      ,BASE_DEC   ,NULL
398
15
         ,0x3f        ,NULL      ,HFILL }},
399
400
15
    {&hf_cw_seq,  {"Sequence number"    ,"pwcesopsn.cw.seqno"
401
15
         ,FT_UINT16     ,BASE_DEC   ,NULL
402
15
         ,0       ,NULL      ,HFILL }},
403
404
15
    {&hf_payload  ,{"TDM payload"     ,"pwcesopsn.payload"
405
15
          ,FT_BYTES     ,BASE_NONE    ,NULL
406
15
          ,0        ,NULL      ,HFILL }},
407
408
15
    {&hf_payload_l  ,{"TDM payload length"    ,"pwcesopsn.payload.len"
409
15
          ,FT_INT32     ,BASE_DEC   ,NULL
410
15
          ,0        ,NULL      ,HFILL }}
411
15
  };
412
413
15
  static int *ett_array[] = {
414
15
    &ett_pw_cesopsn
415
15
  };
416
15
  static ei_register_info ei[] = {
417
15
    { &ei_packet_size_too_small, { "pwcesopsn.packet_size_too_small", PI_MALFORMED, PI_ERROR, "PW packet size is too small to carry sensible information", EXPFILL }},
418
15
    { &ei_cw_bits03, { "pwcesopsn.cw.bits03.not_zero", PI_MALFORMED, PI_ERROR, "Bits 0..3 of Control Word must be 0", EXPFILL }},
419
15
    { &ei_cw_lm, { "pwcesopsn.cw.lm.reserved", PI_UNDECODED, PI_WARN, "Reserved combination of L and Modifier bits", EXPFILL }},
420
15
    { &ei_cw_frg, { "pwcesopsn.cw.frag.not_allowed", PI_MALFORMED, PI_ERROR, "Fragmentation of payload is not allowed for basic CESoPSN mode", EXPFILL }},
421
15
    { &ei_pref_cw_len, { "pwcesopsn.cw.length.invalid", PI_MALFORMED, PI_ERROR, "Bad Length: too small", EXPFILL }},
422
15
    { &ei_payload_size_invalid_error, { "pwcesopsn.payload.size_invalid", PI_MALFORMED, PI_ERROR, "CESoPSN payload size invalid", EXPFILL }},
423
15
    { &ei_payload_size_invalid_undecoded, { "pwcesopsn.payload.undecoded", PI_UNDECODED, PI_NOTE, "CESoPSN payload: omitted to conserve bandwidth", EXPFILL }},
424
15
  };
425
15
  expert_module_t* expert_pwcesopsn;
426
427
15
  proto = proto_register_protocol("CESoPSN basic NxDS0 mode (no RTP support)", "CESoPSN basic (no RTP)", "pwcesopsn");
428
15
  proto_register_field_array(proto, hf, array_length(hf));
429
15
  proto_register_subtree_array(ett_array, array_length(ett_array));
430
15
  expert_pwcesopsn = expert_register_protocol(proto);
431
15
  expert_register_field_array(expert_pwcesopsn, ei, array_length(ei));
432
15
  pw_cesopsn_mpls_handle = register_dissector("pw_cesopsn_mpls", dissect_pw_cesopsn_mpls, proto);
433
15
  pw_cesopsn_udp_handle = register_dissector("pw_cesopsn_udp", dissect_pw_cesopsn_udp, proto);
434
15
}
435
436
437
void proto_reg_handoff_pw_cesopsn(void)
438
15
{
439
15
  pw_padding_handle = find_dissector_add_dependency("pw_padding", proto);
440
441
  /* For Decode As */
442
15
  dissector_add_for_decode_as("mpls.label", pw_cesopsn_mpls_handle);
443
15
  dissector_add_for_decode_as("mpls.pfn", pw_cesopsn_mpls_handle);
444
445
15
  dissector_add_for_decode_as_with_preference("udp.port", pw_cesopsn_udp_handle);
446
15
}
447
448
/*
449
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
450
 *
451
 * Local variables:
452
 * c-basic-offset: 8
453
 * tab-width: 8
454
 * indent-tabs-mode: t
455
 * End:
456
 *
457
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
458
 * :indentSize=8:tabSize=8:noTabs=false:
459
 */