Coverage Report

Created: 2026-06-30 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
 */