Coverage Report

Created: 2025-02-15 06:25

/src/wireshark/epan/dissectors/packet-macsec.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-macsec.c
2
 * Routines for IEEE 802.1AE MACsec dissection
3
 * Copyright 2013, Allan W. Nielsen <anielsen@vitesse.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
#include "config.h"
13
14
#include <epan/packet.h>
15
#include <epan/etypes.h>
16
#include <epan/tfs.h>
17
#include <wsutil/array.h>
18
#include <wsutil/wsgcrypt.h>
19
20
void proto_register_macsec(void);
21
void proto_reg_handoff_macsec(void);
22
23
static dissector_handle_t macsec_handle;
24
static dissector_handle_t ethertype_handle;
25
26
/* TCI/AN field masks */
27
14
#define TCI_MASK     0xFC
28
27
#define TCI_V_MASK   0x80
29
14
#define TCI_ES_MASK  0x40
30
26
#define TCI_SC_MASK  0x20
31
14
#define TCI_SCB_MASK 0x10
32
40
#define TCI_E_MASK   0x08
33
34
#define TCI_C_MASK   0x04
34
14
#define AN_MASK      0x03
35
36
26
#define AES_KEY_LEN           (16)
37
12
#define ICV_LEN               (16)
38
#define IV_LEN                (12)
39
40
58
#define HWADDR_LEN            (6)
41
48
#define ETHERTYPE_LEN         (2)
42
13
#define ETHHDR_LEN            ((HWADDR_LEN * 2) + ETHERTYPE_LEN)
43
44
15
#define SECTAG_LEN_WITH_SC    (14)
45
9
#define SECTAG_LEN_WITHOUT_SC (6)
46
47
0
#define AAD_ENCRYPTED_LEN     (28)
48
49
#define MAX_PAYLOAD_LEN       (1500)
50
51
52
static int proto_macsec;
53
static int hf_macsec_TCI;
54
static int hf_macsec_TCI_V;
55
static int hf_macsec_TCI_ES;
56
static int hf_macsec_TCI_SC;
57
static int hf_macsec_TCI_SCB;
58
static int hf_macsec_TCI_E;
59
static int hf_macsec_TCI_C;
60
static int hf_macsec_AN;
61
static int hf_macsec_SL;
62
static int hf_macsec_PN;
63
static int hf_macsec_SCI_system_identifier;
64
static int hf_macsec_SCI_port_identifier;
65
static int hf_macsec_etype;
66
static int hf_macsec_eth_padding;
67
static int hf_macsec_ICV;
68
static int hf_macsec_ICV_check_success;
69
static int hf_macsec_decrypted_data;
70
71
/* Initialize the subtree pointers */
72
static int ett_macsec;
73
static int ett_macsec_tci;
74
75
/* Decrypting payload buffer */
76
static uint8_t macsec_payload[MAX_PAYLOAD_LEN];
77
78
/* AAD buffer */
79
static uint8_t aad[MAX_PAYLOAD_LEN];
80
81
static const char *psk = NULL;
82
static unsigned char *psk_bin = NULL;
83
84
/* convert a 0-terminated preference key_string that contains a hex number
85
 *  into its binary representation
86
 * e.g. key_string "abcd" will be converted into two bytes 0xab, 0xcd
87
 * return the number of binary bytes or -1 for error */
88
static int
89
pref_key_string_to_bin(const char *key_string, unsigned char **key_bin)
90
13
{
91
13
    int key_string_len;
92
13
    int i, j;
93
13
    char input[3];
94
95
13
    ws_return_val_if(key_bin == NULL, -1);
96
97
13
    if (NULL == key_string) {
98
0
        *key_bin = NULL;
99
0
        return -1;
100
0
    }
101
102
13
    key_string_len = (int)strlen(key_string);
103
13
    if (key_string_len != 2 * AES_KEY_LEN) {
104
13
        *key_bin = NULL;
105
13
        return (key_string_len / 2);
106
13
    }
107
108
0
    *key_bin = (unsigned char *)g_malloc(key_string_len / 2);
109
110
0
    input[2] = '\0';
111
0
    for (i = 0, j = 0; i < (key_string_len - 1); i += 2, j++) {
112
0
        input[0] = key_string[0 + i];
113
0
        input[1] = key_string[1 + i];
114
115
        /* attention, brackets are required */
116
0
        (*key_bin)[j] = (unsigned char)strtoul((const char *)&input, NULL, 16);
117
0
    }
118
119
0
    return (key_string_len / 2);
120
13
}
121
122
/* Code to actually dissect the packets */
123
13
static int dissect_macsec(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
124
13
    unsigned    sectag_length, data_length, short_length, icv_length;
125
13
    unsigned    fcs_length = 0;
126
13
    unsigned    data_offset, icv_offset;
127
13
    uint8_t     tci_an_field;
128
129
13
    int         icv_check_success = PROTO_CHECKSUM_E_BAD;
130
13
    bool        key_provided = false;
131
13
    bool        encrypted = false;
132
13
    unsigned    payload_len;
133
13
    unsigned    offset;
134
135
13
    gcry_cipher_hd_t handle = 0;
136
137
13
    proto_item *macsec_item;
138
13
    proto_tree *macsec_tree = NULL;
139
140
13
    tvbuff_t *next_tvb;
141
142
    /* Construct the 14-byte ethernet header (6-byte dst MAC, 6-byte src MAC, 2-byte ethernet type)(part of aad) */
143
13
    uint8_t header[ETHHDR_LEN] = {0};
144
13
    if (pinfo->dl_dst.data != NULL)
145
13
    {
146
13
        memcpy(header, pinfo->dl_dst.data, HWADDR_LEN);
147
13
    }
148
13
    if (pinfo->dl_src.data != NULL)
149
13
    {
150
13
        memcpy((header + HWADDR_LEN), pinfo->dl_src.data, HWADDR_LEN);
151
13
    }
152
153
13
    uint8_t e_type[ETHERTYPE_LEN] = {(uint8_t)(ETHERTYPE_MACSEC >> 8), (uint8_t)(ETHERTYPE_MACSEC & 0xff)};
154
13
    memcpy(header + (ETHHDR_LEN - ETHERTYPE_LEN), &e_type, ETHERTYPE_LEN);
155
156
    /* Parse the encryption key, and set the flag to indicate if the key is provided*/
157
13
    if (pref_key_string_to_bin(psk, &psk_bin) == AES_KEY_LEN) {
158
0
        key_provided = true;
159
0
    }
160
161
13
    tci_an_field = tvb_get_uint8(tvb, 0);
162
163
    /* if the frame is an encrypted MACsec frame, remember that */
164
13
    if (((tci_an_field & TCI_E_MASK) == TCI_E_MASK) || ((tci_an_field & TCI_C_MASK) == TCI_C_MASK)) {
165
4
        encrypted = true;
166
4
    }
167
168
13
    if ((tci_an_field & TCI_V_MASK) != 0) {  /* version must be zero */
169
1
        return 0;
170
1
    }
171
172
12
    icv_length = ICV_LEN;  /* Fixed size for version 0 */
173
174
12
    if (tci_an_field & TCI_SC_MASK) {
175
3
        sectag_length = SECTAG_LEN_WITH_SC;  /* optional SCI present */
176
9
    } else {
177
9
        sectag_length = SECTAG_LEN_WITHOUT_SC;
178
9
    }
179
180
    /* Check for length too short */
181
12
    if (tvb_captured_length(tvb) <= (sectag_length + icv_length)) {
182
0
        return 0;
183
0
    }
184
185
    /* short length field: 1..47 bytes, 0 means 48 bytes or more */
186
12
    short_length = (uint32_t)tvb_get_uint8(tvb, 1);
187
188
    /* Get the payload section */
189
12
    if (short_length != 0) {
190
3
        data_length = short_length;
191
3
        fcs_length = tvb_reported_length(tvb) - sectag_length - icv_length - short_length;
192
193
        /*
194
         * We know the length, so set it here for the previous ethertype
195
         * dissector. This will allow us to calculate the FCS correctly.
196
         */
197
3
        set_actual_length(tvb, short_length + sectag_length + icv_length);
198
9
    } else {
199
        /*
200
         * This assumes that no FCS is present after the ICV, which might not be true!
201
         * Workaround: turn Ethernet "Assume packets have FCS" = Always, when FCS present.
202
         * If there's another (non FCS) trailer afterwards, set Ethernet
203
         * "Fixed ethernet trailer length".
204
         *
205
         * TODO: Find better heuristic to detect presence of FCS / trailers.
206
         */
207
9
        data_length = tvb_reported_length(tvb) - sectag_length - icv_length;
208
9
    }
209
12
    data_offset = sectag_length;
210
12
    icv_offset  = data_length + data_offset;
211
212
12
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "MACSEC");
213
12
    col_set_str(pinfo->cinfo, COL_INFO, "MACsec frame");
214
215
12
    if (tree) {
216
12
        if (encrypted) {
217
3
            macsec_item = proto_tree_add_item(tree, proto_macsec, tvb, 0, sectag_length, ENC_NA);
218
9
        } else {
219
            /* Add the EtherType too since this is authentication only. */
220
9
            macsec_item = proto_tree_add_item(tree, proto_macsec, tvb, 0, sectag_length + ETHERTYPE_LEN, ENC_NA);
221
9
        }
222
12
        macsec_tree = proto_item_add_subtree(macsec_item, ett_macsec);
223
224
12
        static int * const flags[] = {
225
12
            &hf_macsec_TCI_V,
226
12
            &hf_macsec_TCI_ES,
227
12
            &hf_macsec_TCI_SC,
228
12
            &hf_macsec_TCI_SCB,
229
12
            &hf_macsec_TCI_E,
230
12
            &hf_macsec_TCI_C,
231
12
            NULL
232
12
        };
233
234
12
        proto_tree_add_bitmask_with_flags(macsec_tree, tvb, 0,
235
12
                hf_macsec_TCI, ett_macsec_tci, flags, ENC_NA, BMT_NO_TFS);
236
237
12
        offset = 0;
238
12
        proto_tree_add_item(macsec_tree, hf_macsec_AN, tvb, offset, 1, ENC_NA);
239
12
        offset += 1;
240
241
12
        proto_tree_add_item(macsec_tree, hf_macsec_SL, tvb, offset, 1, ENC_NA);
242
12
        offset += 1;
243
244
12
        proto_tree_add_item(macsec_tree, hf_macsec_PN, tvb, offset, 4, ENC_BIG_ENDIAN);
245
12
        offset += 4;
246
247
12
        if (sectag_length == SECTAG_LEN_WITH_SC) {
248
3
            proto_tree_add_item(macsec_tree, hf_macsec_SCI_system_identifier, tvb, offset, HWADDR_LEN, ENC_NA);
249
3
            offset += HWADDR_LEN;
250
251
3
            proto_tree_add_item(macsec_tree, hf_macsec_SCI_port_identifier, tvb, offset, 2, ENC_BIG_ENDIAN);
252
3
        }
253
12
    }
254
255
12
    next_tvb = tvb_new_subset_length(tvb, data_offset, data_length);
256
257
    /* Try to decrypt/authenticate the data if a key is provided */
258
12
    if (key_provided) {
259
        /* Build the IV */
260
0
        uint8_t iv[IV_LEN] = {0};
261
0
        tvb_memcpy(tvb, iv,     6,  HWADDR_LEN); // SI System identifier (source MAC)
262
0
        tvb_memcpy(tvb, iv + 6, 12, 2);          // PI Port identifier
263
0
        tvb_memcpy(tvb, iv + 8, 2,  4);          // PN Packet number
264
265
0
        if (gcry_cipher_open(&handle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_GCM, 0))
266
0
        {
267
0
            ws_warning("gcry_cipher_open fail");
268
0
            goto out;
269
0
        }
270
271
0
        if (gcry_cipher_setkey(handle, psk_bin, AES_KEY_LEN))
272
0
        {
273
0
            ws_warning("gcry_cipher_setkey fail");
274
0
            goto out;
275
0
        }
276
277
0
        if (gcry_cipher_setiv(handle, iv, sizeof(iv)))
278
0
        {
279
0
            ws_warning("gcry_cipher_setiv fail");
280
0
            goto out;
281
0
        }
282
283
0
        if (encrypted) {
284
0
            payload_len = tvb_captured_length(next_tvb);
285
286
            /* For authenticated and encrypted data, the AAD is always 28 bytes and consists of the
287
            header data and security tag. */
288
0
            const uint8_t *buf = tvb_get_ptr(tvb, 0, SECTAG_LEN_WITH_SC);
289
290
0
            memcpy(aad, header, ETHHDR_LEN);
291
0
            memcpy(aad + ETHHDR_LEN, buf, SECTAG_LEN_WITH_SC);
292
293
            /* Authenticate with the AAD. */
294
0
            if (gcry_cipher_authenticate(handle, aad, AAD_ENCRYPTED_LEN))
295
0
            {
296
0
                ws_warning("gcry_cipher_authenticate fail");
297
0
                goto out;
298
0
            }
299
300
0
            tvb_memcpy(next_tvb, macsec_payload, 0, payload_len);
301
302
            /* Attempt to decrypt into the local buffer. */
303
0
            if (gcry_cipher_decrypt(handle, macsec_payload, payload_len, NULL, 0))
304
0
            {
305
0
                ws_warning("gcry_cipher_decrypt fail");
306
0
                goto out;
307
0
            }
308
309
0
        } else {
310
            /* the frame length for the AAD is the complete frame including ethernet header but without the ICV */
311
0
            unsigned frame_len = (ETHHDR_LEN + tvb_captured_length(tvb)) - ICV_LEN;
312
313
            // For authenticated-only data, the aad is the frame minus the ICV
314
            // We have to build the AAD since the incoming TVB payload does not have the Ethernet header.
315
0
            payload_len = frame_len - ETHHDR_LEN;
316
317
            // Copy the header we built previously, then the frame data up to the ICV.
318
0
            memcpy(aad, header, ETHHDR_LEN);
319
0
            memcpy((aad + ETHHDR_LEN), tvb_get_ptr(tvb, 0, payload_len), payload_len);
320
321
            /* Authenticate with the AAD. */
322
0
            if (gcry_cipher_authenticate(handle, aad, frame_len))
323
0
            {
324
0
                ws_warning("gcry_cipher_authenticate fail");
325
0
                goto out;
326
0
            }
327
0
        }
328
329
        /* Fetch the ICV and use it to verify the decrypted data. */
330
0
        uint8_t icv[ICV_LEN] = {0};
331
0
        tvb_memcpy(tvb, icv, icv_offset, icv_length);
332
0
        if (gcry_cipher_checktag(handle, icv, sizeof(icv)))
333
0
        {
334
0
            ws_info("gcry_cipher_checktag fail");
335
0
            goto out;
336
0
        }
337
338
        /* Everything checks out! */
339
0
        icv_check_success = PROTO_CHECKSUM_E_GOOD;
340
0
    }
341
342
12
out:
343
12
    if (0 != handle) {
344
0
        gcry_cipher_close(handle);
345
0
    }
346
    // Show the original data.
347
12
    call_data_dissector(next_tvb, pinfo, tree);
348
349
12
    ethertype_data_t ethertype_data;
350
351
    /* default the next tv_buff to remove ICV */
352
    /* lets hand over a buffer without ICV to limit effect of wrong padding calculation */
353
12
    next_tvb = tvb_new_subset_length(tvb, data_offset + 2, data_length - 2);
354
12
    ethertype_data.etype = tvb_get_ntohs(tvb, data_offset);
355
356
    // If the data are ok, attempt to continue dissection.
357
12
    if (PROTO_CHECKSUM_E_GOOD == icv_check_success)
358
0
    {
359
0
        if (encrypted) {
360
0
            tvbuff_t *plain_tvb;
361
362
0
            plain_tvb = tvb_new_child_real_data(next_tvb, (uint8_t *)wmem_memdup(pinfo->pool, macsec_payload, payload_len),
363
0
                                                payload_len, payload_len);
364
0
            ethertype_data.etype = tvb_get_ntohs(plain_tvb, 0);
365
366
            /* lets hand over a buffer without ICV to limit effect of wrong padding calculation */
367
0
            next_tvb = tvb_new_subset_length(plain_tvb, 2, payload_len - 2);
368
369
            /* show the decrypted data and original ethertype */
370
0
            proto_tree_add_item(tree, hf_macsec_decrypted_data, plain_tvb, 0, payload_len, ENC_NA);
371
372
            /* add the decrypted data as a data source for the next dissectors */
373
0
            add_new_data_source(pinfo, plain_tvb, "Decrypted Data");
374
375
            /* The ethertype is the one from the start of the decrypted data. */
376
0
            proto_tree_add_item(tree, hf_macsec_etype, plain_tvb, 0, 2, ENC_BIG_ENDIAN);
377
378
0
        } else {
379
            /* lets hand over a buffer without ICV to limit effect of wrong padding calculation */
380
0
            next_tvb = tvb_new_subset_length(tvb, data_offset + 2, data_length - 2);
381
382
            /* The ethertype is the original from the unencrypted data. */
383
0
            proto_tree_add_item(tree, hf_macsec_etype, tvb, data_offset, 2, ENC_BIG_ENDIAN);
384
0
        }
385
0
    }
