2 * Routines for IEEE 802.3br Frame Preemption Protocol packet disassembly
4 * Copyright 2017, Anton Glukhov <anton.a.glukhov@gmail.com>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include <epan/packet.h>
16 #include <wiretap/wtap.h>
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>
25 void proto_register_fpp(void);
26 void proto_reg_handoff_fpp(void);
30 static dissector_handle_t fpp_handle
;
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
;
42 static expert_field ei_fpp_crc32
;
43 static expert_field ei_fpp_mcrc32
;
46 static int ett_fpp_preamble
;
48 static reassembly_table fpp_reassembly_table
;
50 static dissector_handle_t ethl2_handle
;
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
;
66 static const fragment_items fpp_frag_items
= {
67 /* Fragment subtrees */
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 */
89 #define FPP_DEFAULT_PREAMBLE_LENGTH 8
90 #define FPP_CRC_LENGTH 4
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
117 SMD_PP_ContFrag_0
= 0x61,
118 SMD_PP_ContFrag_1
= 0x52,
119 SMD_PP_ContFrag_2
= 0x9e,
120 SMD_PP_ContFrag_3
= 0x2a,
130 PACKET_DIRECTION_INBOUND
= 0x1,
131 PACKET_DIRECTION_OUTBOUND
= 0x2,
132 PACKET_DIRECTION_UNKNOWN
= 0x0,
133 } packet_direction_enum
;
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]" },
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]" },
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]" },
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]" },
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]"},
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]" },
194 get_preamble_length(tvbuff_t
*tvb
) {
198 if( 0x50 == tvb_get_uint8(tvb
, offset
) )
200 //First octet contains preamble alignment bits. Ignore it.
204 while( tvb_get_uint8(tvb
, offset
) == Octet_0x55
&& ( offset
+ 2 < tvb_reported_length(tvb
) ) )
209 uint8_t smd1
= tvb_get_uint8(tvb
, offset
);
220 case SMD_PP_ContFrag_0
:
221 case SMD_PP_ContFrag_1
:
222 case SMD_PP_ContFrag_2
:
223 case SMD_PP_ContFrag_3
:
226 return FPP_DEFAULT_PREAMBLE_LENGTH
;
231 get_crc_stat(tvbuff_t
*tvb
, uint32_t crc
, uint32_t mcrc
) {
233 uint32_t received_crc
= tvb_get_uint32(tvb
, tvb_reported_length(tvb
) - FPP_CRC_LENGTH
, ENC_BIG_ENDIAN
);
235 if (received_crc
== crc
) {
237 } else if (received_crc
== mcrc
) {
246 get_express_crc_stat(tvbuff_t
*tvb
, uint32_t express_crc
) {
248 uint32_t received_crc
= tvb_get_uint32(tvb
, tvb_reported_length(tvb
) - FPP_CRC_LENGTH
, ENC_BIG_ENDIAN
);
250 if (received_crc
== express_crc
) {
259 get_packet_type(tvbuff_t
*tvb
) {
260 /* function analyze a packet based on preamble and ignore crc */
264 if( 0x50 == tvb_get_uint8(tvb
, offset
) )
266 //First octet contains preamble alignment bits. Ignore it.
270 while( tvb_get_uint8(tvb
, offset
) == Octet_0x55
&& ( offset
+ 2 < tvb_reported_length(tvb
) ) )
275 uint8_t smd1
= tvb_get_uint8(tvb
, offset
);
276 uint8_t smd2
= tvb_get_uint8(tvb
, offset
+ 1);
283 return FPP_Packet_Init
;
285 return FPP_Packet_Verify
;
287 return FPP_Packet_Response
;
289 return FPP_Packet_Expess
;
290 case SMD_PP_ContFrag_0
:
291 case SMD_PP_ContFrag_1
:
292 case SMD_PP_ContFrag_2
:
293 case SMD_PP_ContFrag_3
:
299 return FPP_Packet_Cont
;
301 return FPP_Packet_Invalid
;
304 return FPP_Packet_Invalid
;
307 return FPP_Packet_Invalid
;
311 col_fstr_process(tvbuff_t
*tvb
, packet_info
*pinfo
, fpp_crc_t crc_val
) {
312 unsigned preamble_length
= get_preamble_length( tvb
);
314 switch( get_packet_type(tvb
) ) {
315 case FPP_Packet_Expess
:
316 col_set_str(pinfo
->cinfo
, COL_INFO
, "[Express]");
318 case FPP_Packet_Verify
:
319 col_set_str(pinfo
->cinfo
, COL_INFO
, "[Verify]");
321 case FPP_Packet_Response
:
322 col_set_str(pinfo
->cinfo
, COL_INFO
, "[Respond]");
324 case FPP_Packet_Init
:
325 if (crc_val
== CRC_CRC
)
326 col_add_str(pinfo
->cinfo
, COL_INFO
, try_val_to_str(tvb_get_uint8(tvb
, preamble_length
-1), preemptive_delim_desc
));
327 else if (crc_val
== CRC_mCRC
)
328 col_add_str(pinfo
->cinfo
, COL_INFO
, try_val_to_str(tvb_get_uint8(tvb
, preamble_length
-1), initial_delim_desc
));
330 col_add_str(pinfo
->cinfo
, COL_INFO
, try_val_to_str(tvb_get_uint8(tvb
, preamble_length
-1), corrupted_delim_desc
));
332 case FPP_Packet_Cont
:
333 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s %s", try_val_to_str(tvb_get_uint8(tvb
, preamble_length
-2), continuation_delim_desc
),
334 try_val_to_str(tvb_get_uint8(tvb
, preamble_length
-1), frag_count_delim_desc
));
347 wmem_map_t
*crc_history
;
350 typedef struct _fpp_ctx_t fpp_ctx_t
;
352 static packet_direction_enum
353 get_packet_direction(packet_info
*pinfo
) {
354 switch (pinfo
->p2p_dir
) {
356 return PACKET_DIRECTION_INBOUND
;
358 return PACKET_DIRECTION_OUTBOUND
;
360 return PACKET_DIRECTION_UNKNOWN
;
365 init_fpp_ctx(struct _fpp_ctx_t
*ctx
, uint8_t frame_cnt
, uint32_t crc
) {
366 ctx
->preemption
= true;
367 ctx
->frame_cnt
= frame_cnt
;
368 ctx
->frag_cnt
= FragCount_3
;
371 ctx
->crc_history
= wmem_map_new(wmem_epan_scope(), g_int_hash
, g_int_equal
);
375 frag_cnt_next(uint8_t cur_num
) {
390 get_cont_by_start(uint8_t start_cnt
) {
391 if (start_cnt
== SMD_PP_Start_0
)
392 return SMD_PP_ContFrag_0
;
393 else if (start_cnt
== SMD_PP_Start_1
)
394 return SMD_PP_ContFrag_1
;
395 else if (start_cnt
== SMD_PP_Start_2
)
396 return SMD_PP_ContFrag_2
;
397 else if (start_cnt
== SMD_PP_Start_3
)
398 return SMD_PP_ContFrag_3
;
400 return SMD_PP_ContFrag_0
;
403 struct _fpp_pdata_t
{
404 /* struct for future possible usage */
408 typedef struct _fpp_pdata_t fpp_pdata_t
;
411 drop_conversation(conversation_t
*conv
) {
413 ctx
= (fpp_ctx_t
*)conversation_get_proto_data(conv
, proto_fpp
);
415 wmem_free(wmem_file_scope(), ctx
);
417 conversation_delete_proto_data(conv
, proto_fpp
);
421 drop_fragments(packet_info
*pinfo
) {
423 unsigned interface_id
;
424 packet_direction_enum packet_direction
= get_packet_direction(pinfo
);
426 if (pinfo
->rec
->presence_flags
& WTAP_HAS_INTERFACE_ID
)
427 interface_id
= pinfo
->rec
->rec_header
.packet_header
.interface_id
;
430 interface_id
= interface_id
<< 0x2;
431 tvbuf
= fragment_delete(&fpp_reassembly_table
, pinfo
, interface_id
| packet_direction
, NULL
);
439 dissect_preemption(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
) {
440 fpp_packet_t pck_type
;
442 unsigned preamble_length
= get_preamble_length( tvb
);
443 unsigned preamble_bit_length
= preamble_length
* 8;
444 bool preamble_unaligned
= false;
446 uint8_t smd1
= tvb_get_uint8(tvb
, preamble_length
- 2);
447 uint8_t smd2
= tvb_get_uint8(tvb
, preamble_length
- 1);
449 unsigned crc_offset
= tvb_reported_length(tvb
) - FPP_CRC_LENGTH
;
450 int frag_size
= tvb_reported_length(tvb
) - preamble_length
- FPP_CRC_LENGTH
;
452 /* Reassembly parameters. */
453 tvbuff_t
*new_tvb
= NULL
;
454 fragment_head
*frag_data
;
455 bool save_fragmented
;
456 conversation_t
*conv
;
458 unsigned interface_id
;
459 packet_direction_enum packet_direction
= get_packet_direction(pinfo
);
462 /* mCRC calculations needs previous crc */
463 uint32_t crc
, mcrc
, prev_crc
;
465 if (pinfo
->rec
->presence_flags
& WTAP_HAS_INTERFACE_ID
)
466 interface_id
= pinfo
->rec
->rec_header
.packet_header
.interface_id
;
469 interface_id
= interface_id
<< 0x2;
471 /* Create a tree for the preamble. */
472 proto_item
*ti_preamble
= proto_tree_add_item(tree
, hf_fpp_preamble
, tvb
, 0, preamble_length
, ENC_NA
);
474 if( 0x50 == tvb_get_uint8(tvb
, 0) )
476 //First octet contains preamble alignment bits.
477 preamble_bit_length
-= 4;
478 preamble_unaligned
= true;
481 if( preamble_bit_length
== FPP_DEFAULT_PREAMBLE_LENGTH
* 8 ) {
482 proto_item_append_text(ti_preamble
, " [Preamble length: Normal]" );
483 } else if( preamble_bit_length
< FPP_DEFAULT_PREAMBLE_LENGTH
* 8 ) {
484 proto_item_append_text(ti_preamble
, " [Preamble length: Shortened by %d bits]", FPP_DEFAULT_PREAMBLE_LENGTH
* 8 - preamble_bit_length
);
485 } else if( preamble_bit_length
> FPP_DEFAULT_PREAMBLE_LENGTH
* 8 ) {
486 proto_item_append_text(ti_preamble
, " [Preamble length: Lengthened by %d bits]", preamble_bit_length
- FPP_DEFAULT_PREAMBLE_LENGTH
* 8 );
489 proto_tree_add_item(tree
, hf_fpp_mdata
, tvb
, preamble_length
, frag_size
, ENC_NA
);
491 proto_tree
*fpp_preamble_tree
= proto_item_add_subtree(ti_preamble
, ett_fpp_preamble
);
493 if( preamble_unaligned
) {
494 proto_tree_add_item(fpp_preamble_tree
, hf_fpp_preamble_pad
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
497 pck_type
= get_packet_type(tvb
);
499 if(pck_type
== FPP_Packet_Cont
)
501 proto_item
*ti_smd
= proto_tree_add_item(fpp_preamble_tree
, hf_fpp_preamble_smd
, tvb
, preamble_length
- 2, 1, ENC_BIG_ENDIAN
);
502 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 proto_item_append_text(ti_smd
, " %s", try_val_to_str(tvb_get_uint8(tvb
, preamble_length
-2), delim_desc
) );
504 proto_item_append_text(ti_fragcnt
, " %s", try_val_to_str(tvb_get_uint8(tvb
, preamble_length
-1), frag_count_delim_desc
) );
508 proto_item
*ti_smd
= proto_tree_add_item(fpp_preamble_tree
, hf_fpp_preamble_smd
, tvb
, preamble_length
- 1, 1, ENC_BIG_ENDIAN
);
509 proto_item_append_text(ti_smd
, " %s", try_val_to_str(tvb_get_uint8(tvb
, preamble_length
-1), delim_desc
) );
513 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 if (pck_type
== FPP_Packet_Init
) {
517 /* will be used for seeding the crc calculation */
518 if (!PINFO_FD_VISITED(pinfo
)) {
519 conv
= conversation_new_by_id(pinfo
->num
, CONVERSATION_NONE
, interface_id
| packet_direction
);
520 /* XXX Is this needed? */
521 find_conversation_pinfo(pinfo
, 0);
524 else if (pck_type
== FPP_Packet_Cont
&& conv
) {
525 ctx
= (fpp_ctx_t
*)conversation_get_proto_data(conv
, proto_fpp
);
527 if (!PINFO_FD_VISITED(pinfo
)) {
528 if ((ctx
->preemption
) && (ctx
->frame_cnt
== smd1
) && (frag_cnt_next(ctx
->frag_cnt
) == smd2
)) {
531 /* create a copy of frame number and previous crc and store in crc_history */
532 uint32_t *copy_of_pinfo_num
= wmem_new(wmem_epan_scope(), uint32_t);
533 uint32_t *copy_of_prev_crc
= wmem_new(wmem_epan_scope(), uint32_t);
534 *copy_of_pinfo_num
= pinfo
->num
;
535 *copy_of_prev_crc
= prev_crc
;
536 wmem_map_insert(ctx
->crc_history
, copy_of_pinfo_num
, copy_of_prev_crc
);
539 prev_crc
= *(uint32_t *)wmem_map_lookup(ctx
->crc_history
, &pinfo
->num
);
544 crc
= GUINT32_SWAP_LE_BE(crc32_ccitt_tvb_offset_seed(tvb
, preamble_length
, frag_size
, GUINT32_SWAP_LE_BE(prev_crc
) ^ 0xffffffff));
545 mcrc
= crc
^ 0xffff0000;
546 crc_val
= get_crc_stat(tvb
, crc
, mcrc
); /* might be crc if last part or mcrc if continuation */
548 /* fill column Info */
549 col_fstr_process(tvb
, pinfo
, crc_val
);
551 if (pck_type
== FPP_Packet_Init
) {
552 /* Add data to this new conversation during first iteration*/
553 if (conv
&& !PINFO_FD_VISITED(pinfo
)) {
554 ctx
= wmem_new(wmem_file_scope(), struct _fpp_ctx_t
);
555 init_fpp_ctx(ctx
, get_cont_by_start(smd2
), crc
);
556 ctx
->size
= frag_size
;
557 conversation_add_proto_data(conv
, proto_fpp
, ctx
);
560 if (crc_val
== CRC_CRC
) {
561 /* Non-fragmented packet
562 end of continuation */
563 drop_fragments(pinfo
);
565 if (conv
&& !PINFO_FD_VISITED(pinfo
)) {
566 drop_conversation(conv
);
569 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
);
571 return tvb_new_subset_length(tvb
, preamble_length
, frag_size
);
573 else if (crc_val
== CRC_mCRC
) {
575 drop_fragments(pinfo
);
577 frag_data
= fragment_add_check(&fpp_reassembly_table
,
578 tvb
, preamble_length
, pinfo
, interface_id
| packet_direction
, NULL
,
581 set_address_tvb(&pinfo
->dl_dst
, AT_ETHER
, 6, tvb
, 8);
582 set_address_tvb(&pinfo
->dst
, AT_ETHER
, 6, tvb
, 8);
583 set_address_tvb(&pinfo
->dl_src
, AT_ETHER
, 6, tvb
, 14);
584 set_address_tvb(&pinfo
->src
, AT_ETHER
, 6, tvb
, 14);
586 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
);
588 if (frag_data
!= NULL
) {
589 col_append_frame_number(pinfo
, COL_INFO
, " [Reassembled in #%u]", frag_data
->reassembled_in
);
590 process_reassembled_data(tvb
, preamble_length
, pinfo
,
591 "Reassembled FPP", frag_data
, &fpp_frag_items
,
595 /* Possibly first fragment */
596 drop_fragments(pinfo
);
597 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
);
599 } else if (pck_type
== FPP_Packet_Cont
) {
600 if (crc_val
== CRC_mCRC
) {
601 /* Continuation fragment */
602 /* Update data of this conversation */
603 if (!PINFO_FD_VISITED(pinfo
) && conv
) {
604 ctx
= (fpp_ctx_t
*)conversation_get_proto_data(conv
, proto_fpp
);
606 fpp_pdata_t
*fpp_pdata
= wmem_new(wmem_file_scope(), fpp_pdata_t
);
607 fpp_pdata
->offset
= ctx
->size
;
608 p_add_proto_data(wmem_file_scope(), pinfo
, proto_fpp
, interface_id
| packet_direction
, fpp_pdata
);
610 ctx
->size
+= frag_size
;
611 ctx
->frag_cnt
= smd2
;
616 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
);
618 fpp_pdata_t
*fpp_pdata
= (fpp_pdata_t
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_fpp
, interface_id
| packet_direction
);
620 frag_data
= fragment_add_check(&fpp_reassembly_table
,
621 tvb
, preamble_length
, pinfo
, interface_id
| packet_direction
, NULL
,
622 fpp_pdata
->offset
, frag_size
, true);
623 if (frag_data
!= NULL
) {
624 col_append_frame_number(pinfo
, COL_INFO
, " [Reassembled in #%u]", frag_data
->reassembled_in
);
625 process_reassembled_data(tvb
, preamble_length
, pinfo
,
626 "Reassembled FPP", frag_data
, &fpp_frag_items
,
630 drop_fragments(pinfo
);
632 } 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
639 ctx
= (fpp_ctx_t
*)conversation_get_proto_data(conv
, proto_fpp
);
640 if ((ctx
) && (ctx
->preemption
) && (ctx
->frame_cnt
== smd1
) && (frag_cnt_next(ctx
->frag_cnt
) == smd2
)) {
641 fpp_pdata_t
*fpp_pdata
= wmem_new(wmem_file_scope(), fpp_pdata_t
);
642 if (!PINFO_FD_VISITED(pinfo
)) {
643 fpp_pdata
->offset
= ctx
->size
;
644 p_add_proto_data(wmem_file_scope(), pinfo
, proto_fpp
, interface_id
| packet_direction
, fpp_pdata
);
649 fpp_pdata_t
*fpp_pdata
= (fpp_pdata_t
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_fpp
, interface_id
| packet_direction
);
651 save_fragmented
= pinfo
->fragmented
;
652 pinfo
->fragmented
= true;
653 frag_data
= fragment_add_check(&fpp_reassembly_table
,
654 tvb
, preamble_length
, pinfo
, interface_id
| packet_direction
, NULL
,
655 fpp_pdata
->offset
, frag_size
, false);
656 // Attempt reassembly.
657 new_tvb
= process_reassembled_data(tvb
, preamble_length
, pinfo
,
658 "Reassembled FPP", frag_data
, &fpp_frag_items
,
660 pinfo
->fragmented
= save_fragmented
;
662 drop_fragments(pinfo
);
663 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
);
667 /* Reassembly was successful; return the completed datagram. */
668 uint32_t reassembled_crc
= GUINT32_SWAP_LE_BE(crc32_ccitt_tvb_offset(new_tvb
, 0, tvb_reported_length(new_tvb
)));
670 /* Reassembly frame takes place regardless of whether the check sum was correct or not. */
671 proto_tree_add_checksum(tree
, tvb
, crc_offset
, hf_fpp_crc32
, -1, &ei_fpp_crc32
, pinfo
, reassembled_crc
, ENC_BIG_ENDIAN
, PROTO_CHECKSUM_VERIFY
);
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 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
);
683 if (!PINFO_FD_VISITED(pinfo
) && conv
) {
684 ctx
= (fpp_ctx_t
*)conversation_get_proto_data(conv
, proto_fpp
);
686 fpp_pdata_t
*fpp_pdata
= wmem_new(wmem_file_scope(), fpp_pdata_t
);
687 fpp_pdata
->offset
= ctx
->size
;
688 p_add_proto_data(wmem_file_scope(), pinfo
, proto_fpp
, interface_id
| packet_direction
, fpp_pdata
);
690 ctx
->size
+= frag_size
;
691 ctx
->frag_cnt
= smd2
;
695 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
);
698 } else if (pck_type
== FPP_Packet_Verify
) {
699 proto_tree_add_checksum(tree
, tvb
, crc_offset
, hf_fpp_mcrc32
, -1, &ei_fpp_mcrc32
, pinfo
, mcrc
, ENC_BIG_ENDIAN
, PROTO_CHECKSUM_VERIFY
);
700 } else if (pck_type
== FPP_Packet_Response
) {
701 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
);
708 dissect_express(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, uint32_t crc
, fpp_crc_t crc_val
) {
710 unsigned crc_offset
= tvb_reported_length(tvb
) - FPP_CRC_LENGTH
;
712 unsigned preamble_length
= get_preamble_length( tvb
);
713 unsigned preamble_bit_length
= preamble_length
* 8;
714 bool preamble_unaligned
= false;
715 unsigned pdu_data_len
= tvb_reported_length(tvb
) - preamble_length
- FPP_CRC_LENGTH
;
718 proto_item
*ti_preamble
= proto_tree_add_item(tree
, hf_fpp_preamble
, tvb
, offset
, preamble_length
, ENC_NA
);
719 offset
+= preamble_length
;
721 if( 0x50 == tvb_get_uint8(tvb
, 0) )
723 //First octet contains preamble alignment bits.
724 preamble_bit_length
-= 4;
725 preamble_unaligned
= true;
728 if( preamble_bit_length
== FPP_DEFAULT_PREAMBLE_LENGTH
* 8 ) {
729 proto_item_append_text(ti_preamble
, " [Preamble length: Normal]" );
730 } else if( preamble_bit_length
< FPP_DEFAULT_PREAMBLE_LENGTH
* 8 ) {
731 proto_item_append_text(ti_preamble
, " [Preamble length: Shortened by %d bits]", FPP_DEFAULT_PREAMBLE_LENGTH
* 8 - preamble_bit_length
);
732 } else if( preamble_bit_length
> FPP_DEFAULT_PREAMBLE_LENGTH
* 8 ) {
733 proto_item_append_text(ti_preamble
, " [Preamble length: Lengthened by %d bits]", preamble_bit_length
- FPP_DEFAULT_PREAMBLE_LENGTH
* 8 );
737 proto_tree_add_item(tree
, hf_fpp_mdata
, tvb
, offset
, pdu_data_len
, ENC_NA
);
739 proto_tree
*fpp_preamble_tree
= proto_item_add_subtree(ti_preamble
, ett_fpp_preamble
);
741 if( preamble_unaligned
) {
742 proto_tree_add_item(fpp_preamble_tree
, hf_fpp_preamble_pad
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
744 proto_item
*ti_smd
= proto_tree_add_item(fpp_preamble_tree
, hf_fpp_preamble_smd
, tvb
, preamble_length
- 1, 1, ENC_BIG_ENDIAN
);
745 proto_item_append_text(ti_smd
, " [SMD-E]" );
747 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
);
749 if (crc_val
== CRC_CRC
) {
750 return tvb_new_subset_length(tvb
, preamble_length
, pdu_data_len
);
756 dissect_fpp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
758 uint32_t express_crc
;
760 tvbuff_t
*next
= tvb
;
761 unsigned preamble_length
= get_preamble_length( tvb
);
762 unsigned pdu_data_len
= tvb_reported_length(tvb
) - preamble_length
- FPP_CRC_LENGTH
;
764 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "FPP");
765 col_clear(pinfo
->cinfo
,COL_INFO
);
767 proto_item
*ti
= proto_tree_add_item(tree
, proto_fpp
, tvb
, 0, -1, ENC_NA
);
769 proto_tree
*fpp_tree
= proto_item_add_subtree(ti
, ett_fpp
);
771 switch (get_packet_type(tvb
)) {
772 case FPP_Packet_Expess
:
773 /* this is the old crc calculation which is only valid for express frames */
774 express_crc
= GUINT32_SWAP_LE_BE(crc32_ccitt_tvb_offset(tvb
, preamble_length
, pdu_data_len
));
776 /* is express_crc valid */
777 crc_val
= get_express_crc_stat(tvb
, express_crc
);
779 /* fill column Info */
780 col_fstr_process(tvb
, pinfo
, crc_val
);
782 next
= dissect_express(tvb
, pinfo
, fpp_tree
, express_crc
, crc_val
);
784 case FPP_Packet_Init
:
785 case FPP_Packet_Cont
:
786 case FPP_Packet_Verify
:
787 case FPP_Packet_Response
:
788 next
= dissect_preemption(tvb
, pinfo
, fpp_tree
);
795 call_dissector(ethl2_handle
, next
, pinfo
, tree
);
797 tvbuff_t
*new_tvb
= tvb_new_subset_length(tvb
, preamble_length
, pdu_data_len
);
798 call_data_dissector(new_tvb
, pinfo
, tree
);
800 return tvb_captured_length(tvb
);
804 proto_register_fpp(void)
806 static hf_register_info hf
[] = {
808 { "Preamble", "fpp.preamble",
813 { &hf_fpp_preamble_pad
,
814 { "Alignment padding, not part of frame", "fpp.preamble.pad",
819 { &hf_fpp_preamble_smd
,
820 { "SMD", "fpp.preamble.smd",
825 { &hf_fpp_preamble_frag_count
,
826 { "Fragment count", "fpp.preamble.frag_count",
832 { "mData", "fpp.mdata",
838 { "CRC", "fpp.crc32",
843 { &hf_fpp_crc32_status
,
844 { "Checksum Status", "fpp.checksum.status",
845 FT_UINT8
, BASE_NONE
, VALS(proto_checksum_vals
), 0x0,
850 { "mCRC", "fpp.mcrc32",
855 { &hf_fpp_mcrc32_status
,
856 { "Checksum Status", "fpp.checksum.status",
857 FT_UINT8
, BASE_NONE
, VALS(proto_checksum_vals
), 0x0,
862 /* Reassembly fields. */
864 { "Message fragments", "fpp.fragments",
865 FT_NONE
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}},
867 { "Message fragment", "fpp.fragment",
868 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}},
869 { &hf_fpp_fragment_overlap
,
870 { "Message fragment overlap", "fpp.fragment.overlap",
871 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}},
872 { &hf_fpp_fragment_overlap_conflicts
,
873 { "Message fragment overlapping with conflicting data", "fpp.fragment.overlap.conflicts",
874 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}},
875 { &hf_fpp_fragment_multiple_tails
,
876 { "Message has multiple tail fragments", "fpp.fragment.multiple_tails",
877 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}},
878 { &hf_fpp_fragment_too_long_fragment
,
879 { "Message fragment too long", "fpp.fragment.too_long_fragment",
880 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}},
881 { &hf_fpp_fragment_error
,
882 { "Message defragmentation error", "fpp.fragment.error",
883 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}},
884 { &hf_fpp_fragment_count
,
885 { "Message fragment count", "fpp.fragment.count",
886 FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
}},
887 { &hf_fpp_reassembled_in
,
888 { "Reassembled in", "fpp.reassembled.in",
889 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}},
890 { &hf_fpp_reassembled_length
,
891 { "Reassembled fpp length", "fpp.reassembled.length",
892 FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
}},
895 /* Setup protocol subtree array */
896 static int *ett
[] = {
899 /* Reassembly subtrees. */
904 static ei_register_info ei
[] = {
906 { "fpp.mcrc32_bad", PI_CHECKSUM
, PI_ERROR
,
907 "Bad mCRC checksum", EXPFILL
}
910 { "fpp.crc32_bad", PI_CHECKSUM
, PI_ERROR
,
911 "Bad CRC checksum", EXPFILL
}
915 expert_module_t
* expert_fpp
;
917 proto_fpp
= proto_register_protocol (
918 "IEEE 802.3br Frame Preemption Protocol",
919 "Frame Preemption Protocol",
923 proto_register_field_array(proto_fpp
, hf
, array_length(hf
));
924 proto_register_subtree_array(ett
, array_length(ett
));
925 expert_fpp
= expert_register_protocol(proto_fpp
);
926 expert_register_field_array(expert_fpp
, ei
, array_length(ei
));
928 reassembly_table_register(&fpp_reassembly_table
, &addresses_reassembly_table_functions
);
930 fpp_handle
= register_dissector("fpp", dissect_fpp
, proto_fpp
);
934 proto_reg_handoff_fpp(void)
936 dissector_add_uint("wtap_encap", WTAP_ENCAP_ETHERNET_MPACKET
, fpp_handle
);
938 ethl2_handle
= find_dissector_add_dependency("eth_withoutfcs", proto_fpp
);
942 * Editor modelines - https://www.wireshark.org/tools/modelines.html
947 * indent-tabs-mode: nil
950 * vi: set shiftwidth=4 tabstop=8 expandtab:
951 * :indentSize=4:tabSize=8:noTabs=false: