Coverage Report

Created: 2025-12-27 06:52

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