386
387
    /* add the ICV to the sectag subtree */
388
12
    proto_tree_add_item(macsec_tree, hf_macsec_ICV, tvb, icv_offset, icv_length, ENC_NA);
389
12
    proto_tree_set_appendix(macsec_tree, tvb, icv_offset, icv_length);
390
391
    /* If the frame decoded, or was not encrypted, continue dissection */
392
12
    if ((PROTO_CHECKSUM_E_GOOD == icv_check_success) || (false == encrypted)) {
393
        /* help eth padding calculation by subtracting length of the sectag, ethertype, icv, and fcs */
394
9
        int pkt_len_saved = pinfo->fd->pkt_len;
395
396
9
        pinfo->fd->pkt_len -= (sectag_length + 2 + icv_length + fcs_length);
397
398
        /* continue dissection */
399
9
        ethertype_data.payload_offset = 0;
400
9
        ethertype_data.fh_tree = macsec_tree;
401
        /* XXX: This could be another trailer, a FCS, or the Ethernet dissector
402
            * incorrectly detecting padding if we don't have short_length. */
403
9
        ethertype_data.trailer_id = hf_macsec_eth_padding;
404
9
        ethertype_data.fcs_len = 0;
405
406
9
        call_dissector_with_data(ethertype_handle, next_tvb, pinfo, tree, &ethertype_data);
407
408
        /* restore original value */
409
9
        pinfo->fd->pkt_len = pkt_len_saved;
410
9
    }
411
412
    /* Set icv_check_success to the correct status */
413
12
    if (!key_provided) {
414
12
        icv_check_success = PROTO_CHECKSUM_E_UNVERIFIED;
415
12
    }
416
417
    /* If the frame was not verified correctly, append this string to the info line
418
     * after dissection completes.
419
     */
420
12
    if (PROTO_CHECKSUM_E_BAD == icv_check_success) {
421
0
        col_append_str(pinfo->cinfo, COL_INFO, " [Authentication fail]");
422
0
    }
423
424
    /* add a flag indicating the frame is or is not verified. */
425
12
    macsec_item = proto_tree_add_uint(macsec_tree, hf_macsec_ICV_check_success, tvb, 0, 0, icv_check_success);
426
12
    proto_item_set_generated(macsec_item);
427
428
    /* We called set_actual length if fcs_length !=0, so length is adjusted. */
429
12
    return tvb_captured_length(tvb);
430
12
}
431
432
void
433
proto_register_macsec(void)
434
14
{
435
14
    module_t *module;
436
14
    static hf_register_info hf[] = {
437
14
        { &hf_macsec_TCI,
438
14
            { "TCI", "macsec.TCI", FT_UINT8, BASE_HEX,
439
14
              NULL, TCI_MASK, "TAG Control Information", HFILL }
440
14
        },
441
14
        { &hf_macsec_TCI_V,
442
14
            { "VER", "macsec.TCI.V", FT_UINT8, BASE_HEX,
443
14
              NULL, TCI_V_MASK, "Version", HFILL }
444
14
        },
445
14
        { &hf_macsec_TCI_ES,
446
14
            { "ES", "macsec.TCI.ES", FT_BOOLEAN, 8,
447
14
              TFS(&tfs_set_notset), TCI_ES_MASK, "End Station", HFILL }
448
14
        },
449
14
        { &hf_macsec_TCI_SC,
450
14
            { "SC", "macsec.TCI.SC", FT_BOOLEAN, 8,
451
14
              TFS(&tfs_set_notset), TCI_SC_MASK, "Secure Channel", HFILL }
452
14
        },
453
14
        { &hf_macsec_TCI_SCB,
454
14
            { "SCB", "macsec.TCI.SCB", FT_BOOLEAN, 8,
455
14
              TFS(&tfs_set_notset), TCI_SCB_MASK, "Single Copy Broadcast", HFILL }
456
14
        },
457
14
        { &hf_macsec_TCI_E,
458
14
            { "E", "macsec.TCI.E", FT_BOOLEAN, 8,
459
14
              TFS(&tfs_set_notset), TCI_E_MASK, "Encryption", HFILL }
460
14
        },
461
14
        { &hf_macsec_TCI_C,
462
14
            { "C", "macsec.TCI.C", FT_BOOLEAN, 8,
463
14
              TFS(&tfs_set_notset), TCI_C_MASK, "Changed Text", HFILL }
464
14
        },
465
14
        { &hf_macsec_AN,
466
14
            { "AN", "macsec.AN", FT_UINT8, BASE_HEX,
467
14
              NULL, AN_MASK, "Association Number", HFILL }
468
14
        },
469
14
        { &hf_macsec_SL,
470
14
            { "Short length", "macsec.SL", FT_UINT8, BASE_DEC,
471
14
              NULL, 0, NULL, HFILL }
472
14
        },
473
14
        { &hf_macsec_PN,
474
14
            { "Packet number", "macsec.PN", FT_UINT32, BASE_DEC,
475
14
              NULL, 0, NULL, HFILL }
476
14
        },
477
14
        { &hf_macsec_SCI_system_identifier,
478
14
            { "System Identifier", "macsec.SCI.system_identifier", FT_ETHER, BASE_NONE,
479
14
                NULL, 0, NULL, HFILL }
480
14
        },
481
14
        { &hf_macsec_SCI_port_identifier,
482
14
            { "Port Identifier", "macsec.SCI.port_identifier", FT_UINT16, BASE_DEC,
483
14
              NULL, 0, NULL, HFILL }
484
14
        },
485
14
        { &hf_macsec_etype,
486
14
            { "Ethertype", "macsec.etype", FT_UINT16, BASE_HEX,
487
14
              NULL, 0, NULL, HFILL }
488
14
        },
489
14
        { &hf_macsec_eth_padding,
490
14
            { "Padding", "macsec.eth_padding", FT_BYTES, BASE_NONE,
491
14
              NULL, 0, NULL, HFILL }
492
14
        },
493
14
        { &hf_macsec_ICV,
494
14
            { "ICV", "macsec.ICV", FT_BYTES, BASE_NONE,
495
14
              NULL, 0, NULL, HFILL }
496
14
        },
497
14
        { &hf_macsec_ICV_check_success,
498
14
            { "Frame authentication status", "macsec.auth_status", FT_UINT8, BASE_DEC,
499
14
              NULL, 0, NULL, HFILL }
500
14
        },
501
14
        { &hf_macsec_decrypted_data,
502
14
            { "Decrypted Data", "macsec.decrypted_data", FT_BYTES, BASE_NONE,
503
14
            NULL, 0, NULL, HFILL }
504
14
        },
505
14
    };
506
507
    /* Setup protocol subtree array */
508
14
    static int *ett[] = {
509
14
        &ett_macsec,
510
14
        &ett_macsec_tci
511
14
    };
512
513
    /* Register the protocol name and description */
514
14
    proto_macsec = proto_register_protocol("802.1AE Security tag", "MACsec", "macsec");
515
516
    /* Required function calls to register the header fields and subtrees used */
517
14
    proto_register_field_array(proto_macsec, hf, array_length(hf));
518
14
    proto_register_subtree_array(ett, array_length(ett));
519
520
    /* Register the dissector */
521
14
    macsec_handle = register_dissector("macsec", dissect_macsec, proto_macsec);
522
523
    /* Register the text box to enter the pre-shared key */
524
14
    module = prefs_register_protocol(proto_macsec, NULL);
525
14
    prefs_register_string_preference(module, "psk", "MACsec Pre-Shared Key",
526
14
                                     "Pre-Shared AES-GCM-128 Key as a HEX string (16 bytes).",
527
14
                                     &psk);
528
14
}
529
530
void
531
proto_reg_handoff_macsec(void)
532
14
{
533
14
    dissector_add_uint("ethertype", ETHERTYPE_MACSEC, macsec_handle);
534
535
14
    ethertype_handle = find_dissector("ethertype");
536
14
}
537
538
/*
539
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
540
 *
541
 * Local variables:
542
 * c-basic-offset: 4
543
 * tab-width: 8
544
 * indent-tabs-mode: nil
545
 * End:
546
 *
547
 * vi: set shiftwidth=4 tabstop=8 expandtab:
548
 * :indentSize=4:tabSize=8:noTabs=true:
549
 */
550