TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags
[wireshark-sm.git] / epan / dissectors / packet-fpp.c
blobf1f686cb0ca4b4d9bacbbcdb1188e7e3738fbd4e
1 /* packet-fpp.c
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
13 #include "config.h"
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);
28 static int proto_fpp;
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;
45 static int ett_fpp;
46 static int ett_fpp_preamble;
48 static reassembly_table fpp_reassembly_table;
50 static dissector_handle_t ethl2_handle;
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;
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"
89 #define FPP_DEFAULT_PREAMBLE_LENGTH 8
90 #define FPP_CRC_LENGTH 4
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;
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;
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;
123 typedef enum {
124 CRC_CRC,
125 CRC_mCRC,
126 CRC_FALSE
127 } fpp_crc_t;
129 typedef enum {
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]" },
141 { 0x0, NULL }
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 }
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 }
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 }
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 }
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 }
193 static uint32_t
194 get_preamble_length(tvbuff_t *tvb) {
196 uint32_t offset = 0;
198 if( 0x50 == tvb_get_uint8(tvb, offset) )
200 //First octet contains preamble alignment bits. Ignore it.
201 offset = 1;
204 while( tvb_get_uint8(tvb, offset) == Octet_0x55 && ( offset + 2 < tvb_reported_length(tvb) ) )
206 offset++;
209 uint8_t smd1 = tvb_get_uint8(tvb, offset);
211 switch (smd1) {
212 case SMD_PP_Start_0:
213 case SMD_PP_Start_1:
214 case SMD_PP_Start_2:
215 case SMD_PP_Start_3:
216 case SMD_Verify:
217 case SMD_Respond:
218 case SMD_Express:
219 return offset + 1;
220 case SMD_PP_ContFrag_0:
221 case SMD_PP_ContFrag_1:
222 case SMD_PP_ContFrag_2:
223 case SMD_PP_ContFrag_3:
224 return offset + 2;
225 default:
226 return FPP_DEFAULT_PREAMBLE_LENGTH;
230 static fpp_crc_t
231 get_crc_stat(tvbuff_t *tvb, uint32_t crc, uint32_t mcrc) {
232 fpp_crc_t crc_val;
233 uint32_t received_crc = tvb_get_uint32(tvb, tvb_reported_length(tvb) - FPP_CRC_LENGTH, ENC_BIG_ENDIAN);
235 if (received_crc == crc) {
236 crc_val = CRC_CRC;
237 } else if (received_crc == mcrc) {
238 crc_val = CRC_mCRC;
239 } else {
240 crc_val = CRC_FALSE;
242 return crc_val;
245 static fpp_crc_t
246 get_express_crc_stat(tvbuff_t *tvb, uint32_t express_crc) {
247 fpp_crc_t crc_val;
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) {
251 crc_val = CRC_CRC;
252 } else {
253 crc_val = CRC_FALSE;
255 return crc_val;
258 static fpp_packet_t
259 get_packet_type(tvbuff_t *tvb) {
260 /* function analyze a packet based on preamble and ignore crc */
262 uint32_t offset = 0;
264 if( 0x50 == tvb_get_uint8(tvb, offset) )
266 //First octet contains preamble alignment bits. Ignore it.
267 offset = 1;
270 while( tvb_get_uint8(tvb, offset) == Octet_0x55 && ( offset + 2 < tvb_reported_length(tvb) ) )
272 offset++;
275 uint8_t smd1 = tvb_get_uint8(tvb, offset);
276 uint8_t smd2 = tvb_get_uint8(tvb, offset + 1);
278 switch (smd1) {
279 case SMD_PP_Start_0:
280 case SMD_PP_Start_1:
281 case SMD_PP_Start_2:
282 case SMD_PP_Start_3:
283 return FPP_Packet_Init;
284 case SMD_Verify:
285 return FPP_Packet_Verify;
286 case SMD_Respond:
287 return FPP_Packet_Response;
288 case SMD_Express:
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:
294 switch (smd2) {
295 case FragCount_0:
296 case FragCount_1:
297 case FragCount_2:
298 case FragCount_3:
299 return FPP_Packet_Cont;
300 default:
301 return FPP_Packet_Invalid;
303 default:
304 return FPP_Packet_Invalid;
307 return FPP_Packet_Invalid;
310 static void
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]");
317 break;
318 case FPP_Packet_Verify:
319 col_set_str(pinfo->cinfo, COL_INFO, "[Verify]");
320 break;
321 case FPP_Packet_Response:
322 col_set_str(pinfo->cinfo, COL_INFO, "[Respond]");
323 break;
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));
329 else
330 col_add_str(pinfo->cinfo, COL_INFO, try_val_to_str(tvb_get_uint8(tvb, preamble_length-1), corrupted_delim_desc));
331 break;
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));
335 break;
336 default:
337 break;
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;
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) {
355 case P2P_DIR_RECV:
356 return PACKET_DIRECTION_INBOUND;
357 case P2P_DIR_SENT:
358 return PACKET_DIRECTION_OUTBOUND;
359 default:
360 return PACKET_DIRECTION_UNKNOWN;
364 static void
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;
369 ctx->size = 0;
370 ctx->crc = crc;
371 ctx->crc_history = wmem_map_new(wmem_epan_scope(), g_int_hash, g_int_equal);
374 static uint8_t
375 frag_cnt_next(uint8_t cur_num) {
376 switch(cur_num) {
377 case FragCount_0:
378 return FragCount_1;
379 case FragCount_1:
380 return FragCount_2;
381 case FragCount_2:
382 return FragCount_3;
383 case FragCount_3:
384 default:
385 return FragCount_0;
389 static uint8_t
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;
399 else
400 return SMD_PP_ContFrag_0;
403 struct _fpp_pdata_t {
404 /* struct for future possible usage */
405 uint32_t offset;
408 typedef struct _fpp_pdata_t fpp_pdata_t;
410 static void
411 drop_conversation(conversation_t *conv) {
412 fpp_ctx_t *ctx;
413 ctx = (fpp_ctx_t*)conversation_get_proto_data(conv, proto_fpp);
414 if (ctx != NULL) {
415 wmem_free(wmem_file_scope(), ctx);
417 conversation_delete_proto_data(conv, proto_fpp);
420 static void
421 drop_fragments(packet_info *pinfo) {
422 tvbuff_t *tvbuf;
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;
428 else
429 interface_id = 0;
430 interface_id = interface_id << 0x2;
431 tvbuf = fragment_delete(&fpp_reassembly_table, pinfo, interface_id | packet_direction, NULL);
433 if (tvbuf != NULL) {
434 tvb_free(tvbuf);
438 static tvbuff_t*
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;
457 fpp_ctx_t *ctx;
458 unsigned interface_id;
459 packet_direction_enum packet_direction = get_packet_direction(pinfo);
460 fpp_crc_t crc_val;
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;
467 else
468 interface_id = 0;
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) );
506 else
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) );
512 prev_crc = 0;
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);
526 if (ctx) {
527 if (!PINFO_FD_VISITED(pinfo)) {
528 if ((ctx->preemption) && (ctx->frame_cnt == smd1) && (frag_cnt_next(ctx->frag_cnt) == smd2)) {
529 prev_crc = ctx->crc;
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);
538 else {
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) {
574 /* First fragment */
575 drop_fragments(pinfo);
577 frag_data = fragment_add_check(&fpp_reassembly_table,
578 tvb, preamble_length, pinfo, interface_id | packet_direction, NULL,
579 0, frag_size, true);
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,
592 NULL, tree);
594 } else {
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);
605 if (ctx) {
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;
612 ctx->crc = crc;
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);
619 if (fpp_pdata) {
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,
627 NULL, tree);
629 } else {
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
638 if (conv) {
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);
650 if (fpp_pdata) {
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,
659 NULL, tree);
660 pinfo->fragmented = save_fragmented;
661 } else {
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);
666 if (new_tvb) {
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);
673 return new_tvb;
674 } 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 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 return NULL;
681 } else {
682 /* Invalid packet */
683 if (!PINFO_FD_VISITED(pinfo) && conv) {
684 ctx = (fpp_ctx_t *)conversation_get_proto_data(conv, proto_fpp);
685 if (ctx) {
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;
692 ctx->crc = crc;
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);
704 return NULL;
707 static tvbuff_t *
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;
711 unsigned offset = 0;
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);
752 return NULL;
755 static int
756 dissect_fpp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
758 uint32_t express_crc;
759 fpp_crc_t crc_val;
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);
783 break;
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);
789 break;
790 default:
791 break;
794 if (next) {
795 call_dissector(ethl2_handle, next, pinfo, tree);
796 } else {
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);
803 void
804 proto_register_fpp(void)
806 static hf_register_info hf[] = {
807 { &hf_fpp_preamble,
808 { "Preamble", "fpp.preamble",
809 FT_BYTES, BASE_NONE,
810 NULL, 0x0,
811 NULL, HFILL }
813 { &hf_fpp_preamble_pad,
814 { "Alignment padding, not part of frame", "fpp.preamble.pad",
815 FT_UINT8, BASE_HEX,
816 NULL, 0x0F,
817 NULL, HFILL }
819 { &hf_fpp_preamble_smd,
820 { "SMD", "fpp.preamble.smd",
821 FT_UINT8, BASE_HEX,
822 NULL, 0x0,
823 NULL, HFILL }
825 { &hf_fpp_preamble_frag_count,
826 { "Fragment count", "fpp.preamble.frag_count",
827 FT_UINT8, BASE_HEX,
828 NULL, 0x0,
829 NULL, HFILL }
831 { &hf_fpp_mdata,
832 { "mData", "fpp.mdata",
833 FT_BYTES, BASE_NONE,
834 NULL, 0x0,
835 NULL, HFILL }
837 { &hf_fpp_crc32,
838 { "CRC", "fpp.crc32",
839 FT_UINT32, BASE_HEX,
840 NULL, 0x0,
841 NULL, HFILL }
843 { &hf_fpp_crc32_status,
844 { "Checksum Status", "fpp.checksum.status",
845 FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0,
846 NULL, HFILL
849 { &hf_fpp_mcrc32,
850 { "mCRC", "fpp.mcrc32",
851 FT_UINT32, BASE_HEX,
852 NULL, 0x0,
853 NULL, HFILL }
855 { &hf_fpp_mcrc32_status,
856 { "Checksum Status", "fpp.checksum.status",
857 FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0,
858 NULL, HFILL
862 /* Reassembly fields. */
863 { &hf_fpp_fragments,
864 { "Message fragments", "fpp.fragments",
865 FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL }},
866 { &hf_fpp_fragment,
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[] = {
897 &ett_fpp,
898 &ett_fpp_preamble,
899 /* Reassembly subtrees. */
900 &ett_fpp_fragment,
901 &ett_fpp_fragments
904 static ei_register_info ei[] = {
905 { &ei_fpp_mcrc32,
906 { "fpp.mcrc32_bad", PI_CHECKSUM, PI_ERROR,
907 "Bad mCRC checksum", EXPFILL }
909 { &ei_fpp_crc32,
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",
920 "fpp"
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);
933 void
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
944 * Local variables:
945 * c-basic-offset: 4
946 * tab-width: 8
947 * indent-tabs-mode: nil
948 * End:
950 * vi: set shiftwidth=4 tabstop=8 expandtab:
951 * :indentSize=4:tabSize=8:noTabs=false: