/src/wireshark/epan/dissectors/packet-gfp.c
Line | Count | Source |
1 | | /* packet-gfp.c |
2 | | * Routines for Generic Framing Procedure dissection |
3 | | * Copyright 2015, John Thacker <johnthacker@gmail.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 | | |
12 | | /* |
13 | | * Generic Framing Procedure (GFP) is used to map octet-aligned variable |
14 | | * length payloads (e.g. Ethernet, MPLS, octet-aligned PPP, IP) into |
15 | | * octet-synchronous signals such as SONET/SDH (ITU-T G.707) and OTN |
16 | | * (ITU-T G.709). GFP is a telecommunications industry standard defined in |
17 | | * ITU-T G.7041/Y.1303. |
18 | | * |
19 | | * Reference: |
20 | | * https://www.itu.int/rec/T-REC-G.7041/ |
21 | | */ |
22 | | |
23 | | #include <config.h> |
24 | | |
25 | | #include <epan/packet.h> /* Should be first Wireshark include (other than config.h) */ |
26 | | #include <epan/expert.h> |
27 | | #include <epan/tfs.h> |
28 | | #include <epan/crc16-tvb.h> |
29 | | #include <epan/crc32-tvb.h> |
30 | | #include <epan/decode_as.h> |
31 | | #include <epan/proto_data.h> |
32 | | |
33 | | #include <wiretap/wtap.h> |
34 | | |
35 | | /* Prototypes */ |
36 | | /* (Required to prevent [-Wmissing-prototypes] warnings */ |
37 | | void proto_reg_handoff_gfp(void); |
38 | | void proto_register_gfp(void); |
39 | | |
40 | | /* Dissector handle */ |
41 | | static dissector_handle_t gfp_handle; |
42 | | |
43 | | /* Initialize the protocol and registered fields */ |
44 | | static int proto_gfp; |
45 | | static int hf_gfp_pli; |
46 | | static int hf_gfp_chec; |
47 | | static int hf_gfp_chec_status; |
48 | | static int hf_gfp_type; |
49 | | static int hf_gfp_pti; |
50 | | static int hf_gfp_pfi; |
51 | | static int hf_gfp_exi; |
52 | | static int hf_gfp_upi_data; |
53 | | static int hf_gfp_upi_management; |
54 | | static int hf_gfp_thec; |
55 | | static int hf_gfp_thec_status; |
56 | | static int hf_gfp_cid; |
57 | | static int hf_gfp_ehec; |
58 | | static int hf_gfp_ehec_status; |
59 | | static int hf_gfp_fcs; |
60 | | static int hf_gfp_fcs_good; |
61 | | static int hf_gfp_fcs_bad; |
62 | | |
63 | | static expert_field ei_gfp_pli_idle_nonempty; |
64 | | static expert_field ei_gfp_pli_unknown; |
65 | | static expert_field ei_gfp_pli_invalid; |
66 | | static expert_field ei_gfp_chec_bad; |
67 | | static expert_field ei_gfp_thec_bad; |
68 | | static expert_field ei_gfp_ehec_bad; |
69 | | static expert_field ei_gfp_exi_short; |
70 | | static expert_field ei_gfp_pfi_short; |
71 | | static expert_field ei_gfp_payload_undecoded; |
72 | | static expert_field ei_gfp_fcs_bad; |
73 | | |
74 | 0 | #define GFP_USER_DATA 0 |
75 | 0 | #define GFP_CLIENT_MANAGEMENT 4 |
76 | 0 | #define GFP_MANAGEMENT_COMMUNICATIONS 5 |
77 | | |
78 | 0 | #define GFP_EXT_NULL 0 |
79 | 0 | #define GFP_EXT_LINEAR 1 |
80 | 0 | #define GFP_EXT_RING 2 |
81 | | |
82 | | /* Initialize the subtree pointers */ |
83 | | static int ett_gfp; |
84 | | static int ett_gfp_type; |
85 | | static int ett_gfp_fcs; |
86 | | |
87 | | static dissector_table_t gfp_dissector_table; |
88 | | |
89 | | /* ITU-T G.7041 6.1.1, 6.2 */ |
90 | | static const range_string gfp_pli_rvals[] = { |
91 | | {0, 0, "Idle Frame"}, |
92 | | {1, 3, "Control Frame (Reserved)"}, |
93 | | {4, UINT16_MAX, "Client Frame"}, |
94 | | {0, 0, NULL} |
95 | | }; |
96 | | |
97 | | static int * const gfp_type_data_fields[] = { |
98 | | &hf_gfp_pti, |
99 | | &hf_gfp_pfi, |
100 | | &hf_gfp_exi, |
101 | | &hf_gfp_upi_data, |
102 | | NULL |
103 | | }; |
104 | | |
105 | | static int * const gfp_type_management_fields[] = { |
106 | | &hf_gfp_pti, |
107 | | &hf_gfp_pfi, |
108 | | &hf_gfp_exi, |
109 | | &hf_gfp_upi_management, |
110 | | NULL |
111 | | }; |
112 | | |
113 | | static const value_string gfp_pti_vals[] = { |
114 | | {GFP_USER_DATA, "User Data"}, |
115 | | {GFP_CLIENT_MANAGEMENT, "Client Management"}, |
116 | | {GFP_MANAGEMENT_COMMUNICATIONS, "Management Communications"}, |
117 | | {0, NULL} |
118 | | }; |
119 | | |
120 | | static const value_string gfp_exi_vals[] = { |
121 | | {GFP_EXT_NULL, "Null Extension Header"}, |
122 | | {GFP_EXT_LINEAR, "Linear Frame"}, |
123 | | {GFP_EXT_RING, "Ring Frame"}, |
124 | | {0, NULL} |
125 | | }; |
126 | | |
127 | | static const range_string gfp_upi_data_rvals[] = { |
128 | | {0, 0, "Reserved and not available"}, |
129 | | {1, 1, "Frame-Mapped Ethernet"}, |
130 | | {2, 2, "Frame-Mapped PPP"}, |
131 | | {3, 3, "Transparent Fibre Channel"}, |
132 | | {4, 4, "Transparent FICON"}, |
133 | | {5, 5, "Transparent ESCON"}, |
134 | | {6, 6, "Transparent Gbit Ethernet"}, |
135 | | {7, 7, "Reserved"}, |
136 | | {8, 8, "Frame-Mapped Multiple Access Protocol over SDH (MAPOS)"}, |
137 | | {9, 9, "Transparent DVB ASI"}, |
138 | | {10, 10, "Frame-Mapped IEEE 802.17 Resilient Packet Ring"}, |
139 | | {11, 11, "Frame-Mapped Fibre Channel FC-BBW"}, |
140 | | {12, 12, "Asynchronous Transparent Fibre Channel"}, |
141 | | {13, 13, "Frame-Mapped MPLS"}, |
142 | | {14, 14, "Frame-Mapped MPLS (Multicast) [Deprecated]"}, |
143 | | {15, 15, "Frame-Mapped OSI network layer protocols (IS-IS, ES-IS, CLNP)"}, |
144 | | {16, 16, "Frame-Mapped IPv4"}, |
145 | | {17, 17, "Frame-Mapped IPv6"}, |
146 | | {18, 18, "Frame-Mapped DVB-ASI"}, |
147 | | {19, 19, "Frame-Mapped 64B/66B encoded Ethernet, including frame preamble"}, |
148 | | {20, 20, "Frame-Mapped 64B/66B encoded Ethernet ordered set information"}, |
149 | | {21, 21, "Transparent transcoded FC-1200"}, |
150 | | /*UPI value 22 & 23 from Amendment 3 (01/2015)*/ |
151 | | {22, 22, "Precision Time Protocol message"}, |
152 | | {23, 23, "Synchronization status message"}, |
153 | | {24, 239, "Reserved for future standardization"}, |
154 | | {240, 252, "Reserved for proprietary use"}, |
155 | | {253, 253, "Reserved for proprietary use, formerly Frame-Mapped 64B/66B encoded Ethernet, including frame preamble"}, |
156 | | {254, 254, "Reserved for proprietary use, formerly Frame-Mapped 64B/66B encoded Ethernet ordered set information"}, |
157 | | {255, 255, "Reserved and not available"}, |
158 | | {0, 0, NULL } |
159 | | }; |
160 | | |
161 | | static const range_string gfp_upi_management_rvals[] = { |
162 | | {0, 0, "Reserved and not available"}, |
163 | | {1, 1, "Client Signal Fail (Loss of Client Signal)"}, |
164 | | {2, 2, "Client Signal Fail (Loss of Character Synchronisation)"}, |
165 | | {3, 3, "Defect Clear Indication (DCI)"}, |
166 | | {4, 4, "Forward Defect Indication (FDI)"}, |
167 | | {5, 5, "Reverse Defect Indication (RDI)"}, |
168 | | {6, 223, "Reserved for future use"}, |
169 | | {224, 254, "Reserved for proprietary use"}, |
170 | | {255, 255, "Reserved and not available"}, |
171 | | {0, 0, NULL} |
172 | | }; |
173 | | |
174 | | |
175 | | /* Even GFP idle frames must have 4 bytes for the core header. |
176 | | * If data is received with fewer than this it is rejected. */ |
177 | 0 | #define GFP_MIN_LENGTH 4 |
178 | | |
179 | | static void gfp_prompt(packet_info *pinfo, char* result) |
180 | 0 | { |
181 | 0 | snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "UPI %u as", |
182 | 0 | GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_gfp, 0))); |
183 | 0 | } |
184 | | |
185 | | static void *gfp_value(packet_info *pinfo) |
186 | 0 | { |
187 | 0 | return p_get_proto_data(pinfo->pool, pinfo, proto_gfp, 0); |
188 | 0 | } |
189 | | |
190 | | /* GFP has several identical 16 bit CRCs in its header (HECs). Note that |
191 | | * this function increases the offset. */ |
192 | | static void |
193 | | gfp_add_hec_tree(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned *offset, const unsigned len, const int field, const int field_status, expert_field *ei_bad) |
194 | 0 | { |
195 | |
|
196 | 0 | unsigned hec_calc; |
197 | |
|
198 | 0 | hec_calc = crc16_r3_ccitt_tvb(tvb, *offset, len); |
199 | 0 | *offset += len; |
200 | |
|
201 | 0 | proto_tree_add_checksum(tree, tvb, *offset, field, field_status, ei_bad, pinfo, hec_calc, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY); |
202 | 0 | *offset += 2; |
203 | 0 | } |
204 | | |
205 | | /* G.7041 6.1.2 GFP payload area */ |
206 | | static void |
207 | | dissect_gfp_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree *gfp_tree, unsigned *offset, unsigned payload_len) |
208 | 0 | { |
209 | 0 | tvbuff_t *payload_tvb; |
210 | 0 | proto_item *type_ti = NULL; |
211 | 0 | proto_item *fcs_ti; |
212 | 0 | proto_tree *fcs_tree = NULL; |
213 | 0 | unsigned pti, pfi, exi, upi; |
214 | 0 | unsigned fcs, fcs_calc; |
215 | 0 | unsigned fcs_len = 0; |
216 | | |
217 | | /* G.7041 6.1.2.3 Payload area scrambling |
218 | | * Note that payload when sent on the wire is scrambled as per ATM |
219 | | * with a 1 + x^43 multiplicative scrambler. Likely already removed by |
220 | | * the time we get a capture file (as with ATM). Could have a pref, |
221 | | * but if it's present we have to save state over subsequent frames, |
222 | | * always would fail to decode the first 43 payload bytes of a capture. */ |
223 | | |
224 | | /* G.7041 6.1.2.1 Payload Header - at least 4 bytes */ |
225 | 0 | tvb_ensure_bytes_exist(tvb, *offset, 4); |
226 | 0 | payload_len -= 4; |
227 | | |
228 | | /* G.7041 6.1.2.1.1 GFP type field - mandatory 2 bytes */ |
229 | 0 | pti = tvb_get_bits8(tvb, 8*(*offset), 3); |
230 | 0 | pfi = tvb_get_bits8(tvb, 8*(*offset)+3, 1); |
231 | 0 | exi = tvb_get_bits8(tvb, 8*(*offset)+4, 4); |
232 | 0 | upi = tvb_get_uint8(tvb, *offset+1); |
233 | 0 | p_add_proto_data(pinfo->pool, pinfo, proto_gfp, 0, GUINT_TO_POINTER(upi)); |
234 | |
|
235 | 0 | col_add_str(pinfo->cinfo, COL_INFO, val_to_str(pinfo->pool, pti, gfp_pti_vals, "Reserved PTI (%d)")); |
236 | 0 | if (pti == GFP_USER_DATA || |
237 | 0 | pti == GFP_MANAGEMENT_COMMUNICATIONS) { |
238 | | /* G.7041 Table 6-3 - GFP_MANAGEMENT_COMMUNICATIONS |
239 | | * uses the same UPI table as USER_DATA, though |
240 | | * "not all of these UPI types are applicable" in that case. */ |
241 | 0 | type_ti = proto_tree_add_bitmask_with_flags(gfp_tree, tvb, *offset, hf_gfp_type, |
242 | 0 | ett_gfp_type, gfp_type_data_fields, ENC_BIG_ENDIAN, BMT_NO_FLAGS); |
243 | 0 | col_append_sep_str(pinfo->cinfo, COL_INFO, ": ", rval_to_str_wmem(pinfo->pool, upi, gfp_upi_data_rvals, "Unknown 0x%02x")); |
244 | 0 | } else if (pti == GFP_CLIENT_MANAGEMENT) { |
245 | | /* G.7041 Table 6-4 */ |
246 | 0 | type_ti = proto_tree_add_bitmask_with_flags(gfp_tree, tvb, *offset, hf_gfp_type, |
247 | 0 | ett_gfp_type, gfp_type_management_fields, ENC_BIG_ENDIAN, BMT_NO_FLAGS); |
248 | 0 | col_append_sep_str(pinfo->cinfo, COL_INFO, ": ", rval_to_str_wmem(pinfo->pool, upi, gfp_upi_management_rvals, "Unknown 0x%02x")); |
249 | 0 | } |
250 | | |
251 | | /* G.7041 6.1.2.1.2 Type HEC (tHEC) - mandatory 2 bytes */ |
252 | 0 | gfp_add_hec_tree(tvb, pinfo, gfp_tree, offset, 2, hf_gfp_thec, hf_gfp_thec_status, &ei_gfp_thec_bad); |
253 | |
|
254 | 0 | switch (exi) { |
255 | 0 | case GFP_EXT_NULL: |
256 | | /* G.7041 6.1.2.1.3.1 Null extension header */ |
257 | 0 | break; |
258 | | |
259 | 0 | case GFP_EXT_LINEAR: |
260 | | /* G.7041 6.1.2.1.3.2 Extension header for a linear frame */ |
261 | 0 | if (payload_len < 4) { |
262 | 0 | expert_add_info(pinfo, type_ti, &ei_gfp_exi_short); |
263 | 0 | payload_len = 0; |
264 | 0 | } |
265 | 0 | else { |
266 | 0 | payload_len -= 4; |
267 | 0 | } |
268 | 0 | proto_tree_add_item(gfp_tree, hf_gfp_cid, tvb, *offset, 1, ENC_BIG_ENDIAN); |
269 | | /* Next byte spare field, reserved */ |
270 | | |
271 | | /* 6.1.2.1.4 Extension HEC field */ |
272 | 0 | gfp_add_hec_tree(tvb, pinfo, gfp_tree, offset, 2, hf_gfp_ehec, hf_gfp_ehec_status, &ei_gfp_ehec_bad); |
273 | 0 | break; |
274 | 0 | case GFP_EXT_RING: |
275 | | /* 6.1.2.1.3.3 Extension header for a ring frame */ |
276 | | /* "For further study." Undefined so fall through */ |
277 | 0 | default: |
278 | | /* Reserved */ |
279 | | /* TODO: Mark as error / unhandled? */ |
280 | 0 | break; |
281 | 0 | } |
282 | | |
283 | 0 | proto_item_set_end(gfp_tree, tvb, *offset); |
284 | |
|
285 | 0 | if (pfi == 1) { /* 6.1.2.2.1 Payload FCS field present */ |
286 | 0 | if (payload_len < 4) { |
287 | 0 | expert_add_info(pinfo, type_ti, &ei_gfp_pfi_short); |
288 | 0 | fcs_len = payload_len; |
289 | 0 | payload_len = 0; |
290 | 0 | } else { |
291 | 0 | fcs_len = 4; |
292 | 0 | payload_len -= 4; |
293 | 0 | } |
294 | |
|
295 | 0 | proto_tree_set_appendix(gfp_tree, tvb, *offset + payload_len, fcs_len); |
296 | 0 | fcs = tvb_get_ntohl(tvb, *offset + payload_len); |
297 | | /* Same CRC32 as ATM */ |
298 | | /* As with ATM, we can either compute the CRC as it would be |
299 | | * calculated and compare (last step involves taking the complement), |
300 | | * or we can include the passed CRC in the input and check to see |
301 | | * if the remainder is a known value. I like the first method |
302 | | * only because it lets us display what we should have received. */ |
303 | | /* Method 1: */ |
304 | 0 | fcs_calc = crc32_mpeg2_tvb_offset(tvb, *offset, payload_len); |
305 | 0 | if (fcs == ~fcs_calc) { |
306 | 0 | fcs_ti = proto_tree_add_uint_format_value(gfp_tree, hf_gfp_fcs, tvb, *offset+payload_len, 4, fcs, "0x%08x [correct]", fcs); |
307 | 0 | fcs_tree = proto_item_add_subtree(fcs_ti, ett_gfp_fcs); |
308 | 0 | fcs_ti = proto_tree_add_boolean(fcs_tree, hf_gfp_fcs_good, tvb, *offset+payload_len, 4, true); |
309 | 0 | proto_item_set_generated(fcs_ti); |
310 | 0 | fcs_ti = proto_tree_add_boolean(fcs_tree, hf_gfp_fcs_bad, tvb, *offset+payload_len, 4, false); |
311 | 0 | proto_item_set_generated(fcs_ti); |
312 | 0 | } else { |
313 | 0 | fcs_ti = proto_tree_add_uint_format_value(gfp_tree, hf_gfp_fcs, tvb, *offset+payload_len, 4, fcs, "0x%08x [incorrect, should be 0x%08x]", fcs, fcs_calc); |
314 | 0 | fcs_tree = proto_item_add_subtree(fcs_ti, ett_gfp_fcs); |
315 | 0 | fcs_ti = proto_tree_add_boolean(fcs_tree, hf_gfp_fcs_good, tvb, *offset+payload_len, 4, false); |
316 | 0 | proto_item_set_generated(fcs_ti); |
317 | 0 | fcs_ti = proto_tree_add_boolean(fcs_tree, hf_gfp_fcs_bad, tvb, *offset+payload_len, 4, true); |
318 | 0 | proto_item_set_generated(fcs_ti); |
319 | 0 | expert_add_info(pinfo, fcs_ti, &ei_gfp_fcs_bad); |
320 | 0 | } |
321 | | /* Method 2: */ |
322 | | /* fcs_calc = crc32_mpeg2_tvb_offset(tvb, *offset, payload_len+4); |
323 | | fcs_ti = proto_tree_add_uint(gfp_tree, hf_gfp_fcs, tvb, *offset+payload_len, 4, fcs); |
324 | | proto_item_append_text(fcs_ti, (fcs_calc == 0xC704DD7B) ? " [correct]" : " [incorrect]"); */ |
325 | 0 | } |
326 | | |
327 | | /* Some client frames we can do. Others are not implemented yet. |
328 | | * Transparent mode types are much trickier than frame-mapped, |
329 | | * since they requires reassembling streams across multiple GFP packets. */ |
330 | 0 | payload_tvb = tvb_new_subset_length(tvb, *offset, payload_len); |
331 | 0 | switch (pti) { |
332 | 0 | case GFP_USER_DATA: |
333 | 0 | case GFP_MANAGEMENT_COMMUNICATIONS: |
334 | 0 | if (!dissector_try_uint(gfp_dissector_table, upi, payload_tvb, pinfo, tree)) { |
335 | 0 | expert_add_info_format(pinfo, type_ti, &ei_gfp_payload_undecoded, "Payload type 0x%02x (%s) unsupported", upi, rval_to_str_const(upi, gfp_upi_data_rvals, "UNKNOWN")); |
336 | 0 | call_data_dissector(payload_tvb, pinfo, tree); |
337 | 0 | } |
338 | 0 | break; |
339 | | |
340 | 0 | case GFP_CLIENT_MANAGEMENT: |
341 | 0 | call_data_dissector(payload_tvb, pinfo, tree); |
342 | 0 | break; |
343 | | |
344 | 0 | default: |
345 | 0 | break; |
346 | 0 | } |
347 | 0 | *offset += payload_len; |
348 | 0 | *offset += fcs_len; |
349 | 0 | } |
350 | | |
351 | | static int |
352 | | dissect_gfp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
353 | | void *data _U_) |
354 | 0 | { |
355 | 0 | proto_item *ti, *pli_ti; |
356 | 0 | proto_tree *gfp_tree; |
357 | 0 | unsigned offset = 0; |
358 | 0 | int len = 0; |
359 | 0 | unsigned pli; |
360 | | |
361 | | /*** HEURISTICS ***/ |
362 | | |
363 | | /* Check that the packet is long enough for it to belong to us. */ |
364 | 0 | if (tvb_reported_length(tvb) < GFP_MIN_LENGTH) |
365 | 0 | return 0; |
366 | | |
367 | | /*** COLUMN DATA ***/ |
368 | | |
369 | | /* Set the Protocol column to the constant string of GFP */ |
370 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "GFP"); |
371 | |
|
372 | 0 | col_clear(pinfo->cinfo, COL_INFO); |
373 | | /* Avoid asserts for leaving these blank. */ |
374 | 0 | col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "N/A"); |
375 | 0 | col_set_str(pinfo->cinfo, COL_RES_DL_DST, "N/A"); |
376 | | |
377 | | /*** PROTOCOL TREE ***/ |
378 | | |
379 | | /* create display subtree for the protocol */ |
380 | 0 | ti = proto_tree_add_item(tree, proto_gfp, tvb, 0, GFP_MIN_LENGTH, ENC_NA); |
381 | |
|
382 | 0 | gfp_tree = proto_item_add_subtree(ti, ett_gfp); |
383 | | |
384 | | /* ITU-T G.7041 6.1.1 GFP core header */ |
385 | | /* The core header could be scrambled (see G.7041 6.1.1.3) but isn't on |
386 | | * the GFP level capture files I've seen as it's removed before then. |
387 | | * If using this as a subdissector to a SDH or OTN dissector, that could |
388 | | * be an issue. TODO: Maybe add a pref for scrambling? */ |
389 | 0 | len = 2; |
390 | 0 | pli_ti = proto_tree_add_item_ret_uint(gfp_tree, hf_gfp_pli, tvb, |
391 | 0 | offset, len, ENC_BIG_ENDIAN, &pli); |
392 | 0 | if (pli < 4) { /* Don't interpret as payload length */ |
393 | 0 | proto_item_append_text(pli_ti, " (%s)", rval_to_str_const(pli, gfp_pli_rvals, "Unknown")); |
394 | 0 | } |
395 | 0 | col_set_str(pinfo->cinfo, COL_INFO, rval_to_str_const(pli, gfp_pli_rvals, "Unknown")); |
396 | | |
397 | | /* 6.1.1.2 Core HEC field */ |
398 | 0 | gfp_add_hec_tree(tvb, pinfo, gfp_tree, &offset, len, hf_gfp_chec, hf_gfp_chec_status, &ei_gfp_chec_bad); |
399 | |
|
400 | 0 | if (pli == 0) { /* 6.2.1 GFP idle frames */ |
401 | 0 | if (tvb_reported_length_remaining(tvb, offset)) { |
402 | 0 | expert_add_info(pinfo, pli_ti, &ei_gfp_pli_idle_nonempty); |
403 | 0 | } |
404 | 0 | } else if (pli < 4) { /* 6.2.2 Other control frames (reserved) */ |
405 | 0 | expert_add_info(pinfo, pli_ti, &ei_gfp_pli_unknown); |
406 | 0 | } else { |
407 | | /* G.7041 6.1.2 GFP payload area */ |
408 | 0 | if (tvb_reported_length(tvb) < pli + offset) { |
409 | | /* avoid signed / unsigned comparison */ |
410 | 0 | proto_item_append_text(pli_ti, " (invalid, reported length is %u)", tvb_reported_length_remaining(tvb, offset)); |
411 | 0 | expert_add_info(pinfo, pli_ti, &ei_gfp_pli_invalid); |
412 | 0 | } |
413 | 0 | dissect_gfp_payload(tvb, pinfo, tree, gfp_tree, &offset, pli); |
414 | 0 | } |
415 | | |
416 | | /* Return the amount of data this dissector was able to dissect */ |
417 | 0 | return offset; |
418 | 0 | } |
419 | | |
420 | | void |
421 | | proto_register_gfp(void) |
422 | 14 | { |
423 | | /* Setup list of header fields See Section 1.5 of README.dissector for |
424 | | * details. */ |
425 | 14 | static hf_register_info hf[] = { |
426 | 14 | { &hf_gfp_pli, |
427 | 14 | { "Payload Length Indicator", "gfp.pli", FT_UINT16, BASE_DEC, |
428 | 14 | NULL, 0x0, NULL, HFILL } |
429 | 14 | }, |
430 | 14 | { &hf_gfp_chec, |
431 | 14 | { "Core HEC", "gfp.chec", FT_UINT16, BASE_HEX, |
432 | 14 | NULL, 0x0, NULL, HFILL } |
433 | 14 | }, |
434 | 14 | { &hf_gfp_chec_status, |
435 | 14 | { "cHEC Status", "gfp.chec.status", FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0, |
436 | 14 | NULL, HFILL } |
437 | 14 | }, |
438 | 14 | { &hf_gfp_type, |
439 | 14 | { "Type Field", "gfp.type", FT_UINT16, BASE_HEX, NULL, 0x0, |
440 | 14 | NULL, HFILL } |
441 | 14 | }, |
442 | 14 | { &hf_gfp_pti, |
443 | 14 | { "PTI", "gfp.pti", FT_UINT16, BASE_HEX, VALS(gfp_pti_vals), |
444 | 14 | 0xE000, "Payload Type Identifier", HFILL } |
445 | 14 | }, |
446 | 14 | { &hf_gfp_pfi, |
447 | 14 | { "PFI", "gfp.pfi", FT_BOOLEAN, 16, TFS(&tfs_present_absent), |
448 | 14 | 0x1000, "Payload FCS Indicator", HFILL } |
449 | 14 | }, |
450 | 14 | { &hf_gfp_exi, |
451 | 14 | { "EXI", "gfp.exi", FT_UINT16, BASE_HEX, VALS(gfp_exi_vals), |
452 | 14 | 0x0F00, "Extension Header Identifier", HFILL } |
453 | 14 | }, |
454 | 14 | { &hf_gfp_upi_data, |
455 | 14 | { "UPI", "gfp.upi", FT_UINT16, BASE_HEX|BASE_RANGE_STRING, |
456 | 14 | RVALS(gfp_upi_data_rvals), |
457 | 14 | 0xFF, "User Payload Identifier for Client Data Frame (or Management Communications Frame)", HFILL } |
458 | 14 | }, |
459 | 14 | { &hf_gfp_upi_management, |
460 | 14 | { "UPI", "gfp.upi", FT_UINT16, BASE_HEX|BASE_RANGE_STRING, |
461 | 14 | RVALS(gfp_upi_management_rvals), |
462 | 14 | 0xFF, "User Payload Identifier for Client Management Frame", HFILL } |
463 | 14 | }, |
464 | 14 | { &hf_gfp_thec, |
465 | 14 | { "Type HEC", "gfp.thec", FT_UINT16, BASE_HEX, NULL, 0x0, |
466 | 14 | NULL, HFILL } |
467 | 14 | }, |
468 | 14 | { &hf_gfp_thec_status, |
469 | 14 | { "tHEC Status", "gfp.thec.status", FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0, |
470 | 14 | NULL, HFILL } |
471 | 14 | }, |
472 | 14 | { &hf_gfp_cid, |
473 | 14 | { "Channel ID", "gfp.cid", FT_UINT8, BASE_HEX, NULL, 0x0, |
474 | 14 | NULL, HFILL } |
475 | 14 | }, |
476 | 14 | { &hf_gfp_ehec, |
477 | 14 | { "Extension HEC", "gfp.ehec", FT_UINT16, BASE_HEX, NULL, 0x0, |
478 | 14 | NULL, HFILL } |
479 | 14 | }, |
480 | 14 | { &hf_gfp_ehec_status, |
481 | 14 | { "eHEC Status", "gfp.ehec.status", FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0, |
482 | 14 | NULL, HFILL } |
483 | 14 | }, |
484 | 14 | { &hf_gfp_fcs, |
485 | 14 | { "Payload FCS", "gfp.fcs", FT_UINT32, BASE_HEX, NULL, 0x0, |
486 | 14 | NULL, HFILL } |
487 | 14 | }, |
488 | 14 | { &hf_gfp_fcs_good, |
489 | 14 | { "Good FCS", "gfp.fcs_good", FT_BOOLEAN, BASE_NONE, NULL, 0x0, |
490 | 14 | "True: FCS matches payload; False: doesn't match", HFILL } |
491 | 14 | }, |
492 | 14 | { &hf_gfp_fcs_bad, |
493 | 14 | { "Bad eHEC", "gfp.fcs_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0, |
494 | 14 | "True: FCS doesn't match payload; False: matches", HFILL } |
495 | 14 | } |
496 | 14 | }; |
497 | | |
498 | | /* Setup protocol subtree array */ |
499 | 14 | static int *ett[] = { |
500 | 14 | &ett_gfp, |
501 | 14 | &ett_gfp_type, |
502 | 14 | &ett_gfp_fcs |
503 | 14 | }; |
504 | | |
505 | | /* Setup protocol expert items */ |
506 | 14 | static ei_register_info ei[] = { |
507 | 14 | { &ei_gfp_pli_idle_nonempty, |
508 | 14 | { "gfp.pli.idle.nonempty", PI_MALFORMED, PI_ERROR, |
509 | 14 | "Payload present on idle frame", EXPFILL } |
510 | 14 | }, |
511 | 14 | { &ei_gfp_pli_unknown, |
512 | 14 | { "gfp.pli.unknown", PI_UNDECODED, PI_WARN, |
513 | 14 | "Unknown control frame type", EXPFILL } |
514 | 14 | }, |
515 | 14 | { &ei_gfp_pli_invalid, |
516 | 14 | { "gfp.pli.invalid", PI_MALFORMED, PI_WARN, |
517 | 14 | "Bogus PLI does not match reported length", EXPFILL } |
518 | 14 | }, |
519 | 14 | { &ei_gfp_chec_bad, |
520 | 14 | { "gfp.chec.bad", PI_CHECKSUM, PI_WARN, |
521 | 14 | "Bad cHEC", EXPFILL } |
522 | 14 | }, |
523 | 14 | { &ei_gfp_thec_bad, |
524 | 14 | { "gfp.thec.bad", PI_CHECKSUM, PI_WARN, |
525 | 14 | "Bad tHEC", EXPFILL } |
526 | 14 | }, |
527 | 14 | { &ei_gfp_ehec_bad, |
528 | 14 | { "gfp.ehec.bad", PI_CHECKSUM, PI_WARN, |
529 | 14 | "Bad eHEC", EXPFILL } |
530 | 14 | }, |
531 | 14 | { &ei_gfp_exi_short, |
532 | 14 | { "gfp.exi.missing", PI_MALFORMED, PI_ERROR, |
533 | 14 | "EXI bit set but PLI too short for extension header", EXPFILL} |
534 | 14 | }, |
535 | 14 | { &ei_gfp_pfi_short, |
536 | 14 | { "gfp.pfi.missing", PI_MALFORMED, PI_ERROR, |
537 | 14 | "PFI bit set but PLI too short for payload FCS", EXPFILL} |
538 | 14 | }, |
539 | 14 | { &ei_gfp_payload_undecoded, |
540 | 14 | { "gfp.payload.undecoded", PI_UNDECODED, PI_WARN, |
541 | 14 | "Payload type not supported yet by the dissector", EXPFILL} |
542 | 14 | }, |
543 | 14 | { &ei_gfp_fcs_bad, |
544 | 14 | { "gfp.fcs.bad", PI_CHECKSUM, PI_WARN, |
545 | 14 | "Bad FCS", EXPFILL } |
546 | 14 | } |
547 | 14 | }; |
548 | | |
549 | | /* Decode As handling */ |
550 | 14 | static build_valid_func gfp_da_build_value[1] = {gfp_value}; |
551 | 14 | static decode_as_value_t gfp_da_values = {gfp_prompt, 1, gfp_da_build_value}; |
552 | 14 | static decode_as_t gfp_da = {"gfp", "gfp.upi", 1, 0, &gfp_da_values, NULL, NULL, |
553 | 14 | decode_as_default_populate_list, decode_as_default_reset, decode_as_default_change, NULL, NULL, NULL }; |
554 | | |
555 | | /* module_t *gfp_module; */ |
556 | 14 | expert_module_t *expert_gfp; |
557 | | |
558 | | /* Register the protocol name and description */ |
559 | 14 | proto_gfp = proto_register_protocol("Generic Framing Procedure", |
560 | 14 | "GFP", "gfp"); |
561 | 14 | gfp_handle = register_dissector("gfp", dissect_gfp, |
562 | 14 | proto_gfp); |
563 | | |
564 | | /* Required function calls to register the header fields and subtrees */ |
565 | 14 | proto_register_field_array(proto_gfp, hf, array_length(hf)); |
566 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
567 | | |
568 | | /* Required function calls to register expert items */ |
569 | 14 | expert_gfp = expert_register_protocol(proto_gfp); |
570 | 14 | expert_register_field_array(expert_gfp, ei, array_length(ei)); |
571 | | |
572 | | /* Subdissectors for payload */ |
573 | 14 | gfp_dissector_table = register_dissector_table("gfp.upi", "GFP UPI (for Client Data frames)", |
574 | 14 | proto_gfp, FT_UINT8, BASE_DEC); |
575 | | |
576 | | /* Don't register a preferences module yet since there are no prefs in |
577 | | * order to avoid a warning. (See section 2.6 of README.dissector |
578 | | * for more details on preferences). */ |
579 | | /*gfp_module = prefs_register_protocol(proto_gfp, NULL);*/ |
580 | | |
581 | 14 | register_decode_as(&gfp_da); |
582 | 14 | } |
583 | | |
584 | | void |
585 | | proto_reg_handoff_gfp(void) |
586 | 14 | { |
587 | 14 | dissector_add_uint("wtap_encap", WTAP_ENCAP_GFP_T, gfp_handle); |
588 | 14 | dissector_add_uint("wtap_encap", WTAP_ENCAP_GFP_F, gfp_handle); |
589 | | |
590 | | /* Add a few of the easiest UPIs to decode. There's more that probably |
591 | | * would work, but are untested (frame mapped DVB, frame mapped Fibre |
592 | | * Channel). The transparent mode ones are trickier, since without a |
593 | | * one-to-one mapping of frames, we would have to reassemble payload |
594 | | * packets across multiple GFP packets. |
595 | | * |
596 | | * Section 7.1.1 "Ethernet MAC encapsulation" of G.7041 says |
597 | | * "The Ethernet MAC octets from destination address through |
598 | | * "frame check sequence, inclusive, are placed in the GFP payload |
599 | | * "information field.", so we want the dissector for Ethernet |
600 | | * frames including the FCS. */ |
601 | 14 | dissector_add_uint("gfp.upi", 1, find_dissector("eth_withfcs")); |
602 | 14 | dissector_add_uint("gfp.upi", 2, find_dissector("ppp_hdlc")); |
603 | 14 | dissector_add_uint("gfp.upi", 9, find_dissector("mp2t")); |
604 | 14 | dissector_add_uint("gfp.upi", 12, find_dissector("mpls")); |
605 | 14 | dissector_add_uint("gfp.upi", 13, find_dissector("mpls")); |
606 | 14 | dissector_add_uint("gfp.upi", 16, find_dissector("ip")); |
607 | 14 | dissector_add_uint("gfp.upi", 17, find_dissector("ipv6")); |
608 | 14 | } |
609 | | |
610 | | /* |
611 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
612 | | * |
613 | | * Local variables: |
614 | | * c-basic-offset: 4 |
615 | | * tab-width: 8 |
616 | | * indent-tabs-mode: nil |
617 | | * End: |
618 | | * |
619 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
620 | | * :indentSize=4:tabSize=8:noTabs=true: |
621 | | */ |