2 * Routines for SAToP PW dissection as per RFC4553.
3 * Copyright 2009, Dmitry Trebich, Artem Tamazov <artem.tamazov@tellabs.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
12 * ---------------------------------
13 * 19.03.2009 initial implementation
14 * 14.08.2009 added: support for IP/UDP demultiplexing
16 * - Decoding of PW payload
21 #include <epan/packet.h>
22 #include <epan/expert.h>
24 #include "packet-mpls.h"
25 #include "packet-pw-common.h"
26 #include "packet-rtp.h"
30 void proto_register_pw_satop(void);
31 void proto_reg_handoff_pw_satop(void);
33 static int proto
= -1;
34 static int ett_pw_satop
;
37 static int hf_cw_bits03
;
44 static int hf_payload
;
45 static int hf_payload_l
;
47 static expert_field ei_cw_rsv
;
48 static expert_field ei_payload_size_invalid_undecoded
;
49 static expert_field ei_payload_size_invalid
;
50 static expert_field ei_cw_frg
;
51 static expert_field ei_cw_bits03
;
52 static expert_field ei_cw_packet_size_too_small
;
54 static dissector_handle_t pw_padding_handle
;
55 static dissector_handle_t pw_satop_udp_handle
;
56 static dissector_handle_t pw_satop_mpls_handle
;
58 const char pwc_longname_pw_satop
[] = "SAToP";
59 static const char shortname
[] = "SAToP";
62 static bool pref_has_rtp_header
;
63 static bool pref_heuristic_rtp_header
= true;
67 void dissect_pw_satop(tvbuff_t
* tvb_original
70 ,pwc_demux_type_t demux
)
72 int min_packet_size_this_dissector
= PWC_SIZEOF_CW
;
75 int rtp_header_offset
;
88 ,PAY_LIKE_OCTET_ALIGNED_T1
94 if (dissect_try_cw_first_nibble(tvb_original
, pinfo
, tree
))
102 DISSECTOR_ASSERT_NOT_REACHED();
106 packet_size
= tvb_reported_length_remaining(tvb_original
, 0);
107 if (pref_has_rtp_header
) {
108 min_packet_size_this_dissector
+= SIZEOF_RTP
;
111 if (packet_size
< min_packet_size_this_dissector
)
114 item
= proto_tree_add_item(tree
, proto
, tvb_original
, 0, -1, ENC_NA
);
115 expert_add_info_format(pinfo
, item
, &ei_cw_packet_size_too_small
,
116 "PW packet size (%d) is too small to carry sensible information"
118 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, shortname
);
119 col_set_str(pinfo
->cinfo
, COL_INFO
, "Malformed: PW packet is too small");
126 rtp_header_offset
= PWC_SIZEOF_CW
;
127 sn
= tvb_get_uint16(tvb_original
, 2, ENC_BIG_ENDIAN
);
130 rtp_header_offset
= 0;
131 sn
= tvb_get_uint16(tvb_original
, SIZEOF_RTP
+ 2, ENC_BIG_ENDIAN
);
134 DISSECTOR_ASSERT_NOT_REACHED();
138 if ((pref_has_rtp_header
) ||
139 ((pref_heuristic_rtp_header
) &&
140 /* Check for RTP version 2, the other fields must be zero */
141 (tvb_get_uint8(tvb_original
, rtp_header_offset
) == 0x80) &&
142 /* Check the marker is zero. Unfortunately PT is not always from the dynamic range */
143 ((tvb_get_uint8(tvb_original
, rtp_header_offset
+ 1) & 0x80) == 0) &&
144 /* The sequence numbers from cw and RTP header must match */
145 (tvb_get_ntohs(tvb_original
, rtp_header_offset
+ 2) == sn
)))
153 cw_offset
= SIZEOF_RTP
;
156 DISSECTOR_ASSERT_NOT_REACHED();
159 encaps_size
= PWC_SIZEOF_CW
+ SIZEOF_RTP
;
160 has_rtp_header
= true;
163 encaps_size
= PWC_SIZEOF_CW
;
164 has_rtp_header
= false;
167 /* check how "good" is this packet */
168 /* also decide payload length from packet size, CW and optional RTP header */
170 if (0 != (tvb_get_uint8(tvb_original
, cw_offset
) & 0xf0 /*bits03*/))
172 properties
|= PWC_CW_BAD_BITS03
;
174 if (0 != (tvb_get_uint8(tvb_original
, cw_offset
) & 0x03 /*rsv*/))
176 properties
|= PWC_CW_BAD_RSV
;
178 if (0 != (tvb_get_uint8(tvb_original
, cw_offset
+ 1) & 0xc0 /*frag*/))
180 properties
|= PWC_CW_BAD_FRAG
;
184 * [...MAY be used to carry the length of the SAToP
185 * packet (defined as the size of the SAToP header + the payload
186 * size) if it is less than 64 bytes, and MUST be set to zero
189 * Note that this differs from RFC4385's definition of length:
190 * [ If the MPLS payload is less than 64 bytes, the length field
191 * MUST be set to the length of the PW payload...]
193 * We will use RFC4553's definition here.
196 int payload_size_from_packet
;
198 cw_len
= tvb_get_uint8(tvb_original
, cw_offset
+ 1) & 0x3f;
199 payload_size_from_packet
= packet_size
- encaps_size
;
202 int payload_size_from_cw
;
203 payload_size_from_cw
= cw_len
- encaps_size
;
205 * Assumptions for error case,
206 * will be overwritten if no errors found:
208 payload_size
= payload_size_from_packet
;
211 if (payload_size_from_cw
< 0)
213 properties
|= PWC_CW_BAD_PAYLEN_LT_0
;
215 else if (payload_size_from_cw
> payload_size_from_packet
)
217 properties
|= PWC_CW_BAD_PAYLEN_GT_PACKET
;
219 else if (payload_size_from_packet
>= 64)
221 properties
|= PWC_CW_BAD_LEN_MUST_BE_0
;
225 payload_size
= payload_size_from_cw
;
226 padding_size
= payload_size_from_packet
- payload_size_from_cw
; /* >=0 */
231 payload_size
= payload_size_from_packet
;
235 if (payload_size
== 0)
238 * As CW.L it indicates that PW payload is invalid, dissector should
239 * not blame packets with bad payload (including "bad" or "strange" SIZE of
240 * payload) when L bit is set.
242 if (0 == (tvb_get_uint8(tvb_original
, cw_offset
) & 0x08 /*L bit*/))
244 properties
|= PWC_PAY_SIZE_BAD
;
248 /* guess about payload type */
249 if (payload_size
== 256)
251 payload_properties
= PAY_LIKE_E1
;
253 else if (payload_size
== 192)
255 payload_properties
= PAY_LIKE_T1
;
257 else if (payload_size
== 1024)
259 payload_properties
= PAY_LIKE_E3_T3
;
261 else if ((payload_size
!= 0) && (payload_size
% 25 == 0))
263 payload_properties
= PAY_LIKE_OCTET_ALIGNED_T1
;
267 payload_properties
= PAY_NO_IDEA
; /*we do not have any ideas about payload type*/
271 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, shortname
);
272 col_clear(pinfo
->cinfo
, COL_INFO
);
273 if (properties
& PWC_ANYOF_CW_BAD
)
275 col_set_str(pinfo
->cinfo
, COL_INFO
, "CW:Bad, ");
278 if (properties
& PWC_PAY_SIZE_BAD
)
280 col_append_str(pinfo
->cinfo
, COL_INFO
, "Payload size:0 (Bad)");
284 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "TDM octets:%d", (int)payload_size
);
287 if (padding_size
!= 0)
289 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", Padding:%d", (int)padding_size
);
295 item
= proto_tree_add_item(tree
, proto
, tvb_original
, 0, -1, ENC_NA
);
296 pwc_item_append_cw(item
, tvb_get_ntohl(tvb_original
, cw_offset
), true);
297 pwc_item_append_text_n_items(item
, (int)payload_size
, "octet");
300 tree2
= proto_item_add_subtree(item
, ett_pw_satop
);
301 if (has_rtp_header
&& demux
== PWC_DEMUX_UDP
)
303 dissect_rtp_shim_header(tvb_original
, 0, pinfo
, tree2
, NULL
);
309 tvb
= tvb_new_subset_length(tvb_original
, cw_offset
, PWC_SIZEOF_CW
);
310 item2
= proto_tree_add_item(tree2
, hf_cw
, tvb
, 0, -1, ENC_NA
);
311 pwc_item_append_cw(item2
, tvb_get_ntohl(tvb
, 0), false);
314 tree3
= proto_item_add_subtree(item2
, ett_pw_satop
);
317 if (properties
& PWC_CW_BAD_BITS03
) /*display only if value is wrong*/
319 item3
= proto_tree_add_item(tree3
, hf_cw_bits03
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
320 expert_add_info(pinfo
, item3
, &ei_cw_bits03
);
323 proto_tree_add_item(tree3
, hf_cw_l
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
324 proto_tree_add_item(tree3
, hf_cw_r
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
326 item3
= proto_tree_add_item(tree3
, hf_cw_rsv
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
327 if (properties
& PWC_CW_BAD_RSV
)
329 expert_add_info(pinfo
, item3
, &ei_cw_rsv
);
332 item3
= proto_tree_add_item(tree3
, hf_cw_frg
, tvb
, 1, 1, ENC_BIG_ENDIAN
);
333 if (properties
& PWC_CW_BAD_FRAG
)
335 expert_add_info(pinfo
, item3
, &ei_cw_frg
);
338 item3
= proto_tree_add_item(tree3
, hf_cw_len
, tvb
, 1, 1, ENC_BIG_ENDIAN
);
339 if (properties
& PWC_CW_BAD_PAYLEN_LT_0
)
341 expert_add_info_format(pinfo
, item3
, &ei_payload_size_invalid
,
342 "Bad Length: too small, must be > %d",
345 if (properties
& PWC_CW_BAD_PAYLEN_GT_PACKET
)
347 expert_add_info_format(pinfo
, item3
, &ei_payload_size_invalid
,
348 "Bad Length: must be <= than PSN packet size (%d)",
351 if (properties
& PWC_CW_BAD_LEN_MUST_BE_0
)
353 expert_add_info_format(pinfo
, item3
, &ei_payload_size_invalid
,
354 "Bad Length: must be 0 if SAToP packet size (%d) is > 64",
358 proto_tree_add_item(tree3
, hf_cw_seq
, tvb
, 2, 2, ENC_BIG_ENDIAN
);
363 if (has_rtp_header
&& demux
!= PWC_DEMUX_UDP
)
365 dissect_rtp_shim_header(tvb_original
, PWC_SIZEOF_CW
, pinfo
, tree2
, NULL
);
370 if (properties
& PWC_PAY_SIZE_BAD
)
372 expert_add_info_format(pinfo
, item
, &ei_payload_size_invalid
,
373 "SAToP payload: none found. Size of payload must be <> 0");
375 else if (payload_size
== 0)
377 expert_add_info(pinfo
, item
, &ei_payload_size_invalid_undecoded
);
383 tree2
= proto_item_add_subtree(item
, ett_pw_satop
);
387 tvb
= tvb_new_subset_length(tvb_original
, encaps_size
, payload_size
);
388 item2
= proto_tree_add_item(tree2
, hf_payload
, tvb
, 0, -1, ENC_NA
);
389 pwc_item_append_text_n_items(item2
, (int)payload_size
, "octet");
393 switch(payload_properties
)
396 s
= " (looks like E1)";
399 s
= " (looks like T1)";
402 s
= " (looks like E3/T3)";
404 case PAY_LIKE_OCTET_ALIGNED_T1
:
405 s
= " (looks like octet-aligned T1)";
412 proto_item_append_text(item2
, "%s", s
);
413 tree3
= proto_item_add_subtree(item2
, ett_pw_satop
);
414 call_data_dissector(tvb
, pinfo
, tree3
);
415 item2
= proto_tree_add_int(tree3
, hf_payload_l
, tvb
, 0, 0
416 ,(int)payload_size
); /* allow filtering */
417 proto_item_set_hidden(item2
);
423 if (padding_size
> 0)
426 tree2
= proto_item_add_subtree(item
, ett_pw_satop
);
429 tvb
= tvb_new_subset_length_caplen(tvb_original
, PWC_SIZEOF_CW
+ payload_size
, padding_size
, -1);
430 call_dissector(pw_padding_handle
, tvb
, pinfo
, tree2
);
439 int dissect_pw_satop_mpls( tvbuff_t
* tvb_original
, packet_info
* pinfo
, proto_tree
* tree
, void* data _U_
)
441 dissect_pw_satop(tvb_original
,pinfo
,tree
,PWC_DEMUX_MPLS
);
442 return tvb_captured_length(tvb_original
);
447 int dissect_pw_satop_udp( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, void* data _U_
)
449 dissect_pw_satop(tvb
,pinfo
,tree
,PWC_DEMUX_UDP
);
450 return tvb_captured_length(tvb
);
454 void proto_register_pw_satop(void)
456 static hf_register_info hf
[] = {
457 { &hf_cw
,{"Control Word" ,"pwsatop.cw"
458 ,FT_NONE
,BASE_NONE
,NULL
461 {&hf_cw_bits03
,{"Bits 0 to 3" ,"pwsatop.cw.bits03"
462 ,FT_UINT8
,BASE_DEC
,NULL
463 ,0xf0 ,NULL
,HFILL
}},
465 {&hf_cw_l
, {"L bit: TDM payload state" ,"pwsatop.cw.lbit"
466 ,FT_UINT8
,BASE_DEC
,VALS(pwc_vals_cw_l_bit
)
467 ,0x08 ,NULL
,HFILL
}},
469 {&hf_cw_r
, {"R bit: Local CE-bound IWF" ,"pwsatop.cw.rbit"
470 ,FT_UINT8
,BASE_DEC
,VALS(pwc_vals_cw_r_bit
)
471 ,0x04 ,NULL
,HFILL
}},
473 {&hf_cw_rsv
, {"Reserved" ,"pwsatop.cw.rsv"
474 ,FT_UINT8
,BASE_DEC
,NULL
475 ,0x03 ,NULL
,HFILL
}},
477 {&hf_cw_frg
, {"Fragmentation" ,"pwsatop.cw.frag"
478 ,FT_UINT8
,BASE_DEC
,VALS(pwc_vals_cw_frag
)
479 ,0xc0 ,NULL
,HFILL
}},
481 {&hf_cw_len
, {"Length" ,"pwsatop.cw.length"
482 ,FT_UINT8
,BASE_DEC
,NULL
483 ,0x3f ,NULL
,HFILL
}},
485 {&hf_cw_seq
, {"Sequence number" ,"pwsatop.cw.seqno"
486 ,FT_UINT16
,BASE_DEC
,NULL
489 {&hf_payload
,{"TDM payload" ,"pwsatop.payload"
490 ,FT_BYTES
,BASE_NONE
,NULL
493 {&hf_payload_l
,{"TDM payload length" ,"pwsatop.payload.len"
494 ,FT_INT32
,BASE_DEC
,NULL
498 static int *ett_array
[] = {
501 static ei_register_info ei
[] = {
502 { &ei_cw_packet_size_too_small
, { "pwsatop.packet_size_too_small", PI_MALFORMED
, PI_ERROR
, "PW packet size is too small to carry sensible information", EXPFILL
}},
503 { &ei_cw_bits03
, { "pwsatop.cw.bits03.not_zero", PI_MALFORMED
, PI_ERROR
, "Bits 0..3 of Control Word must be 0", EXPFILL
}},
504 { &ei_cw_rsv
, { "pwsatop.cw.rsv.not_zero", PI_MALFORMED
, PI_ERROR
, "RSV bits of Control Word must be 0", EXPFILL
}},
505 { &ei_cw_frg
, { "pwsatop.cw.frag.not_allowed", PI_MALFORMED
, PI_ERROR
, "Fragmentation of payload is not allowed for SAToP", EXPFILL
}},
506 { &ei_payload_size_invalid
, { "pwsatop.payload.size_invalid", PI_MALFORMED
, PI_ERROR
, "Bad Length: too small", EXPFILL
}},
507 { &ei_payload_size_invalid_undecoded
, { "pwsatop.payload.undecoded", PI_UNDECODED
, PI_NOTE
, "SAToP payload: omitted to conserve bandwidth", EXPFILL
}},
510 module_t
*pwsatop_module
;
511 expert_module_t
* expert_pwsatop
;
513 proto
= proto_register_protocol(pwc_longname_pw_satop
, shortname
, "pwsatopcw");
514 proto_register_field_array(proto
, hf
, array_length(hf
));
515 proto_register_subtree_array(ett_array
, array_length(ett_array
));
516 expert_pwsatop
= expert_register_protocol(proto
);
517 expert_register_field_array(expert_pwsatop
, ei
, array_length(ei
));
518 pwsatop_module
= prefs_register_protocol(proto
, NULL
);
519 prefs_register_bool_preference(pwsatop_module
, "rtp_header", "RTP header in SAToP header",
520 "Whether or not the RTP header is present in the SAToP header.", &pref_has_rtp_header
);
521 prefs_register_bool_preference(pwsatop_module
, "rtp_header_heuristic", "Try to find RTP header in SAToP header",
522 "Heuristically determine if an RTP header is present in the SAToP header.", &pref_heuristic_rtp_header
);
523 pw_satop_mpls_handle
= register_dissector("pw_satop_mpls", dissect_pw_satop_mpls
, proto
);
524 pw_satop_udp_handle
= register_dissector("pw_satop_udp", dissect_pw_satop_udp
, proto
);
527 void proto_reg_handoff_pw_satop(void)
529 pw_padding_handle
= find_dissector_add_dependency("pw_padding", proto
);
532 dissector_add_for_decode_as("mpls.label", pw_satop_mpls_handle
);
533 dissector_add_for_decode_as("mpls.pfn", pw_satop_mpls_handle
);
534 dissector_add_for_decode_as_with_preference("udp.port", pw_satop_udp_handle
);
538 * Editor modelines - https://www.wireshark.org/tools/modelines.html
543 * indent-tabs-mode: t
546 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
547 * :indentSize=8:tabSize=8:noTabs=false: