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