/src/wireshark/epan/dissectors/packet-fpp.c
Line | Count | Source |
1 | | /* packet-fpp.c |
2 | | * Routines for IEEE 802.3br Frame Preemption Protocol packet disassembly |
3 | | * |
4 | | * Copyright 2017, Anton Glukhov <anton.a.glukhov@gmail.com> |
5 | | * |
6 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1998 Gerald Combs |
9 | | * |
10 | | * SPDX-License-Identifier: GPL-2.0-or-later |
11 | | */ |
12 | | |
13 | | #include "config.h" |
14 | | |
15 | | #include <epan/packet.h> |
16 | | #include <wiretap/wtap.h> |
17 | | |
18 | | #include <epan/expert.h> |
19 | | #include <epan/conversation.h> |
20 | | #include <wsutil/crc32.h> |
21 | | #include <epan/crc32-tvb.h> |
22 | | #include <epan/reassemble.h> |
23 | | #include <epan/proto_data.h> |
24 | | |
25 | | void proto_register_fpp(void); |
26 | | void proto_reg_handoff_fpp(void); |
27 | | |
28 | | static int proto_fpp; |
29 | | |
30 | | static dissector_handle_t fpp_handle; |
31 | | |
32 | | static int hf_fpp_preamble; |
33 | | static int hf_fpp_preamble_pad; |
34 | | static int hf_fpp_preamble_smd; |
35 | | static int hf_fpp_preamble_frag_count; |
36 | | static int hf_fpp_mdata; |
37 | | static int hf_fpp_crc32; |
38 | | static int hf_fpp_crc32_status; |
39 | | static int hf_fpp_mcrc32; |
40 | | static int hf_fpp_mcrc32_status; |
41 | | |
42 | | static expert_field ei_fpp_crc32; |
43 | | static expert_field ei_fpp_mcrc32; |
44 | | |
45 | | static int ett_fpp; |
46 | | static int ett_fpp_preamble; |
47 | | |
48 | | static reassembly_table fpp_reassembly_table; |
49 | | |
50 | | static dissector_handle_t ethl2_handle; |
51 | | |
52 | | /* Reassembly Data */ |
53 | | static int hf_fpp_fragments; |
54 | | static int hf_fpp_fragment; |
55 | | static int hf_fpp_fragment_overlap; |
56 | | static int hf_fpp_fragment_overlap_conflicts; |
57 | | static int hf_fpp_fragment_multiple_tails; |
58 | | static int hf_fpp_fragment_too_long_fragment; |
59 | | static int hf_fpp_fragment_error; |
60 | | static int hf_fpp_fragment_count; |
61 | | static int hf_fpp_reassembled_in; |
62 | | static int hf_fpp_reassembled_length; |
63 | | static int ett_fpp_fragment; |
64 | | static int ett_fpp_fragments; |
65 | | |
66 | | static const fragment_items fpp_frag_items = { |
67 | | /* Fragment subtrees */ |
68 | | &ett_fpp_fragment, |
69 | | &ett_fpp_fragments, |
70 | | /* Fragment fields */ |
71 | | &hf_fpp_fragments, |
72 | | &hf_fpp_fragment, |
73 | | &hf_fpp_fragment_overlap, |
74 | | &hf_fpp_fragment_overlap_conflicts, |
75 | | &hf_fpp_fragment_multiple_tails, |
76 | | &hf_fpp_fragment_too_long_fragment, |
77 | | &hf_fpp_fragment_error, |
78 | | &hf_fpp_fragment_count, |
79 | | /* Reassembled in field */ |
80 | | &hf_fpp_reassembled_in, |
81 | | /* Reassembled length field */ |
82 | | &hf_fpp_reassembled_length, |
83 | | /* Reassembled data field */ |
84 | | NULL, |
85 | | /* Tag */ |
86 | | "fpp fragments" |
87 | | }; |
88 | | |
89 | 7 | #define FPP_DEFAULT_PREAMBLE_LENGTH 8 |
90 | 9 | #define FPP_CRC_LENGTH 4 |
91 | | |
92 | | typedef enum { |
93 | | FPP_Packet_Expess, |
94 | | FPP_Packet_Verify, |
95 | | FPP_Packet_Response, |
96 | | FPP_Packet_Init, |
97 | | FPP_Packet_Cont, |
98 | | FPP_Packet_Invalid, |
99 | | } fpp_packet_t; |
100 | | |
101 | | typedef enum { |
102 | | SMD_Verify = 0x7, |
103 | | SMD_Respond = 0x19, |
104 | | SMD_Express = 0xd5, |
105 | | SMD_PP_Start_0 = 0xe6, |
106 | | SMD_PP_Start_1 = 0x4c, |
107 | | SMD_PP_Start_2 = 0x7f, |
108 | | SMD_PP_Start_3 = 0xb3, |
109 | | FragCount_0 = SMD_PP_Start_0, |
110 | | FragCount_1 = SMD_PP_Start_1, |
111 | | FragCount_2 = SMD_PP_Start_2, |
112 | | FragCount_3 = SMD_PP_Start_3 |
113 | | } first_delim; |
114 | | |
115 | | typedef enum { |
116 | | Octet_0x55 = 0x55, |
117 | | SMD_PP_ContFrag_0 = 0x61, |
118 | | SMD_PP_ContFrag_1 = 0x52, |
119 | | SMD_PP_ContFrag_2 = 0x9e, |
120 | | SMD_PP_ContFrag_3 = 0x2a, |
121 | | } second_delim; |
122 | | |
123 | | typedef enum { |
124 | | CRC_CRC, |
125 | | CRC_mCRC, |
126 | | CRC_FALSE |
127 | | } fpp_crc_t; |
128 | | |
129 | | typedef enum { |
130 | | PACKET_DIRECTION_INBOUND = 0x1, |
131 | | PACKET_DIRECTION_OUTBOUND = 0x2, |
132 | | PACKET_DIRECTION_UNKNOWN = 0x0, |
133 | | } packet_direction_enum; |
134 | | |
135 | | /* Packets with correct CRC sum */ |
136 | | static const value_string preemptive_delim_desc[] = { |
137 | | { SMD_PP_Start_0, "[Non-fragmented packet: SMD-S0]" }, |
138 | | { SMD_PP_Start_1, "[Non-fragmented packet: SMD-S1]" }, |
139 | | { SMD_PP_Start_2, "[Non-fragmented packet: SMD-S2]" }, |
140 | | { SMD_PP_Start_3, "[Non-fragmented packet: SMD-S3]" }, |
141 | | { 0x0, NULL } |
142 | | }; |
143 | | |
144 | | /* Packets with correct mCRC sum */ |
145 | | static const value_string initial_delim_desc[] = { |
146 | | { SMD_PP_Start_0, "[Initial fragment: SMD-S0]" }, |
147 | | { SMD_PP_Start_1, "[Initial fragment: SMD-S1]" }, |
148 | | { SMD_PP_Start_2, "[Initial fragment: SMD-S2]" }, |
149 | | { SMD_PP_Start_3, "[Initial fragment: SMD-S3]" }, |
150 | | { 0x0, NULL } |
151 | | }; |
152 | | |
153 | | /* Packets with incorrect checksum */ |
154 | | static const value_string corrupted_delim_desc[] = { |
155 | | { SMD_PP_Start_0, "[Corrupted fragment: SMD-S0]" }, |
156 | | { SMD_PP_Start_1, "[Corrupted fragment: SMD-S1]" }, |
157 | | { SMD_PP_Start_2, "[Corrupted fragment: SMD-S2]" }, |
158 | | { SMD_PP_Start_3, "[Corrupted fragment: SMD-S3]" }, |
159 | | { 0x0, NULL } |
160 | | }; |
161 | | |
162 | | static const value_string continuation_delim_desc[] = { |
163 | | { SMD_PP_ContFrag_0, "[Continuation fragment: SMD-C0]" }, |
164 | | { SMD_PP_ContFrag_1, "[Continuation fragment: SMD-C1]" }, |
165 | | { SMD_PP_ContFrag_2, "[Continuation fragment: SMD-C2]" }, |
166 | | { SMD_PP_ContFrag_3, "[Continuation fragment: SMD-C3]" }, |
167 | | { 0x0, NULL } |
168 | | }; |
169 | | |
170 | | static const value_string frag_count_delim_desc[] = { |
171 | | { FragCount_0, "[#0]"}, |
172 | | { FragCount_1, "[#1]"}, |
173 | | { FragCount_2, "[#2]"}, |
174 | | { FragCount_3, "[#3]"}, |
175 | | { 0x0, NULL } |
176 | | }; |
177 | | |
178 | | static const value_string delim_desc[] = { |
179 | | { SMD_Verify, "[SMD-V]" }, |
180 | | { SMD_Respond, "[SMD-R]" }, |
181 | | { SMD_Express, "[SMD-E]" }, |
182 | | { SMD_PP_Start_0, "[SMD-S0]" }, |
183 | | { SMD_PP_Start_1, "[SMD-S1]" }, |
184 | | { SMD_PP_Start_2, "[SMD-S2]" }, |
185 | | { SMD_PP_Start_3, "[SMD-S3]" }, |
186 | | { SMD_PP_ContFrag_0, "[SMD-C0]" }, |
187 | | { SMD_PP_ContFrag_1, "[SMD-C1]" }, |
188 | | { SMD_PP_ContFrag_2, "[SMD-C2]" }, |
189 | | { SMD_PP_ContFrag_3, "[SMD-C3]" }, |
190 | | { 0x0, NULL } |
191 | | }; |
192 | | |
193 | | static uint32_t |
194 | 7 | get_preamble_length(tvbuff_t *tvb) { |
195 | | |
196 | 7 | uint32_t offset = 0; |
197 | | |
198 | 7 | if( 0x50 == tvb_get_uint8(tvb, offset) ) |
199 | 0 | { |
200 | | //First octet contains preamble alignment bits. Ignore it. |
201 | 0 | offset = 1; |
202 | 0 | } |
203 | | |
204 | 7 | while( tvb_get_uint8(tvb, offset) == Octet_0x55 && ( offset + 2 < tvb_reported_length(tvb) ) ) |
205 | 0 | { |
206 | 0 | offset++; |
207 | 0 | } |
208 | | |
209 | 7 | uint8_t smd1 = tvb_get_uint8(tvb, offset); |
210 | | |
211 | 7 | switch (smd1) { |
212 | 0 | case SMD_PP_Start_0: |
213 | 0 | case SMD_PP_Start_1: |
214 | 0 | case SMD_PP_Start_2: |
215 | 0 | case SMD_PP_Start_3: |
216 | 0 | case SMD_Verify: |
217 | 0 | case SMD_Respond: |
218 | 0 | case SMD_Express: |
219 | 0 | return offset + 1; |
220 | 6 | case SMD_PP_ContFrag_0: |
221 | 6 | case SMD_PP_ContFrag_1: |
222 | 6 | case SMD_PP_ContFrag_2: |
223 | 6 | case SMD_PP_ContFrag_3: |
224 | 6 | return offset + 2; |
225 | 1 | default: |
226 | 1 | return FPP_DEFAULT_PREAMBLE_LENGTH; |
227 | 7 | } |
228 | 7 | } |
229 | | |
230 | | static fpp_crc_t |
231 | 2 | get_crc_stat(tvbuff_t *tvb, uint32_t crc, uint32_t mcrc) { |
232 | 2 | fpp_crc_t crc_val; |
233 | 2 | uint32_t received_crc = tvb_get_uint32(tvb, tvb_reported_length(tvb) - FPP_CRC_LENGTH, ENC_BIG_ENDIAN); |
234 | | |
235 | 2 | if (received_crc == crc) { |
236 | 0 | crc_val = CRC_CRC; |
237 | 2 | } else if (received_crc == mcrc) { |
238 | 0 | crc_val = CRC_mCRC; |
239 | 2 | } else { |
240 | 2 | crc_val = CRC_FALSE; |
241 | 2 | } |
242 | 2 | return crc_val; |
243 | 2 | } |
244 | | |
245 | | static fpp_crc_t |
246 | 0 | get_express_crc_stat(tvbuff_t *tvb, uint32_t express_crc) { |
247 | 0 | fpp_crc_t crc_val; |
248 | 0 | uint32_t received_crc = tvb_get_uint32(tvb, tvb_reported_length(tvb) - FPP_CRC_LENGTH, ENC_BIG_ENDIAN); |
249 | |
|
250 | 0 | if (received_crc == express_crc) { |
251 | 0 | crc_val = CRC_CRC; |
252 | 0 | } else { |
253 | 0 | crc_val = CRC_FALSE; |
254 | 0 | } |
255 | 0 | return crc_val; |
256 | 0 | } |
257 | | |
258 | | static fpp_packet_t |
259 | 7 | get_packet_type(tvbuff_t *tvb) { |
260 | | /* function analyze a packet based on preamble and ignore crc */ |
261 | | |
262 | 7 | uint32_t offset = 0; |
263 | | |
264 | 7 | if( 0x50 == tvb_get_uint8(tvb, offset) ) |
265 | 0 | { |
266 | | //First octet contains preamble alignment bits. Ignore it. |
267 | 0 | offset = 1; |
268 | 0 | } |
269 | | |
270 | 7 | while( tvb_get_uint8(tvb, offset) == Octet_0x55 && ( offset + 2 < tvb_reported_length(tvb) ) ) |
271 | 0 | { |
272 | 0 | offset++; |
273 | 0 | } |
274 | | |
275 | 7 | uint8_t smd1 = tvb_get_uint8(tvb, offset); |
276 | 7 | uint8_t smd2 = tvb_get_uint8(tvb, offset + 1); |
277 | | |
278 | 7 | switch (smd1) { |
279 | 0 | case SMD_PP_Start_0: |
280 | 0 | case SMD_PP_Start_1: |
281 | 0 | case SMD_PP_Start_2: |
282 | 0 | case SMD_PP_Start_3: |
283 | 0 | return FPP_Packet_Init; |
284 | 0 | case SMD_Verify: |
285 | 0 | return FPP_Packet_Verify; |
286 | 0 | case SMD_Respond: |
287 | 0 | return FPP_Packet_Response; |
288 | 0 | case SMD_Express: |
289 | 0 | return FPP_Packet_Expess; |
290 | 6 | case SMD_PP_ContFrag_0: |
291 | 6 | case SMD_PP_ContFrag_1: |
292 | 6 | case SMD_PP_ContFrag_2: |
293 | 6 | case SMD_PP_ContFrag_3: |
294 | 6 | switch (smd2) { |
295 | 0 | case FragCount_0: |
296 | 0 | case FragCount_1: |
297 | 6 | case FragCount_2: |
298 | 6 | case FragCount_3: |
299 | 6 | return FPP_Packet_Cont; |
300 | 0 | default: |
301 | 0 | return FPP_Packet_Invalid; |
302 | 6 | } |
303 | 1 | default: |
304 | 1 | return FPP_Packet_Invalid; |
305 | 7 | } |
306 | | |
307 | 0 | return FPP_Packet_Invalid; |
308 | 7 | } |
309 | | |
310 | | static void |
311 | 2 | col_fstr_process(tvbuff_t *tvb, packet_info *pinfo, fpp_crc_t crc_val) { |
312 | 2 | unsigned preamble_length = get_preamble_length( tvb ); |
313 | | |
314 | 2 | switch( get_packet_type(tvb) ) { |
315 | 0 | case FPP_Packet_Expess: |
316 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "[Express]"); |
317 | 0 | break; |
318 | 0 | case FPP_Packet_Verify: |
319 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "[Verify]"); |
320 | 0 | break; |
321 | 0 | case FPP_Packet_Response: |
322 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "[Respond]"); |
323 | 0 | break; |
324 | 0 | case FPP_Packet_Init: |
325 | 0 | if (crc_val == CRC_CRC) |
326 | 0 | col_add_str(pinfo->cinfo, COL_INFO, try_val_to_str(tvb_get_uint8(tvb, preamble_length-1), preemptive_delim_desc)); |
327 | 0 | else if (crc_val == CRC_mCRC) |
328 | 0 | col_add_str(pinfo->cinfo, COL_INFO, try_val_to_str(tvb_get_uint8(tvb, preamble_length-1), initial_delim_desc)); |
329 | 0 | else |
330 | 0 | col_add_str(pinfo->cinfo, COL_INFO, try_val_to_str(tvb_get_uint8(tvb, preamble_length-1), corrupted_delim_desc)); |
331 | 0 | break; |
332 | 2 | case FPP_Packet_Cont: |
333 | 2 | col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s", try_val_to_str(tvb_get_uint8(tvb, preamble_length-2), continuation_delim_desc), |
334 | 2 | try_val_to_str(tvb_get_uint8(tvb, preamble_length-1), frag_count_delim_desc)); |
335 | 2 | break; |
336 | 0 | default: |
337 | 0 | break; |
338 | 2 | } |
339 | 2 | } |
340 | | |
341 | | struct _fpp_ctx_t { |
342 | | bool preemption; |
343 | | uint8_t frame_cnt; |
344 | | uint8_t frag_cnt; |
345 | | uint32_t size; |
346 | | uint32_t crc; |
347 | | wmem_map_t *crc_history; |
348 | | }; |
349 | | |
350 | | typedef struct _fpp_ctx_t fpp_ctx_t; |
351 | | |
352 | | static packet_direction_enum |
353 | 2 | get_packet_direction(packet_info *pinfo) { |
354 | 2 | switch (pinfo->p2p_dir) { |
355 | 0 | case P2P_DIR_RECV: |
356 | 0 | return PACKET_DIRECTION_INBOUND; |
357 | 0 | case P2P_DIR_SENT: |
358 | 0 | return PACKET_DIRECTION_OUTBOUND; |
359 | 2 | default: |
360 | 2 | return PACKET_DIRECTION_UNKNOWN; |
361 | 2 | } |
362 | 2 | } |
363 | | |
364 | | static void |
365 | 0 | init_fpp_ctx(struct _fpp_ctx_t *ctx, uint8_t frame_cnt, uint32_t crc) { |
366 | 0 | ctx->preemption = true; |
367 | 0 | ctx->frame_cnt = frame_cnt; |
368 | 0 | ctx->frag_cnt = FragCount_3; |
369 | 0 | ctx->size = 0; |
370 | 0 | ctx->crc = crc; |
371 | 0 | ctx->crc_history = wmem_map_new(wmem_epan_scope(), g_int_hash, g_int_equal); |
372 | 0 | } |
373 | | |
374 | | static uint8_t |
375 | 0 | frag_cnt_next(uint8_t cur_num) { |
376 | 0 | switch(cur_num) { |
377 | 0 | case FragCount_0: |
378 | 0 | return FragCount_1; |
379 | 0 | case FragCount_1: |
380 | 0 | return FragCount_2; |
381 | 0 | case FragCount_2: |
382 | 0 | return FragCount_3; |
383 | 0 | case FragCount_3: |
384 | 0 | default: |
385 | 0 | return FragCount_0; |
386 | 0 | } |
387 | 0 | } |
388 | | |
389 | | static uint8_t |
390 | 0 | get_cont_by_start(uint8_t start_cnt) { |
391 | 0 | if (start_cnt == SMD_PP_Start_0) |
392 | 0 | return SMD_PP_ContFrag_0; |
393 | 0 | else if (start_cnt == SMD_PP_Start_1) |
394 | 0 | return SMD_PP_ContFrag_1; |
395 | 0 | else if (start_cnt == SMD_PP_Start_2) |
396 | 0 | return SMD_PP_ContFrag_2; |
397 | 0 | else if (start_cnt == SMD_PP_Start_3) |
398 | 0 | return SMD_PP_ContFrag_3; |
399 | 0 | else |
400 | 0 | return SMD_PP_ContFrag_0; |
401 | 0 | } |
402 | | |
403 | | struct _fpp_pdata_t { |
404 | | /* struct for future possible usage */ |
405 | | uint32_t offset; |
406 | | }; |
407 | | |
408 | | typedef struct _fpp_pdata_t fpp_pdata_t; |
409 | | |
410 | | static void |
411 | 0 | drop_conversation(conversation_t *conv) { |
412 | 0 | fpp_ctx_t *ctx; |
413 | 0 | ctx = (fpp_ctx_t*)conversation_get_proto_data(conv, proto_fpp); |
414 | 0 | if (ctx != NULL) { |
415 | 0 | wmem_free(wmem_file_scope(), ctx); |
416 | 0 | } |
417 | 0 | conversation_delete_proto_data(conv, proto_fpp); |
418 | 0 | } |
419 | | |
420 | | static void |
421 | 0 | drop_fragments(packet_info *pinfo) { |
422 | 0 | tvbuff_t *tvbuf; |
423 | 0 | unsigned interface_id; |
424 | 0 | packet_direction_enum packet_direction = get_packet_direction(pinfo); |
425 | |
|
426 | 0 | if (pinfo->rec->presence_flags & WTAP_HAS_INTERFACE_ID) |
427 | 0 | interface_id = pinfo->rec->rec_header.packet_header.interface_id; |
428 | 0 | else |
429 | 0 | interface_id = 0; |
430 | 0 | interface_id = interface_id << 0x2; |
431 | 0 | tvbuf = fragment_delete(&fpp_reassembly_table, pinfo, interface_id | packet_direction, NULL); |
432 | |
|
433 | 0 | if (tvbuf != NULL) { |
434 | 0 | tvb_free(tvbuf); |
435 | 0 | } |
436 | 0 | } |
437 | | |
438 | | static tvbuff_t* |
439 | 2 | dissect_preemption(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { |
440 | 2 | fpp_packet_t pck_type; |
441 | | |
442 | 2 | unsigned preamble_length = get_preamble_length( tvb ); |
443 | 2 | unsigned preamble_bit_length = preamble_length * 8; |
444 | 2 | bool preamble_unaligned = false; |
445 | | |
446 | 2 | uint8_t smd1 = tvb_get_uint8(tvb, preamble_length - 2); |
447 | 2 | uint8_t smd2 = tvb_get_uint8(tvb, preamble_length - 1); |
448 | | |
449 | 2 | unsigned crc_offset = tvb_reported_length(tvb) - FPP_CRC_LENGTH; |
450 | 2 | int frag_size = tvb_reported_length(tvb) - preamble_length - FPP_CRC_LENGTH; |
451 | | |
452 | | /* Reassembly parameters. */ |
453 | 2 | tvbuff_t *new_tvb = NULL; |
454 | 2 | fragment_head *frag_data; |
455 | 2 | bool save_fragmented; |
456 | 2 | conversation_t *conv; |
457 | 2 | fpp_ctx_t *ctx; |
458 | 2 | unsigned interface_id; |
459 | 2 | packet_direction_enum packet_direction = get_packet_direction(pinfo); |
460 | 2 | fpp_crc_t crc_val; |
461 | | |
462 | | /* mCRC calculations needs previous crc */ |
463 | 2 | uint32_t crc, mcrc, prev_crc; |
464 | | |
465 | 2 | if (pinfo->rec->presence_flags & WTAP_HAS_INTERFACE_ID) |
466 | 0 | interface_id = pinfo->rec->rec_header.packet_header.interface_id; |
467 | 2 | else |
468 | 2 | interface_id = 0; |
469 | 2 | interface_id = interface_id << 0x2; |
470 | | |
471 | | /* Create a tree for the preamble. */ |
472 | 2 | proto_item *ti_preamble = proto_tree_add_item(tree, hf_fpp_preamble, tvb, 0, preamble_length, ENC_NA); |
473 | | |
474 | 2 | if( 0x50 == tvb_get_uint8(tvb, 0) ) |
475 | 0 | { |
476 | | //First octet contains preamble alignment bits. |
477 | 0 | preamble_bit_length -= 4; |
478 | 0 | preamble_unaligned = true; |
479 | 0 | } |
480 | | |
481 | 2 | if( preamble_bit_length == FPP_DEFAULT_PREAMBLE_LENGTH * 8 ) { |
482 | 0 | proto_item_append_text(ti_preamble, " [Preamble length: Normal]" ); |
483 | 2 | } else if( preamble_bit_length < FPP_DEFAULT_PREAMBLE_LENGTH * 8 ) { |
484 | 2 | proto_item_append_text(ti_preamble, " [Preamble length: Shortened by %d bits]", FPP_DEFAULT_PREAMBLE_LENGTH * 8 - preamble_bit_length ); |
485 | 2 | } else if( preamble_bit_length > FPP_DEFAULT_PREAMBLE_LENGTH * 8 ) { |
486 | 0 | proto_item_append_text(ti_preamble, " [Preamble length: Lengthened by %d bits]", preamble_bit_length - FPP_DEFAULT_PREAMBLE_LENGTH * 8 ); |
487 | 0 | } |
488 | | |
489 | 2 | proto_tree_add_item(tree, hf_fpp_mdata, tvb, preamble_length, frag_size, ENC_NA); |
490 | | |
491 | 2 | proto_tree *fpp_preamble_tree = proto_item_add_subtree(ti_preamble, ett_fpp_preamble); |
492 | | |
493 | 2 | if( preamble_unaligned ) { |
494 | 0 | proto_tree_add_item(fpp_preamble_tree, hf_fpp_preamble_pad, tvb, 0, 1, ENC_BIG_ENDIAN); |
495 | 0 | } |
496 | | |
497 | 2 | pck_type = get_packet_type(tvb); |
498 | | |
499 | 2 | if(pck_type == FPP_Packet_Cont) |
500 | 2 | { |
501 | 2 | proto_item *ti_smd = proto_tree_add_item(fpp_preamble_tree, hf_fpp_preamble_smd, tvb, preamble_length - 2, 1, ENC_BIG_ENDIAN); |
502 | 2 | proto_item *ti_fragcnt = proto_tree_add_item(fpp_preamble_tree, hf_fpp_preamble_frag_count, tvb, preamble_length - 1, 1, ENC_BIG_ENDIAN); |
503 | 2 | proto_item_append_text(ti_smd, " %s", try_val_to_str(tvb_get_uint8(tvb, preamble_length-2), delim_desc) ); |
504 | 2 | proto_item_append_text(ti_fragcnt, " %s", try_val_to_str(tvb_get_uint8(tvb, preamble_length-1), frag_count_delim_desc) ); |
505 | 2 | } |
506 | 0 | else |
507 | 0 | { |
508 | 0 | proto_item *ti_smd = proto_tree_add_item(fpp_preamble_tree, hf_fpp_preamble_smd, tvb, preamble_length - 1, 1, ENC_BIG_ENDIAN); |
509 | 0 | proto_item_append_text(ti_smd, " %s", try_val_to_str(tvb_get_uint8(tvb, preamble_length-1), delim_desc) ); |
510 | 0 | } |
511 | | |
512 | 2 | prev_crc = 0; |
513 | 2 | conv = find_conversation_by_id(pinfo->num, CONVERSATION_NONE, interface_id | packet_direction); |
514 | | /* Create a conversation at every SMD-S fragment. |
515 | | Find the conversation for every SMD-C fragment.*/ |
516 | 2 | if (pck_type == FPP_Packet_Init) { |
517 | | /* will be used for seeding the crc calculation */ |
518 | 0 | if (!PINFO_FD_VISITED(pinfo)) { |
519 | 0 | conv = conversation_new_by_id(pinfo->num, CONVERSATION_NONE, interface_id | packet_direction); |
520 | | /* XXX Is this needed? */ |
521 | 0 | find_conversation_pinfo(pinfo, 0); |
522 | 0 | } |
523 | 0 | } |
524 | 2 | else if (pck_type == FPP_Packet_Cont && conv) { |
525 | 0 | ctx = (fpp_ctx_t *)conversation_get_proto_data(conv, proto_fpp); |
526 | 0 | if (ctx) { |
527 | 0 | if (!PINFO_FD_VISITED(pinfo)) { |
528 | 0 | if ((ctx->preemption) && (ctx->frame_cnt == smd1) && (frag_cnt_next(ctx->frag_cnt) == smd2)) { |
529 | 0 | prev_crc = ctx->crc; |
530 | 0 | } |
531 | | /* create a copy of frame number and previous crc and store in crc_history */ |
532 | 0 | uint32_t *copy_of_pinfo_num = wmem_new(wmem_epan_scope(), uint32_t); |
533 | 0 | uint32_t *copy_of_prev_crc = wmem_new(wmem_epan_scope(), uint32_t); |
534 | 0 | *copy_of_pinfo_num = pinfo->num; |
535 | 0 | *copy_of_prev_crc = prev_crc; |
536 | 0 | wmem_map_insert(ctx->crc_history, copy_of_pinfo_num, copy_of_prev_crc); |
537 | 0 | } |
538 | 0 | else { |
539 | 0 | prev_crc = *(uint32_t *)wmem_map_lookup(ctx->crc_history, &pinfo->num); |
540 | 0 | } |
541 | 0 | } |
542 | 0 | } |
543 | | |
544 | 2 | crc = GUINT32_SWAP_LE_BE(crc32_ccitt_tvb_offset_seed(tvb, preamble_length, frag_size, GUINT32_SWAP_LE_BE(prev_crc) ^ 0xffffffff)); |
545 | 2 | mcrc = crc ^ 0xffff0000; |
546 | 2 | crc_val = get_crc_stat(tvb, crc, mcrc); /* might be crc if last part or mcrc if continuation */ |
547 | | |
548 | | /* fill column Info */ |
549 | 2 | col_fstr_process(tvb, pinfo, crc_val); |
550 | | |
551 | 2 | if (pck_type == FPP_Packet_Init) { |
552 | | /* Add data to this new conversation during first iteration*/ |
553 | 0 | if (conv && !PINFO_FD_VISITED(pinfo)) { |
554 | 0 | ctx = wmem_new(wmem_file_scope(), struct _fpp_ctx_t); |
555 | 0 | init_fpp_ctx(ctx, get_cont_by_start(smd2), crc); |
556 | 0 | ctx->size = frag_size; |
557 | 0 | conversation_add_proto_data(conv, proto_fpp, ctx); |
558 | 0 | } |
559 | |
|
560 | 0 | if (crc_val == CRC_CRC) { |
561 | | /* Non-fragmented packet |
562 | | end of continuation */ |
563 | 0 | drop_fragments(pinfo); |
564 | |
|
565 | 0 | if (conv && !PINFO_FD_VISITED(pinfo)) { |
566 | 0 | drop_conversation(conv); |
567 | 0 | } |
568 | |
|
569 | 0 | proto_tree_add_checksum(tree, tvb, crc_offset, hf_fpp_crc32, hf_fpp_crc32_status, &ei_fpp_crc32, pinfo, crc, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY); |
570 | |
|
571 | 0 | return tvb_new_subset_length(tvb, preamble_length, frag_size); |
572 | 0 | } |
573 | 0 | else if (crc_val == CRC_mCRC) { |
574 | | /* First fragment */ |
575 | 0 | drop_fragments(pinfo); |
576 | |
|
577 | 0 | frag_data = fragment_add_check(&fpp_reassembly_table, |
578 | 0 | tvb, preamble_length, pinfo, interface_id | packet_direction, NULL, |
579 | 0 | 0, frag_size, true); |
580 | |
|
581 | 0 | set_address_tvb(&pinfo->dl_dst, AT_ETHER, 6, tvb, 8); |
582 | 0 | set_address_tvb(&pinfo->dst, AT_ETHER, 6, tvb, 8); |
583 | 0 | set_address_tvb(&pinfo->dl_src, AT_ETHER, 6, tvb, 14); |
584 | 0 | set_address_tvb(&pinfo->src, AT_ETHER, 6, tvb, 14); |
585 | |
|
586 | 0 | proto_tree_add_checksum(tree, tvb, crc_offset, hf_fpp_mcrc32, hf_fpp_mcrc32_status, &ei_fpp_mcrc32, pinfo, mcrc, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY); |
587 | |
|
588 | 0 | if (frag_data != NULL) { |
589 | 0 | col_append_frame_number(pinfo, COL_INFO, " [Reassembled in #%u]", frag_data->reassembled_in); |
590 | 0 | process_reassembled_data(tvb, preamble_length, pinfo, |
591 | 0 | "Reassembled FPP", frag_data, &fpp_frag_items, |
592 | 0 | NULL, tree); |
593 | 0 | } |
594 | 0 | } else { |
595 | | /* Possibly first fragment */ |
596 | 0 | drop_fragments(pinfo); |
597 | 0 | proto_tree_add_checksum(tree, tvb, crc_offset, hf_fpp_mcrc32, hf_fpp_mcrc32_status, &ei_fpp_mcrc32, pinfo, mcrc, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY); |
598 | 0 | } |
599 | 2 | } else if (pck_type == FPP_Packet_Cont) { |
600 | 2 | if (crc_val == CRC_mCRC) { |
601 | | /* Continuation fragment */ |
602 | | /* Update data of this conversation */ |
603 | 0 | if (!PINFO_FD_VISITED(pinfo) && conv) { |
604 | 0 | ctx = (fpp_ctx_t*)conversation_get_proto_data(conv, proto_fpp); |
605 | 0 | if (ctx) { |
606 | 0 | fpp_pdata_t *fpp_pdata = wmem_new(wmem_file_scope(), fpp_pdata_t); |
607 | 0 | fpp_pdata->offset = ctx->size; |
608 | 0 | p_add_proto_data(wmem_file_scope(), pinfo, proto_fpp, interface_id | packet_direction, fpp_pdata); |
609 | |
|
610 | 0 | ctx->size += frag_size; |
611 | 0 | ctx->frag_cnt = smd2; |
612 | 0 | ctx->crc = crc; |
613 | 0 | } |
614 | 0 | } |
615 | |
|
616 | 0 | proto_tree_add_checksum(tree, tvb, crc_offset, hf_fpp_mcrc32, hf_fpp_mcrc32_status, &ei_fpp_mcrc32, pinfo, mcrc, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY); |
617 | |
|
618 | 0 | fpp_pdata_t *fpp_pdata = (fpp_pdata_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_fpp, interface_id | packet_direction); |
619 | 0 | if (fpp_pdata) { |
620 | 0 | frag_data = fragment_add_check(&fpp_reassembly_table, |
621 | 0 | tvb, preamble_length, pinfo, interface_id | packet_direction, NULL, |
622 | 0 | fpp_pdata->offset, frag_size, true); |
623 | 0 | if (frag_data != NULL) { |
624 | 0 | col_append_frame_number(pinfo, COL_INFO, " [Reassembled in #%u]", frag_data->reassembled_in); |
625 | 0 | process_reassembled_data(tvb, preamble_length, pinfo, |
626 | 0 | "Reassembled FPP", frag_data, &fpp_frag_items, |
627 | 0 | NULL, tree); |
628 | 0 | } |
629 | 0 | } else { |
630 | 0 | drop_fragments(pinfo); |
631 | 0 | } |
632 | 2 | } else if (crc_val == CRC_CRC) { |
633 | | /* Suppose that the last fragment dissected |
634 | | 1. preemption is active |
635 | | 2. check frame count and frag count values |
636 | | After these steps check crc of entire reassembled frame |
637 | | */ |
638 | 0 | if (conv) { |
639 | 0 | ctx = (fpp_ctx_t*)conversation_get_proto_data(conv, proto_fpp); |
640 | 0 | if ((ctx) && (ctx->preemption) && (ctx->frame_cnt == smd1) && (frag_cnt_next(ctx->frag_cnt) == smd2)) { |
641 | 0 | fpp_pdata_t *fpp_pdata = wmem_new(wmem_file_scope(), fpp_pdata_t); |
642 | 0 | if (!PINFO_FD_VISITED(pinfo)) { |
643 | 0 | fpp_pdata->offset = ctx->size; |
644 | 0 | p_add_proto_data(wmem_file_scope(), pinfo, proto_fpp, interface_id | packet_direction, fpp_pdata); |
645 | 0 | } |
646 | 0 | } |
647 | 0 | } |
648 | |
|
649 | 0 | fpp_pdata_t *fpp_pdata = (fpp_pdata_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_fpp, interface_id | packet_direction); |
650 | 0 | if (fpp_pdata) { |
651 | 0 | save_fragmented = pinfo->fragmented; |
652 | 0 | pinfo->fragmented = true; |
653 | 0 | frag_data = fragment_add_check(&fpp_reassembly_table, |
654 | 0 | tvb, preamble_length, pinfo, interface_id | packet_direction, NULL, |
655 | 0 | fpp_pdata->offset, frag_size, false); |
656 | | // Attempt reassembly. |
657 | 0 | new_tvb = process_reassembled_data(tvb, preamble_length, pinfo, |
658 | 0 | "Reassembled FPP", frag_data, &fpp_frag_items, |
659 | 0 | NULL, tree); |
660 | 0 | pinfo->fragmented = save_fragmented; |
661 | 0 | } else { |
662 | 0 | drop_fragments(pinfo); |
663 | 0 | proto_tree_add_checksum(tree, tvb, crc_offset, hf_fpp_mcrc32, hf_fpp_mcrc32_status, &ei_fpp_mcrc32, pinfo, mcrc, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY); |
664 | 0 | } |
665 | |
|
666 | 0 | if (new_tvb) { |
667 | | /* Reassembly was successful; return the completed datagram. */ |
668 | 0 | uint32_t reassembled_crc = GUINT32_SWAP_LE_BE(crc32_ccitt_tvb_offset(new_tvb, 0, tvb_reported_length(new_tvb))); |
669 | | |
670 | | /* Reassembly frame takes place regardless of whether the check sum was correct or not. */ |
671 | 0 | proto_tree_add_checksum(tree, tvb, crc_offset, hf_fpp_crc32, -1, &ei_fpp_crc32, pinfo, reassembled_crc, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY); |
672 | |
|
673 | 0 | return new_tvb; |
674 | 0 | } else { |
675 | | /* Reassembly was unsuccessful; show this fragment. This may |
676 | | just mean that we don't yet have all the fragments, so |
677 | | we should not just continue dissecting. */ |
678 | 0 | proto_tree_add_checksum(tree, tvb, crc_offset, hf_fpp_mcrc32, hf_fpp_mcrc32_status, &ei_fpp_mcrc32, pinfo, crc, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY); |
679 | 0 | return NULL; |
680 | 0 | } |
681 | 2 | } else { |
682 | | /* Invalid packet */ |
683 | 2 | if (!PINFO_FD_VISITED(pinfo) && conv) { |
684 | 0 | ctx = (fpp_ctx_t *)conversation_get_proto_data(conv, proto_fpp); |
685 | 0 | if (ctx) { |
686 | 0 | fpp_pdata_t *fpp_pdata = wmem_new(wmem_file_scope(), fpp_pdata_t); |
687 | 0 | fpp_pdata->offset = ctx->size; |
688 | 0 | p_add_proto_data(wmem_file_scope(), pinfo, proto_fpp, interface_id | packet_direction, fpp_pdata); |
689 | |
|
690 | 0 | ctx->size += frag_size; |
691 | 0 | ctx->frag_cnt = smd2; |
692 | 0 | ctx->crc = crc; |
693 | 0 | } |
694 | 0 | } |
695 | 2 | proto_tree_add_checksum(tree, tvb, crc_offset, hf_fpp_mcrc32, hf_fpp_mcrc32_status, &ei_fpp_mcrc32, pinfo, mcrc, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY); |
696 | 2 | } |
697 | | |
698 | 2 | } else if (pck_type == FPP_Packet_Verify) { |
699 | 0 | proto_tree_add_checksum(tree, tvb, crc_offset, hf_fpp_mcrc32, -1, &ei_fpp_mcrc32, pinfo, mcrc, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY); |
700 | 0 | } else if (pck_type == FPP_Packet_Response) { |
701 | 0 | proto_tree_add_checksum(tree, tvb, crc_offset, hf_fpp_mcrc32, hf_fpp_mcrc32_status, &ei_fpp_mcrc32, pinfo, mcrc, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY); |
702 | 0 | } |
703 | | |
704 | 2 | return NULL; |
705 | 2 | } |
706 | | |
707 | | static tvbuff_t * |
708 | 0 | dissect_express(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t crc, fpp_crc_t crc_val) { |
709 | |
|
710 | 0 | unsigned crc_offset = tvb_reported_length(tvb) - FPP_CRC_LENGTH; |
711 | 0 | unsigned offset = 0; |
712 | 0 | unsigned preamble_length = get_preamble_length( tvb ); |
713 | 0 | unsigned preamble_bit_length = preamble_length * 8; |
714 | 0 | bool preamble_unaligned = false; |
715 | 0 | unsigned pdu_data_len = tvb_reported_length(tvb) - preamble_length - FPP_CRC_LENGTH; |
716 | | |
717 | |
|
718 | 0 | proto_item *ti_preamble = proto_tree_add_item(tree, hf_fpp_preamble, tvb, offset, preamble_length, ENC_NA); |
719 | 0 | offset += preamble_length; |
720 | |
|
721 | 0 | if( 0x50 == tvb_get_uint8(tvb, 0) ) |
722 | 0 | { |
723 | | //First octet contains preamble alignment bits. |
724 | 0 | preamble_bit_length -= 4; |
725 | 0 | preamble_unaligned = true; |
726 | 0 | } |
727 | |
|
728 | 0 | if( preamble_bit_length == FPP_DEFAULT_PREAMBLE_LENGTH * 8 ) { |
729 | 0 | proto_item_append_text(ti_preamble, " [Preamble length: Normal]" ); |
730 | 0 | } else if( preamble_bit_length < FPP_DEFAULT_PREAMBLE_LENGTH * 8 ) { |
731 | 0 | proto_item_append_text(ti_preamble, " [Preamble length: Shortened by %d bits]", FPP_DEFAULT_PREAMBLE_LENGTH * 8 - preamble_bit_length ); |
732 | 0 | } else if( preamble_bit_length > FPP_DEFAULT_PREAMBLE_LENGTH * 8 ) { |
733 | 0 | proto_item_append_text(ti_preamble, " [Preamble length: Lengthened by %d bits]", preamble_bit_length - FPP_DEFAULT_PREAMBLE_LENGTH * 8 ); |
734 | 0 | } |
735 | | |
736 | |
|
737 | 0 | proto_tree_add_item(tree, hf_fpp_mdata, tvb, offset, pdu_data_len, ENC_NA); |
738 | |
|
739 | 0 | proto_tree *fpp_preamble_tree = proto_item_add_subtree(ti_preamble, ett_fpp_preamble); |
740 | |
|
741 | 0 | if( preamble_unaligned ) { |
742 | 0 | proto_tree_add_item(fpp_preamble_tree, hf_fpp_preamble_pad, tvb, 0, 1, ENC_BIG_ENDIAN); |
743 | 0 | } |
744 | 0 | proto_item *ti_smd = proto_tree_add_item(fpp_preamble_tree, hf_fpp_preamble_smd, tvb, preamble_length - 1, 1, ENC_BIG_ENDIAN); |
745 | 0 | proto_item_append_text(ti_smd, " [SMD-E]" ); |
746 | |
|
747 | 0 | proto_tree_add_checksum(tree, tvb, crc_offset, hf_fpp_crc32, hf_fpp_crc32_status, &ei_fpp_crc32, pinfo, crc, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY); |
748 | |
|
749 | 0 | if (crc_val == CRC_CRC) { |
750 | 0 | return tvb_new_subset_length(tvb, preamble_length, pdu_data_len); |
751 | 0 | } |
752 | 0 | return NULL; |
753 | 0 | } |
754 | | |
755 | | static int |
756 | | dissect_fpp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
757 | 3 | { |
758 | 3 | uint32_t express_crc; |
759 | 3 | fpp_crc_t crc_val; |
760 | 3 | tvbuff_t *next = tvb; |
761 | 3 | unsigned preamble_length = get_preamble_length( tvb ); |
762 | 3 | unsigned pdu_data_len = tvb_reported_length(tvb) - preamble_length - FPP_CRC_LENGTH; |
763 | | |
764 | 3 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "FPP"); |
765 | 3 | col_clear(pinfo->cinfo,COL_INFO); |
766 | | |
767 | 3 | proto_item *ti = proto_tree_add_item(tree, proto_fpp, tvb, 0, -1, ENC_NA); |
768 | | |
769 | 3 | proto_tree *fpp_tree = proto_item_add_subtree(ti, ett_fpp); |
770 | | |
771 | 3 | switch (get_packet_type(tvb)) { |
772 | 0 | case FPP_Packet_Expess: |
773 | | /* this is the old crc calculation which is only valid for express frames */ |
774 | 0 | express_crc = GUINT32_SWAP_LE_BE(crc32_ccitt_tvb_offset(tvb, preamble_length, pdu_data_len)); |
775 | | |
776 | | /* is express_crc valid */ |
777 | 0 | crc_val = get_express_crc_stat(tvb, express_crc); |
778 | | |
779 | | /* fill column Info */ |
780 | 0 | col_fstr_process(tvb, pinfo, crc_val); |
781 | |
|
782 | 0 | next = dissect_express(tvb, pinfo, fpp_tree, express_crc, crc_val); |
783 | 0 | break; |
784 | 0 | case FPP_Packet_Init: |
785 | 2 | case FPP_Packet_Cont: |
786 | 2 | case FPP_Packet_Verify: |
787 | 2 | case FPP_Packet_Response: |
788 | 2 | next = dissect_preemption(tvb, pinfo, fpp_tree); |
789 | 2 | break; |
790 | 1 | default: |
791 | 1 | break; |
792 | 3 | } |
793 | | |
794 | 3 | if (next) { |
795 | 1 | call_dissector(ethl2_handle, next, pinfo, tree); |
796 | 2 | } else { |
797 | 2 | tvbuff_t *new_tvb = tvb_new_subset_length(tvb, preamble_length, pdu_data_len); |
798 | 2 | call_data_dissector(new_tvb, pinfo, tree); |
799 | 2 | } |
800 | 3 | return tvb_captured_length(tvb); |
801 | 3 | } |
802 | | |
803 | | void |
804 | | proto_register_fpp(void) |
805 | 14 | { |
806 | 14 | static hf_register_info hf[] = { |
807 | 14 | { &hf_fpp_preamble, |
808 | 14 | { "Preamble", "fpp.preamble", |
809 | 14 | FT_BYTES, BASE_NONE, |
810 | 14 | NULL, 0x0, |
811 | 14 | NULL, HFILL } |
812 | 14 | }, |
813 | 14 | { &hf_fpp_preamble_pad, |
814 | 14 | { "Alignment padding, not part of frame", "fpp.preamble.pad", |
815 | 14 | FT_UINT8, BASE_HEX, |
816 | 14 | NULL, 0x0F, |
817 | 14 | NULL, HFILL } |
818 | 14 | }, |
819 | 14 | { &hf_fpp_preamble_smd, |
820 | 14 | { "SMD", "fpp.preamble.smd", |
821 | 14 | FT_UINT8, BASE_HEX, |
822 | 14 | NULL, 0x0, |
823 | 14 | NULL, HFILL } |
824 | 14 | }, |
825 | 14 | { &hf_fpp_preamble_frag_count, |
826 | 14 | { "Fragment count", "fpp.preamble.frag_count", |
827 | 14 | FT_UINT8, BASE_HEX, |
828 | 14 | NULL, 0x0, |
829 | 14 | NULL, HFILL } |
830 | 14 | }, |
831 | 14 | { &hf_fpp_mdata, |
832 | 14 | { "mData", "fpp.mdata", |
833 | 14 | FT_BYTES, BASE_NONE, |
834 | 14 | NULL, 0x0, |
835 | 14 | NULL, HFILL } |
836 | 14 | }, |
837 | 14 | { &hf_fpp_crc32, |
838 | 14 | { "CRC", "fpp.crc32", |
839 | 14 | FT_UINT32, BASE_HEX, |
840 | 14 | NULL, 0x0, |
841 | 14 | NULL, HFILL } |
842 | 14 | }, |
843 | 14 | { &hf_fpp_crc32_status, |
844 | 14 | { "Checksum Status", "fpp.checksum.status", |
845 | 14 | FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0, |
846 | 14 | NULL, HFILL |
847 | 14 | }, |
848 | 14 | }, |
849 | 14 | { &hf_fpp_mcrc32, |
850 | 14 | { "mCRC", "fpp.mcrc32", |
851 | 14 | FT_UINT32, BASE_HEX, |
852 | 14 | NULL, 0x0, |
853 | 14 | NULL, HFILL } |
854 | 14 | }, |
855 | 14 | { &hf_fpp_mcrc32_status, |
856 | 14 | { "Checksum Status", "fpp.checksum.status", |
857 | 14 | FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0, |
858 | 14 | NULL, HFILL |
859 | 14 | }, |
860 | 14 | }, |
861 | | |
862 | | /* Reassembly fields. */ |
863 | 14 | { &hf_fpp_fragments, |
864 | 14 | { "Message fragments", "fpp.fragments", |
865 | 14 | FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }}, |
866 | 14 | { &hf_fpp_fragment, |
867 | 14 | { "Message fragment", "fpp.fragment", |
868 | 14 | FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL }}, |
869 | 14 | { &hf_fpp_fragment_overlap, |
870 | 14 | { "Message fragment overlap", "fpp.fragment.overlap", |
871 | 14 | FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }}, |
872 | 14 | { &hf_fpp_fragment_overlap_conflicts, |
873 | 14 | { "Message fragment overlapping with conflicting data", "fpp.fragment.overlap.conflicts", |
874 | 14 | FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }}, |
875 | 14 | { &hf_fpp_fragment_multiple_tails, |
876 | 14 | { "Message has multiple tail fragments", "fpp.fragment.multiple_tails", |
877 | 14 | FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }}, |
878 | 14 | { &hf_fpp_fragment_too_long_fragment, |
879 | 14 | { "Message fragment too long", "fpp.fragment.too_long_fragment", |
880 | 14 | FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }}, |
881 | 14 | { &hf_fpp_fragment_error, |
882 | 14 | { "Message defragmentation error", "fpp.fragment.error", |
883 | 14 | FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL }}, |
884 | 14 | { &hf_fpp_fragment_count, |
885 | 14 | { "Message fragment count", "fpp.fragment.count", |
886 | 14 | FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }}, |
887 | 14 | { &hf_fpp_reassembled_in, |
888 | 14 | { "Reassembled in", "fpp.reassembled.in", |
889 | 14 | FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL }}, |
890 | 14 | { &hf_fpp_reassembled_length, |
891 | 14 | { "Reassembled fpp length", "fpp.reassembled.length", |
892 | 14 | FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }}, |
893 | 14 | }; |
894 | | |
895 | | /* Setup protocol subtree array */ |
896 | 14 | static int *ett[] = { |
897 | 14 | &ett_fpp, |
898 | 14 | &ett_fpp_preamble, |
899 | | /* Reassembly subtrees. */ |
900 | 14 | &ett_fpp_fragment, |
901 | 14 | &ett_fpp_fragments |
902 | 14 | }; |
903 | | |
904 | 14 | static ei_register_info ei[] = { |
905 | 14 | { &ei_fpp_mcrc32, |
906 | 14 | { "fpp.mcrc32_bad", PI_CHECKSUM, PI_ERROR, |
907 | 14 | "Bad mCRC checksum", EXPFILL } |
908 | 14 | }, |
909 | 14 | { &ei_fpp_crc32, |
910 | 14 | { "fpp.crc32_bad", PI_CHECKSUM, PI_ERROR, |
911 | 14 | "Bad CRC checksum", EXPFILL } |
912 | 14 | }, |
913 | 14 | }; |
914 | | |
915 | 14 | expert_module_t* expert_fpp; |
916 | | |
917 | 14 | proto_fpp = proto_register_protocol ("IEEE 802.3br Frame Preemption Protocol", "Frame Preemption Protocol", "fpp"); |
918 | | |
919 | 14 | proto_register_field_array(proto_fpp, hf, array_length(hf)); |
920 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
921 | 14 | expert_fpp = expert_register_protocol(proto_fpp); |
922 | 14 | expert_register_field_array(expert_fpp, ei, array_length(ei)); |
923 | | |
924 | 14 | reassembly_table_register(&fpp_reassembly_table, &addresses_reassembly_table_functions); |
925 | | |
926 | 14 | fpp_handle = register_dissector("fpp", dissect_fpp, proto_fpp); |
927 | 14 | } |
928 | | |
929 | | void |
930 | | proto_reg_handoff_fpp(void) |
931 | 14 | { |
932 | 14 | dissector_add_uint("wtap_encap", WTAP_ENCAP_ETHERNET_MPACKET, fpp_handle); |
933 | | |
934 | 14 | ethl2_handle = find_dissector_add_dependency("eth_withoutfcs", proto_fpp); |
935 | 14 | } |
936 | | |
937 | | /* |
938 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
939 | | * |
940 | | * Local variables: |
941 | | * c-basic-offset: 4 |
942 | | * tab-width: 8 |
943 | | * indent-tabs-mode: nil |
944 | | * End: |
945 | | * |
946 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
947 | | * :indentSize=4:tabSize=8:noTabs=false: |
948 | | */ |