2 * Routines for Frame Relay MPLS PW dissection as per RFC4619.
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 * 18.03.2009 initial implementation
16 * - Correct FR decode for encapsulations which contain fragmented FR frames.
17 * - FR DLCI Martini (legacy) mode (i.e. legacy CW).
22 #include <epan/packet.h>
23 #include <epan/expert.h>
25 #include "packet-mpls.h"
27 void proto_register_pw_fr(void);
28 void proto_reg_handoff_pw_fr(void);
30 static int proto_encaps
;
31 static int ett_encaps
;
33 /* static int hf_pw_fr; */
34 static int hf_cw_bits03
;
35 static int hf_cw_fecn
;
36 static int hf_cw_becn
;
42 static int hf_cw_padding
;
44 static expert_field ei_payload_size_invalid
;
45 static expert_field ei_cw_bits03
;
46 static expert_field ei_cw_packet_size_too_small
;
48 static const value_string vals_frg
[] = {
49 { 0x0, "Unfragmented" },
50 { 0x1, "First fragment" },
51 { 0x2, "Last fragment" },
52 { 0x3, "Intermediate fragment" },
57 static dissector_handle_t fr_stripped_address_handle
;
58 static dissector_handle_t pw_fr_mpls_handle
;
61 dissect_pw_fr( tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, void* data _U_
)
66 const int encaps_size
= 4; /*encapsulation consists of mandatory CW only*/
69 ,PQ_CW_BAD_BITS03
= 0x002
70 ,PQ_CW_BAD_LEN_GT_PACKET
= 0x004
71 ,PQ_CW_BAD_LEN_MUST_BE_ZERO
= 0x008
72 ,PQ_CW_BAD_LEN_MUST_BE_NONZERO
= 0x010
73 ,PQ_PAYLOAD_SIZE_ZERO
= 0x020
77 packet_size
= tvb_reported_length_remaining(tvb
, 0);
78 if (packet_size
< encaps_size
)
82 item
= proto_tree_add_item(tree
, proto_encaps
, tvb
, 0, -1, ENC_NA
);
83 expert_add_info_format(pinfo
, item
, &ei_cw_packet_size_too_small
,
84 "PW packet (%d) is smaller than PW encapsulation header (%d)",
85 (int)packet_size
,(int)encaps_size
);
87 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "FR PW");
88 col_set_str(pinfo
->cinfo
, COL_INFO
, "Malformed: PW packet < PW encapsulation header");
92 if (dissect_try_cw_first_nibble(tvb
,pinfo
,tree
))
94 return tvb_captured_length(tvb
);
97 /* check how "good" is this packet */
98 /* also decide payload length from packet size and CW */
100 if (0 != (tvb_get_uint8(tvb
, 0) & 0xf0 /*bits03*/))
102 packet_quality
|= PQ_CW_BAD
+ PQ_CW_BAD_BITS03
;
106 * [ If the frame's length (defined as the
107 * length of the layer 2 payload plus the length of the control word)
108 * is less than 64 octets, the length field MUST be set to the PW
109 * payload length. Otherwise, the length field MUST be set to zero. ]
111 * Note difference from RFC4385 which states that:
112 * [..the length field MUST be set to the length of the PW payload
113 * *plus* the length of the *PWMCW*. ]
116 int payload_size_packet
; /*derived from packet size*/
118 cw_len
= tvb_get_uint8(tvb
, 1) & 0x3f;
119 payload_size_packet
= packet_size
- encaps_size
;
122 * Initial assumptions.
124 payload_size
= payload_size_packet
;
127 if (payload_size_packet
< 64)
129 int payload_size_cw
; /*derived from cw*/
130 payload_size_cw
= cw_len
; /*RFC4619-specific*/
131 if (payload_size_cw
== 0)
133 packet_quality
|= PQ_CW_BAD
+ PQ_CW_BAD_LEN_MUST_BE_NONZERO
;
135 else if (payload_size_cw
> payload_size_packet
)
137 packet_quality
|= PQ_CW_BAD
+ PQ_CW_BAD_LEN_GT_PACKET
;
141 payload_size
= payload_size_cw
;
142 payload_padding
= payload_size_packet
- payload_size_cw
; /* >=0 */
145 else /* payload_size_packet >= 64 */
149 packet_quality
|= PQ_CW_BAD
+ PQ_CW_BAD_LEN_MUST_BE_ZERO
;
153 if (payload_size
== 0)
155 packet_quality
|= PQ_PAYLOAD_SIZE_ZERO
;
158 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "FR PW");
159 col_clear(pinfo
->cinfo
, COL_INFO
);
160 if (packet_quality
& PQ_CW_BAD
)
162 col_set_str(pinfo
->cinfo
, COL_INFO
, "CW:Malformed, ");
164 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%d payload octets", (int)payload_size
);
166 if (payload_padding
!= 0)
168 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %d padding", (int)payload_padding
);
173 proto_item
* item_headline
;
176 item_headline
= proto_tree_add_item(tree
, proto_encaps
, tvb
, 0, 4, ENC_NA
);
177 proto_item_append_text(item_headline
, ": 0x%.8" PRIx32
, tvb_get_ntohl(tvb
, 0));
178 subtree
= proto_item_add_subtree(item_headline
, ett_encaps
);
180 if (packet_quality
& PQ_CW_BAD_BITS03
) /*display only if value is wrong*/
182 item
= proto_tree_add_item(subtree
, hf_cw_bits03
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
183 expert_add_info(pinfo
, item
, &ei_cw_bits03
);
186 proto_tree_add_item( subtree
, hf_cw_fecn
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
187 proto_tree_add_item( subtree
, hf_cw_becn
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
188 proto_tree_add_item( subtree
, hf_cw_de
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
189 proto_tree_add_item( subtree
, hf_cw_cr
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
190 proto_tree_add_item( subtree
, hf_cw_frg
, tvb
, 1, 1, ENC_BIG_ENDIAN
);
192 item
= proto_tree_add_item( subtree
, hf_cw_len
, tvb
, 1, 1, ENC_BIG_ENDIAN
);
193 if (packet_quality
& PQ_CW_BAD_LEN_GT_PACKET
)
195 expert_add_info_format(pinfo
, item
, &ei_payload_size_invalid
,
196 "Bad Length: greater than FR payload size (%d)",
199 if (packet_quality
& PQ_CW_BAD_LEN_MUST_BE_NONZERO
)
201 expert_add_info_format(pinfo
, item
, &ei_payload_size_invalid
,
202 "Bad Length: must be non-zero if FR PW packet size (%d) is < 64",
203 (int)(payload_size
+encaps_size
));
205 if (packet_quality
& PQ_CW_BAD_LEN_MUST_BE_ZERO
)
207 expert_add_info_format(pinfo
, item
, &ei_payload_size_invalid
,
208 "Bad Length: must be 0 if FR PW packet size (%d) is >= 64",
209 (int)(payload_size
+encaps_size
));
212 proto_tree_add_item( subtree
, hf_cw_seq
, tvb
, 2, 2, ENC_BIG_ENDIAN
);
214 if (payload_padding
> 0)
216 proto_tree_add_item(subtree
, hf_cw_padding
, tvb
,
217 encaps_size
+payload_size
, payload_padding
, ENC_NA
);
220 if (packet_quality
& PQ_PAYLOAD_SIZE_ZERO
)
222 expert_add_info_format(pinfo
, item_headline
, &ei_payload_size_invalid
,
223 "FR payload size must be non-zero");
227 if (payload_size
> 0)
229 tvbuff_t
*tvb_payload
;
230 tvb_payload
= tvb_new_subset_length(tvb
, encaps_size
, payload_size
);
231 call_dissector( fr_stripped_address_handle
, tvb_payload
, pinfo
, tree
);
233 return tvb_captured_length(tvb
);
238 proto_register_pw_fr(void)
240 static hf_register_info hf
[] = {
241 {&hf_cw_bits03
,{"Bits 0 to 3" ,"pwfr.bits03" ,FT_UINT8
,BASE_HEX
245 {&hf_cw_fecn
,{"FR FECN" ,"pwfr.fecn" ,FT_UINT8
,BASE_DEC
246 ,NULL
,0x08 ,"FR Forward Explicit Congestion Notification bit"
249 {&hf_cw_becn
,{"FR BECN" ,"pwfr.becn" ,FT_UINT8
,BASE_DEC
250 ,NULL
,0x04 ,"FR Backward Explicit Congestion Notification bit"
253 {&hf_cw_de
,{"FR DE bit" ,"pwfr.de" ,FT_UINT8
,BASE_DEC
254 ,NULL
,0x02 ,"FR Discard Eligibility bit"
257 {&hf_cw_cr
,{"FR Frame C/R" ,"pwfr.cr" ,FT_UINT8
,BASE_DEC
258 ,NULL
,0x01 ,"FR frame Command/Response bit"
261 {&hf_cw_frg
,{"Fragmentation" ,"pwfr.frag" ,FT_UINT8
,BASE_DEC
262 ,VALS(vals_frg
) ,0xc0 ,NULL
265 {&hf_cw_len
,{"Length" ,"pwfr.length" ,FT_UINT8
,BASE_DEC
269 {&hf_cw_seq
,{"Sequence number" ,"pwfr.seqno" ,FT_UINT16
,BASE_DEC
273 {&hf_cw_padding
,{"Padding" ,"pwfr.padding" ,FT_BYTES
, BASE_NONE
278 static int *ett
[] = {
282 static ei_register_info ei
[] = {
283 { &ei_cw_packet_size_too_small
, { "pwfr.packet_size_too_small", PI_MALFORMED
, PI_ERROR
, "PW packet is smaller than PW encapsulation header", EXPFILL
}},
284 { &ei_cw_bits03
, { "pwfr.cw.bits03.not_zero", PI_MALFORMED
, PI_ERROR
, "Bits 0..3 of Control Word must be 0", EXPFILL
}},
285 { &ei_payload_size_invalid
, { "pwfr.payload.size_invalid", PI_MALFORMED
, PI_ERROR
, "Bad Length: greater than FR payload size", EXPFILL
}},
287 expert_module_t
* expert_pwfr
;
289 proto_encaps
= proto_register_protocol( "PW Frame Relay DLCI Control Word",
290 "Frame Relay DLCI PW",
292 proto_register_field_array(proto_encaps
, hf
, array_length(hf
));
293 proto_register_subtree_array(ett
, array_length(ett
));
294 expert_pwfr
= expert_register_protocol(proto_encaps
);
295 expert_register_field_array(expert_pwfr
, ei
, array_length(ei
));
296 pw_fr_mpls_handle
= register_dissector("pw_fr", dissect_pw_fr
, proto_encaps
);
301 proto_reg_handoff_pw_fr(void)
303 dissector_add_for_decode_as("mpls.label", pw_fr_mpls_handle
);
304 dissector_add_for_decode_as("mpls.pfn", pw_fr_mpls_handle
);
305 fr_stripped_address_handle
= find_dissector_add_dependency("fr_stripped_address", proto_encaps
);
309 * Editor modelines - https://www.wireshark.org/tools/modelines.html
314 * indent-tabs-mode: t
317 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
318 * :indentSize=8:tabSize=8:noTabs=false: